WIP: Added super basic UDP interface for testing

Basic UDP interface enabled testing with RNS reference implementation.
Added to basic Transport implementation.
This commit is contained in:
attermann 2023-11-26 18:10:46 -07:00
parent 8d943318a6
commit ea7b4603ed
31 changed files with 1276 additions and 646 deletions

View File

@ -29,37 +29,37 @@ namespace RNS {
public:
Bytes() {
//extreme("Bytes object created from default, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((unsigned long)_data.get()));
//mem("Bytes object created from default, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((unsigned long)_data.get()));
}
Bytes(NoneConstructor none) {
//extreme("Bytes object created from NONE, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((unsigned long)_data.get()));
Bytes(const NoneConstructor none) {
//mem("Bytes object created from NONE, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((unsigned long)_data.get()));
}
Bytes(const Bytes& bytes) {
//extreme("Bytes is using shared data");
//mem("Bytes is using shared data");
assign(bytes);
//extreme("Bytes object copy created from bytes \"" + toString() + "\", this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((unsigned long)_data.get()));
//mem("Bytes object copy created from bytes \"" + toString() + "\", this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((unsigned long)_data.get()));
}
Bytes(const uint8_t* chunk, size_t size) {
assign(chunk, size);
//extreme(std::string("Bytes object created from chunk \"") + toString() + "\", this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((unsigned long)_data.get()));
//mem(std::string("Bytes object created from chunk \"") + toString() + "\", this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((unsigned long)_data.get()));
}
Bytes(const char* string) {
assign(string);
//extreme(std::string("Bytes object created from string \"") + toString() + "\", this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((unsigned long)_data.get()));
//mem(std::string("Bytes object created from string \"") + toString() + "\", this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((unsigned long)_data.get()));
}
Bytes(const std::string& string) {
assign(string);
//extreme(std::string("Bytes object created from std::string \"") + toString() + "\", this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((unsigned long)_data.get()));
//mem(std::string("Bytes object created from std::string \"") + toString() + "\", this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((unsigned long)_data.get()));
}
virtual ~Bytes() {
//extreme(std::string("Bytes object destroyed \"") + toString() + "\", this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((unsigned long)_data.get()));
//mem(std::string("Bytes object destroyed \"") + toString() + "\", this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((unsigned long)_data.get()));
}
inline Bytes& operator = (const Bytes& bytes) {
inline const Bytes& operator = (const Bytes& bytes) {
assign(bytes);
return *this;
}
inline Bytes& operator += (const Bytes& bytes) {
inline const Bytes& operator += (const Bytes& bytes) {
append(bytes);
return *this;
}
@ -87,12 +87,12 @@ namespace RNS {
private:
inline SharedData shareData() const {
//extreme("Bytes is sharing its own data");
//mem("Bytes is sharing its own data");
_owner = false;
return _data;
}
inline void newData(size_t size = 0) {
//extreme("Bytes is creating its own data");
//mem("Bytes is creating its own data");
if (size > 0) {
_data = SharedData(new Data(size));
}

View File

@ -26,11 +26,11 @@ Fernet::Fernet(const Bytes& key) {
//self._encryption_key = key[16:]
_encryption_key = key.mid(16);
extreme("Fernet object created");
mem("Fernet object created");
}
Fernet::~Fernet() {
extreme("Fernet object destroyed");
mem("Fernet object destroyed");
}
bool Fernet::verify_hmac(const Bytes& token) {

View File

@ -14,6 +14,7 @@ using namespace RNS::Type::Destination;
Destination::Destination(const Identity& identity, const directions direction, const types type, const char* app_name, const char* aspects) : _object(new Object(identity)) {
assert(_object);
mem("Destination object creating..., this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
// Check input values and build name string
if (strchr(app_name, '.') != nullptr) {
@ -27,8 +28,8 @@ Destination::Destination(const Identity& identity, const directions direction, c
if (!identity && direction == IN && _object->_type != PLAIN) {
debug("Destination::Destination: identity not provided, creating new one");
_object->_identity = Identity();
// CBA TODO should following include a "." delimiter?
fullaspects += _object->_identity.hexhash();
// CBA TODO determine why identity.hexhash is added both here and by expand_name called below
fullaspects += "." + _object->_identity.hexhash();
}
debug("Destination::Destination: full aspects: " + fullaspects);
@ -46,34 +47,53 @@ Destination::Destination(const Identity& identity, const directions direction, c
debug("Destination::Destination: hash: " + _object->_hash.toHex());
// CBA TEST CRASH
debug("Destination::Destination: creating name hash...");
_object->_name_hash = Identity::truncated_hash(expand_name({Type::NONE}, app_name, fullaspects.c_str()));
//p self.name_hash = RNS.Identity.full_hash(self.expand_name(None, app_name, *aspects).encode("utf-8"))[:(RNS.Identity.NAME_HASH_LENGTH//8)]
_object->_name_hash = name_hash(app_name, aspects);
debug("Destination::Destination: name hash: " + _object->_name_hash.toHex());
debug("Destination::Destination: calling register_destination");
Transport::register_destination(*this);
extreme("Destination object created");
mem("Destination object created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
}
/*virtual*/ Destination::~Destination() {
mem("Destination object destroyed, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
if (_object && _object.use_count() == 1) {
extreme("Destination object has last data reference");
// CBA Can't call deregister_destination here because it's possible (likely even) that Destination
// is being destructed from that same collection which will result in a llop and memory errors.
//debug("Destination::~Destination: calling deregister_destination");
//Transport::deregister_destination(*this);
}
}
/*
:returns: A destination name in adressable hash form, for an app_name and a number of aspects.
*/
/*static*/ Bytes Destination::hash(const Identity& identity, const char* app_name, const char* aspects) {
//name_hash = Identity::full_hash(Destination.expand_name(None, app_name, *aspects).encode("utf-8"))[:(RNS.Identity.NAME_HASH_LENGTH//8)]
//addr_hash_material = name_hash
Bytes addr_hash_material = Identity::truncated_hash(expand_name({Type::NONE}, app_name, aspects));
//if identity != None:
// if isinstance(identity, RNS.Identity):
// addr_hash_material += identity.hash
// elif isinstance(identity, bytes) and len(identity) == RNS.Reticulum.TRUNCATED_HASHLENGTH//8:
// addr_hash_material += identity
// else:
// raise TypeError("Invalid material supplied for destination hash calculation")
//p name_hash = Identity::full_hash(Destination.expand_name(None, app_name, *aspects).encode("utf-8"))[:(RNS.Identity.NAME_HASH_LENGTH//8)]
//p addr_hash_material = name_hash
Bytes addr_hash_material = name_hash(app_name, aspects);
if (identity) {
addr_hash_material << identity.hash();
}
//p return RNS.Identity.full_hash(addr_hash_material)[:RNS.Reticulum.TRUNCATED_HASHLENGTH//8]
// CBA TODO valid alternative?
//return Identity::full_hash(addr_hash_material).left(Type::Reticulum::TRUNCATED_HASHLENGTH/8);
return Identity::truncated_hash(addr_hash_material);
}
/*
:returns: A name in hash form, for an app_name and a number of aspects.
*/
/*static*/ Bytes Destination::name_hash(const char* app_name, const char* aspects) {
//p name_hash = Identity::full_hash(Destination.expand_name(None, app_name, *aspects).encode("utf-8"))[:(RNS.Identity.NAME_HASH_LENGTH//8)]
return Identity::full_hash(expand_name({Type::NONE}, app_name, aspects)).left(Type::Identity::NAME_HASH_LENGTH/8);
}
/*
:returns: A tuple containing the app name and a list of aspects, for a full-name string.
*/
@ -194,8 +214,9 @@ Packet Destination::announce(const Bytes& app_data, bool path_response, const In
}
else {
Bytes destination_hash = _object->_hash;
//random_hash = Identity::get_random_hash()[0:5] << int(time.time()).to_bytes(5, "big")
Bytes random_hash;
//p random_hash = Identity::get_random_hash()[0:5] << int(time.time()).to_bytes(5, "big")
// CBA TODO add in time to random hash
Bytes random_hash = Cryptography::random(Type::Identity::RANDOM_HASH_LENGTH/8);
Bytes new_app_data(app_data);
if (new_app_data.empty() && !_object->_default_app_data.empty()) {

View File

@ -56,19 +56,23 @@ namespace RNS {
public:
Destination(Type::NoneConstructor none) {
extreme("Destination NONE object created");
mem("Destination NONE object created, this: " + std::to_string((uintptr_t)this));
}
Destination(const Destination& destination) : _object(destination._object) {
extreme("Destination object copy created");
}
Destination(const Identity& identity, const Type::Destination::directions direction, const Type::Destination::types type, const char* app_name, const char *aspects);
virtual ~Destination() {
extreme("Destination object destroyed");
mem("Destination object copy created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
}
Destination(
const Identity& identity,
const Type::Destination::directions direction,
const Type::Destination::types type,
const char* app_name,
const char* aspects
);
virtual ~Destination();
inline Destination& operator = (const Destination& destination) {
_object = destination._object;
extreme("Destination object copy created by assignment, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
mem("Destination object copy created by assignment, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
return *this;
}
inline operator bool() const {
@ -81,6 +85,7 @@ namespace RNS {
public:
static std::string expand_name(const Identity& identity, const char* app_name, const char* aspects);
static Bytes hash(const Identity& identity, const char* app_name, const char* aspects);
static Bytes name_hash(const char* app_name, const char* aspects);
static Bytes app_and_aspects_from_name(const char* full_name);
static Bytes hash_from_name_and_identity(const char* full_name, const Identity& identity);
@ -168,8 +173,8 @@ namespace RNS {
private:
class Object {
public:
Object(const Identity& identity) : _identity(identity) {}
virtual ~Object() {}
Object(const Identity& identity) : _identity(identity) { mem("Destination::Data object created, this: " + std::to_string((uintptr_t)this)); }
virtual ~Object() { mem("Destination::Data object destroyed, this: " + std::to_string((uintptr_t)this)); }
private:
bool _accept_link_requests = true;
Callbacks _callbacks;

View File

@ -5,6 +5,7 @@
#include "Packet.h"
#include "Log.h"
#include "Utilities/OS.h"
#include "Cryptography/Ed25519.h"
#include "Cryptography/X25519.h"
#include "Cryptography/HKDF.h"
#include "Cryptography/Fernet.h"
@ -14,15 +15,17 @@
using namespace RNS;
using namespace RNS::Type::Identity;
using namespace RNS::Cryptography;
using namespace RNS::Utilities;
/*static*/ std::map<Bytes, Identity::IdentityEntry> Identity::_known_destinations;
/*static*/ bool Identity::_saving_known_destinations = false;
Identity::Identity(bool create_keys) : _object(new Object()) {
Identity::Identity(bool create_keys /*= true*/) : _object(new Object()) {
if (create_keys) {
createKeys();
}
extreme("Identity object created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
mem("Identity object created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
}
void Identity::createKeys() {
@ -60,7 +63,6 @@ Load a private key into the instance.
: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]
@ -70,11 +72,11 @@ bool Identity::load_private_key(const Bytes& prv_bytes) {
_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->_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();
_object->_sig_pub = _object->_sig_prv->public_key();
_object->_sig_pub_bytes = _object->_sig_pub->public_bytes();
update_hashes();
@ -82,13 +84,10 @@ bool Identity::load_private_key(const Bytes& prv_bytes) {
}
catch (std::exception& e) {
//p raise e
error("Failed to load identity key";
error("The contained exception was: " + e.what());
error("Failed to load identity key");
error("The contained exception was: " + std::string(e.what()));
return false;
}
*/
// MOCK
return true;
}
/*
@ -98,7 +97,6 @@ Load a public key into the instance.
: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]
@ -106,15 +104,14 @@ void Identity::load_public_key(const Bytes& pub_bytes) {
//_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)
_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());
error("Error while loading public key, the contained exception was: " + std::string(e.what()));
}
*/
}
bool Identity::load(const char* path) {
@ -150,8 +147,10 @@ Recall identity for a destination hash.
: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) {
extreme("Identity::recall...");
auto iter = _known_destinations.find(destination_hash);
if (iter != _known_destinations.end()) {
extreme("Identity::recall: Found identity entry for destination " + destination_hash.toHex());
const IdentityEntry& identity_data = (*iter).second;
Identity identity(false);
identity.load_public_key(identity_data._public_key);
@ -159,13 +158,16 @@ Recall identity for a destination hash.
return identity;
}
else {
extreme("Identity::recall: Unable to find identity entry for destination " + destination_hash.toHex() + ", performing destination lookup...");
Destination registered_destination(Transport::find_destination_from_hash(destination_hash));
if (registered_destination) {
extreme("Identity::recall: Found destination " + destination_hash.toHex());
Identity identity(false);
identity.load_public_key(registered_destination.identity().get_public_key());
identity.app_data({Bytes::NONE});
return identity;
}
extreme("Identity::recall: Unable to find destination " + destination_hash.toHex());
return {Type::NONE};
}
}
@ -177,39 +179,46 @@ Recall last heard app_data for a destination hash.
:returns: *Bytes* containing app_data, or *None* if the destination is unknown.
*/
/*static*/ Bytes Identity::recall_app_data(const Bytes& destination_hash) {
extreme("Identity::recall_app_data...");
auto iter = _known_destinations.find(destination_hash);
if (iter != _known_destinations.end()) {
extreme("Identity::recall_app_data: Found identity entry for destination " + destination_hash.toHex());
const IdentityEntry& identity_data = (*iter).second;
return identity_data._app_data;
}
else {
extreme("Identity::recall_app_data: Unable to find identity entry for destination " + destination_hash.toHex());
return {Bytes::NONE};
}
}
/*static*/ void Identity::save_known_destinations() {
/*
/*static*/ bool 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
try {
if (_saving_known_destinations) {
double wait_interval = 0.2;
double wait_timeout = 5;
double wait_start = OS::dtime();
while (_saving_known_destinations) {
OS::sleep(wait_interval);
if (OS::dtime() > (wait_start + wait_timeout)) {
error("Could not save known destinations to storage, waiting for previous save operation timed out.");
return false;
}
}
}
Identity.saving_known_destinations = True
save_start = time.time()
_saving_known_destinations = true;
double save_start = OS::dtime();
storage_known_destinations = {}
std::map<Bytes, IdentityEntry> storage_known_destinations;
// TODO
/*
if os.path.isfile(RNS.Reticulum.storagepath+"/known_destinations"):
try:
file = open(RNS.Reticulum.storagepath+"/known_destinations","rb")
@ -217,32 +226,44 @@ Recall last heard app_data for a destination hash.
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]
for (auto& [destination_hash, identity_entry] : storage_known_destinations) {
if (_known_destinations.find(destination_hash) == _known_destinations.end()) {
//_known_destinations[destination_hash] = storage_known_destinations[destination_hash];
//_known_destinations[destination_hash] = identity_entry;
_known_destinations.insert({destination_hash, identity_entry});
}
}
RNS.log("Saving "+str(len(Identity.known_destinations))+" known destinations to storage...", RNS.LOG_DEBUG)
// TODO
/*
debug("Saving " + std::to_string(_known_destinations.size()) + " known destinations to storage...");
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
*/
std::string time_str;
double save_time = OS::dtime() - save_start;
if (save_time < 1) {
time_str = std::to_string(OS::round(save_time*1000, 2)) + "ms";
}
else {
time_str = std::to_string(OS::round(save_time, 2)) + "s";
}
debug("Saved known destinations to storage in " + time_str);
}
catch (std::exception& e) {
error("Error while saving known destinations to disk, the contained exception was: " + std::string(e.what()));
}
_saving_known_destinations = false;
}
/*static*/ void Identity::load_known_destinations() {
// TODO
/*
if os.path.isfile(RNS.Reticulum.storagepath+"/known_destinations"):
try:
@ -264,44 +285,62 @@ Recall last heard app_data for a destination hash.
}
/*static*/ bool Identity::validate_announce(const Packet& packet) {
try {
if (packet.packet_type() == Type::Packet::ANNOUNCE) {
Bytes destination_hash = packet.destination_hash();
extreme("Identity::validate_announce: destination_hash: " + packet.destination_hash().toHex());
Bytes public_key = packet.data().left(KEYSIZE/8);
extreme("Identity::validate_announce: public_key: " + public_key.toHex());
Bytes name_hash = packet.data().mid(KEYSIZE/8, NAME_HASH_LENGTH/8);
extreme("Identity::validate_announce: name_hash: " + name_hash.toHex());
Bytes random_hash = packet.data().mid(KEYSIZE/8 + NAME_HASH_LENGTH/8, RANDOM_HASH_LENGTH/8);
extreme("Identity::validate_announce: random_hash: " + random_hash.toHex());
Bytes signature = packet.data().mid(KEYSIZE/8 + NAME_HASH_LENGTH/8 + RANDOM_HASH_LENGTH/8, SIGLENGTH/8);
extreme("Identity::validate_announce: signature: " + signature.toHex());
Bytes app_data;
if (packet.data().size() > (KEYSIZE/8 + NAME_HASH_LENGTH/8 + RANDOM_HASH_LENGTH/8 + SIGLENGTH/8)) {
app_data = packet.data().mid(KEYSIZE/8 + NAME_HASH_LENGTH/8 + RANDOM_HASH_LENGTH/8 + SIGLENGTH/8);
}
extreme("Identity::validate_announce: app_data: " + app_data.toHex());
Bytes signed_data;
signed_data << packet.destination_hash() << public_key << name_hash << random_hash+app_data;
extreme("Identity::validate_announce: signed_data: " + signed_data.toHex());
if (packet.data().size() <= KEYSIZE/8 + NAME_HASH_LENGTH/8 + RANDOM_HASH_LENGTH/8 + SIGLENGTH/8) {
app_data.clear();
}
Identity announced_identity(false);
announced_identity.load_public_key(public_key);
if (announced_identity.pub() && announced_identity.validate(signature, signed_data)) {
Bytes hash_material = name_hash << announced_identity.hash();
Bytes expected_hash = full_hash(hash_material).left(Type::Reticulum::TRUNCATED_HASHLENGTH/8);
extreme("Identity::validate_announce: destination_hash: " + packet.destination_hash().toHex());
extreme("Identity::validate_announce: expected_hash: " + expected_hash.toHex());
if (packet.destination_hash() == expected_hash) {
// Check if we already have a public key for this destination
// and make sure the public key is not different.
auto iter = _known_destinations.find(packet.destination_hash());
if (iter != _known_destinations.end()) {
IdentityEntry& identity_entry = (*iter).second;
if (public_key != identity_entry._public_key) {
// In reality, this should never occur, but in the odd case
// that someone manages a hash collision, we reject the announce.
critical("Received announce with valid signature and destination hash, but announced public key does not match already known public key.");
critical("This may indicate an attempt to modify network paths, or a random hash collision. The announce was rejected.");
return false;
}
}
remember(packet.get_hash(), packet.destination_hash(), public_key, app_data);
//p del announced_identity
std::string signal_str;
// TODO
/*
try:
if packet.packet_type == RNS.Packet.ANNOUNCE:
destination_hash = packet.destination_hash
public_key = packet.data[:Identity.KEYSIZE//8]
name_hash = packet.data[Identity.KEYSIZE//8:Identity.KEYSIZE//8+Identity.NAME_HASH_LENGTH//8]
random_hash = packet.data[Identity.KEYSIZE//8+Identity.NAME_HASH_LENGTH//8:Identity.KEYSIZE//8+Identity.NAME_HASH_LENGTH//8+10]
signature = packet.data[Identity.KEYSIZE//8+Identity.NAME_HASH_LENGTH//8+10:Identity.KEYSIZE//8+Identity.NAME_HASH_LENGTH//8+10+Identity.SIGLENGTH//8]
app_data = b""
if len(packet.data) > Identity.KEYSIZE//8+Identity.NAME_HASH_LENGTH//8+10+Identity.SIGLENGTH//8:
app_data = packet.data[Identity.KEYSIZE//8+Identity.NAME_HASH_LENGTH//8+10+Identity.SIGLENGTH//8:]
signed_data = destination_hash+public_key+name_hash+random_hash+app_data
if not len(packet.data) > Identity.KEYSIZE//8+Identity.NAME_HASH_LENGTH//8+10+Identity.SIGLENGTH//8:
app_data = None
announced_identity = Identity(create_keys=False)
announced_identity.load_public_key(public_key)
if announced_identity.pub != None and announced_identity.validate(signature, signed_data):
hash_material = name_hash+announced_identity.hash
expected_hash = RNS.Identity.full_hash(hash_material)[:RNS.Reticulum.TRUNCATED_HASHLENGTH//8]
if destination_hash == expected_hash:
# Check if we already have a public key for this destination
# and make sure the public key is not different.
if destination_hash in Identity.known_destinations:
if public_key != Identity.known_destinations[destination_hash][2]:
# In reality, this should never occur, but in the odd case
# that someone manages a hash collision, we reject the announce.
RNS.log("Received announce with valid signature and destination hash, but announced public key does not match already known public key.", RNS.LOG_CRITICAL)
RNS.log("This may indicate an attempt to modify network paths, or a random hash collision. The announce was rejected.", RNS.LOG_CRITICAL)
return False
RNS.Identity.remember(packet.get_hash(), destination_hash, public_key, app_data)
del announced_identity
if packet.rssi != None or packet.snr != None:
signal_str = " ["
if packet.rssi != None:
@ -313,30 +352,35 @@ Recall last heard app_data for a destination hash.
signal_str += "]"
else:
signal_str = ""
if hasattr(packet, "transport_id") and packet.transport_id != None:
RNS.log("Valid announce for "+RNS.prettyhexrep(destination_hash)+" "+str(packet.hops)+" hops away, received via "+RNS.prettyhexrep(packet.transport_id)+" on "+str(packet.receiving_interface)+signal_str, RNS.LOG_EXTREME)
else:
RNS.log("Valid announce for "+RNS.prettyhexrep(destination_hash)+" "+str(packet.hops)+" hops away, received on "+str(packet.receiving_interface)+signal_str, RNS.LOG_EXTREME)
return True
else:
RNS.log("Received invalid announce for "+RNS.prettyhexrep(destination_hash)+": Destination mismatch.", RNS.LOG_DEBUG)
return False
else:
RNS.log("Received invalid announce for "+RNS.prettyhexrep(destination_hash)+": Invalid signature.", RNS.LOG_DEBUG)
del announced_identity
return False
except Exception as e:
RNS.log("Error occurred while validating announce. The contained exception was: "+str(e), RNS.LOG_ERROR)
return False
*/
// MOCK
if (packet.transport_id()) {
extreme("Valid announce for " + packet.destination_hash().toHex() + " " + std::to_string(packet.hops()) + " hops away, received via " + packet.transport_id().toHex() + " on " + packet.receiving_interface().toString() + signal_str);
}
else {
extreme("Valid announce for " + packet.destination_hash().toHex() + " " + std::to_string(packet.hops()) + " hops away, received on " + packet.receiving_interface().toString() + signal_str);
}
return true;
}
else {
debug("Received invalid announce for " + packet.destination_hash().toHex() + ": Destination mismatch.");
return false;
}
}
else {
debug("Received invalid announce for " + packet.destination_hash().toHex() + ": Invalid signature.");
//p del announced_identity
return false;
}
}
}
catch (std::exception& e) {
error("Error occurred while validating announce. The contained exception was: " + std::string(e.what()));
return false;
}
return false;
}
/*
Encrypts information for the identity.
@ -465,6 +509,7 @@ bool Identity::validate(const Bytes& signature, const Bytes& message) const {
assert(_object);
if (_object->_pub) {
try {
extreme("Identity::validate: Attempting to verify signature: " + signature.toHex() + " and message: " + message.toHex());
_object->_sig_pub->verify(signature, message);
return true;
}

View File

@ -36,21 +36,25 @@ namespace RNS {
Bytes _app_data;
};
public:
static std::map<Bytes, IdentityEntry> _known_destinations;
static bool _saving_known_destinations;
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()));
mem("Identity NONE object created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
}
Identity(const Identity& identity) : _object(identity._object) {
extreme("Identity object copy created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
mem("Identity object copy created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
}
Identity(bool create_keys = true);
virtual ~Identity() {
extreme("Identity object destroyed, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
mem("Identity object destroyed, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
}
inline Identity& operator = (const Identity& identity) {
_object = identity._object;
extreme("Identity object copy created by assignment, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
mem("Identity object copy created by assignment, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
return *this;
}
inline operator bool() const {
@ -102,7 +106,7 @@ namespace RNS {
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 bool save_known_destinations();
static void load_known_destinations();
/*
Get a SHA-256 hash of passed data.
@ -141,29 +145,31 @@ namespace RNS {
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 std::string hexhash() const { assert(_object); return _object->_hexhash; }
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 const Cryptography::X25519PrivateKey::Ptr prv() const { assert(_object); return _object->_prv; }
inline const Cryptography::X25519PublicKey::Ptr pub() const { assert(_object); return _object->_pub; }
inline std::string toString() const { assert(_object); return "{Identity:" + _object->_hash.toHex() + "}"; }
private:
class Object {
public:
Object() { extreme("Identity::Data object created, this: " + std::to_string((uintptr_t)this)); }
virtual ~Object() { extreme("Identity::Data object destroyed, this: " + std::to_string((uintptr_t)this)); }
Object() { mem("Identity::Data object created, this: " + std::to_string((uintptr_t)this)); }
virtual ~Object() { mem("Identity::Data object destroyed, this: " + std::to_string((uintptr_t)this)); }
private:
RNS::Cryptography::X25519PrivateKey::Ptr _prv;
Cryptography::X25519PrivateKey::Ptr _prv;
Bytes _prv_bytes;
RNS::Cryptography::Ed25519PrivateKey::Ptr _sig_prv;
Cryptography::Ed25519PrivateKey::Ptr _sig_prv;
Bytes _sig_prv_bytes;
RNS::Cryptography::X25519PublicKey::Ptr _pub;
Cryptography::X25519PublicKey::Ptr _pub;
Bytes _pub_bytes;
RNS::Cryptography::Ed25519PublicKey::Ptr _sig_pub;
Cryptography::Ed25519PublicKey::Ptr _sig_pub;
Bytes _sig_pub_bytes;
Bytes _hash;
@ -175,8 +181,6 @@ namespace RNS {
};
std::shared_ptr<Object> _object;
static std::map<Bytes, IdentityEntry> _known_destinations;
};
}

View File

@ -6,6 +6,8 @@
using namespace RNS;
using namespace RNS::Type::Interface;
/*static*/ uint8_t Interface::DISCOVER_PATHS_FOR = MODE_ACCESS_POINT | MODE_GATEWAY;
/*virtual*/ inline void Interface::processIncoming(const Bytes& data) {
extreme("Interface::processIncoming: data: " + data.toHex());
assert(_object);

View File

@ -30,31 +30,34 @@ namespace RNS {
Bytes _raw;
};
protected:
using HInterface = std::shared_ptr<Interface>;
public:
// Which interface modes a Transport Node
// should actively discover paths for.
uint8_t DISCOVER_PATHS_FOR = Type::Interface::MODE_ACCESS_POINT | Type::Interface::MODE_GATEWAY;
static uint8_t DISCOVER_PATHS_FOR;
public:
Interface(Type::NoneConstructor none) {
extreme("Interface object NONE created");
mem("Interface object NONE created");
}
Interface(const Interface& interface) : _object(interface._object) {
extreme("Interface object copy created");
mem("Interface object copy created");
}
Interface() : _object(new Object()) {
extreme("Interface object created");
mem("Interface object created");
}
Interface(const char* name) : _object(new Object(name)) {
extreme("Interface object created");
mem("Interface object created");
}
virtual ~Interface() {
extreme("Interface object destroyed");
mem("Interface object destroyed");
}
inline Interface& operator = (const Interface& interface) {
_object = interface._object;
extreme("Interface object copy created by assignment, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
mem("Interface object copy created by assignment, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
return *this;
}
inline operator bool() const {
@ -81,19 +84,25 @@ namespace RNS {
inline void FWD(bool FWD) { assert(_object); _object->_FWD = FWD; }
inline void RPT(bool RPT) { assert(_object); _object->_RPT = RPT; }
inline void name(const char* name) { assert(_object); _object->_name = name; }
inline void bitrate(uint32_t bitrate) { assert(_object); _object->_bitrate = bitrate; }
inline void online(bool online) { assert(_object); _object->_online = online; }
inline void announce_allowed_at(uint64_t announce_allowed_at) { assert(_object); _object->_announce_allowed_at = announce_allowed_at; }
public:
inline bool IN() const { assert(_object); return _object->_IN; }
inline bool OUT() const { assert(_object); return _object->_OUT; }
inline bool FWD() const { assert(_object); return _object->_FWD; }
inline bool RPT() const { assert(_object); return _object->_RPT; }
inline bool online() const { assert(_object); return _object->_online; }
inline std::string name() const { assert(_object); return _object->_name; }
inline const Bytes& ifac_identity() const { assert(_object); return _object->_ifac_identity; }
inline Type::Interface::modes mode() const { assert(_object); return _object->_mode; }
inline uint32_t bitrate() const { assert(_object); return _object->_bitrate; }
inline uint64_t announce_allowed_at() const { assert(_object); return _object->_announce_allowed_at; }
inline void announce_allowed_at(uint64_t announce_allowed_at) { assert(_object); _object->_announce_allowed_at = announce_allowed_at; }
inline float announce_cap() const { assert(_object); return _object->_announce_cap; }
inline std::list<AnnounceEntry>& announce_queue() const { assert(_object); return _object->_announce_queue; }
inline bool is_connected_to_shared_instance() const { assert(_object); return _object->_is_connected_to_shared_instance; }
inline bool is_local_shared_instance() const { assert(_object); return _object->_is_local_shared_instance; }
inline HInterface parent_interface() const { assert(_object); return _object->_parent_interface; }
virtual inline std::string toString() const { assert(_object); return "Interface[" + _object->_name + "]"; }
@ -111,18 +120,22 @@ namespace RNS {
std::string _name;
size_t _rxb = 0;
size_t _txb = 0;
bool online = false;
bool _online = false;
Bytes _ifac_identity;
Type::Interface::modes _mode = Type::Interface::MODE_NONE;
uint32_t _bitrate = 0;
uint64_t _announce_allowed_at = 0;
float _announce_cap = 0.0;
std::list<AnnounceEntry> _announce_queue;
bool _is_connected_to_shared_instance = false;
bool _is_local_shared_instance = false;
HInterface _parent_interface;
//Transport& _owner;
friend class Interface;
};
std::shared_ptr<Object> _object;
friend class Transport;
};
}

View File

@ -0,0 +1,134 @@
#include "UDPInterface.h"
#include "../Log.h"
#include <memory>
using namespace RNS;
using namespace RNS::Interfaces;
/*
@staticmethod
def get_address_for_if(name):
import RNS.vendor.ifaddr.niwrapper as netinfo
ifaddr = netinfo.ifaddresses(name)
return ifaddr[netinfo.AF_INET][0]["addr"]
@staticmethod
def get_broadcast_for_if(name):
import RNS.vendor.ifaddr.niwrapper as netinfo
ifaddr = netinfo.ifaddresses(name)
return ifaddr[netinfo.AF_INET][0]["broadcast"]
*/
//p def __init__(self, owner, name, device=None, bindip=None, bindport=None, forwardip=None, forwardport=None):
UDPInterface::UDPInterface(const char* name /*= "UDPInterface"*/) : Interface(name) {
IN(true);
//OUT(false);
OUT(true);
bitrate(BITRATE_GUESS);
}
void UDPInterface::start() {
#ifdef ARDUINO
// Connect to the WiFi network
WiFi.begin(ssid, pwd);
Serial.println("");
// Wait for WiFi network connection to complete
Serial.print("Connecting to ");
Serial.print(ssid);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// Listen for received UDP packets
/*
if (udp.listen(udpPort)) {
Serial.print("UDP Listening on IP: ");
Serial.println(WiFi.localIP());
udp.onPacket([](AsyncUDPPacket packet) {
Serial.print("UDP Packet Type: ");
Serial.print(packet.isBroadcast() ? "Broadcast" : packet.isMulticast() ? "Multicast" : "Unicast");
Serial.print(", From: ");
Serial.print(packet.remoteIP());
Serial.print(":");
Serial.print(packet.remotePort());
Serial.print(", To: ");
Serial.print(packet.localIP());
Serial.print(":");
Serial.print(packet.localPort());
Serial.print(", Length: ");
Serial.print(packet.length()); //dlzka packetu
Serial.print(", Data: ");
Serial.write(packet.data(), packet.length());
Serial.println();
String myString = (const char*)packet.data();
if (myString == "ZAP") {
Serial.println("Zapinam rele");
digitalWrite(rele, LOW);
} else if (myString == "VYP") {
Serial.println("Vypinam rele");
digitalWrite(rele, HIGH);
}
packet.printf("Got %u bytes of data", packet.length());
});
}
*/
// This initializes udp and transfer buffer
udp.begin(udpPort);
#endif
online(true);
}
void UDPInterface::loop() {
if (online()) {
// Check for incoming packet
#ifdef ARDUINO
udp.parsePacket();
size_t len = udp.read(buffer.writable(Type::Reticulum::MTU), Type::Reticulum::MTU);
if (len > 0) {
buffer.resize(len);
processIncoming(buffer);
}
#endif
}
}
/*virtual*/ void UDPInterface::processIncoming(const Bytes& data) {
debug("UDPInterface.processIncoming: data: " + data.toHex());
//debug("UDPInterface.processIncoming: text: " + data.toString());
Interface::processIncoming(data);
}
/*virtual*/ void UDPInterface::processOutgoing(const Bytes& data) {
debug("UDPInterface.processOutgoing: data: " + data.toHex());
debug("UDPInterface.processOutgoing: text: " + data.toString());
try {
if (online()) {
// Send packet
#ifdef ARDUINO
udp.beginPacket(udpAddress, udpPort);
udp.write(data.data(), data.size());
udp.endPacket();
#endif
}
Interface::processOutgoing(data);
}
catch (std::exception& e) {
error("Could not transmit on " + toString() + ". The contained exception was: " + e.what());
}
}

View File

@ -0,0 +1,61 @@
#pragma once
#include "../Interface.h"
#include "../Bytes.h"
#include "../Type.h"
#ifdef ARDUINO
#include <WiFi.h>
#include <WiFiUdp.h>
//#include <AsyncUDP.h>
#endif
#include <stdint.h>
namespace RNS { namespace Interfaces {
class UDPInterface : public Interface {
public:
static const uint32_t BITRATE_GUESS = 10*1000*1000;
//z def get_address_for_if(name):
//z def get_broadcast_for_if(name):
public:
//p def __init__(self, owner, name, device=None, bindip=None, bindport=None, forwardip=None, forwardport=None):
UDPInterface(const char* name = "UDPInterface");
void start();
void loop();
virtual void processIncoming(const Bytes& data);
virtual void processOutgoing(const Bytes& data);
//virtual inline std::string toString() const { return "UDPInterface[" + name() + "/" + bind_ip + ":" + bind_port + "]"; }
virtual inline std::string toString() const { return "UDPInterface[" + name() + "]"; }
private:
const uint16_t HW_MTU = 1064;
//uint8_t buffer[Type::Reticulum::MTU] = {0};
Bytes buffer;
// WiFi network name and password
const char* ssid = "some-ssid";
const char* pwd = "some-pass";
// IP address to send UDP data to.
// it can be ip address of the server or
// broadcast
const char* udpAddress = "255.255.255.255";
const int udpPort = 4242;
// create UDP instance
#ifdef ARDUINO
WiFiUDP udp;
//AsyncUDP udp;
#endif
};
} }

View File

@ -9,7 +9,7 @@ using namespace RNS::Type::Link;
Link::Link() : _object(new Object()) {
assert(_object);
extreme("Link object created");
mem("Link object created");
}

View File

@ -20,14 +20,14 @@ namespace RNS {
public:
Link(Type::NoneConstructor none) {
extreme("Link NONE object created");
mem("Link NONE object created");
}
Link(const Link& link) : _object(link._object) {
extreme("Link object copy created");
mem("Link object copy created");
}
Link();
virtual ~Link(){
extreme("Link object destroyed");
mem("Link object destroyed");
}
inline Link& operator = (const Link& link) {

View File

@ -22,12 +22,15 @@ const char* getLevelName(LogLevel level) {
return "DEBUG";
case LOG_EXTREME:
return "EXTRA";
case LOG_MEM:
return "MEM";
default:
return "";
}
}
LogLevel _level = LOG_VERBOSE;
//LogLevel _level = LOG_VERBOSE;
LogLevel _level = LOG_EXTREME;
void RNS::loglevel(LogLevel level) {
_level = level;
@ -41,7 +44,7 @@ void RNS::doLog(const char *msg, LogLevel level) {
if (level > _level) {
return;
}
#ifndef NATIVE
#ifdef ARDUINO
Serial.print(getLevelName(level));
Serial.print(" ");
Serial.println(msg);
@ -55,7 +58,7 @@ void RNS::head(const char *msg, LogLevel level) {
if (level > _level) {
return;
}
#ifndef NATIVE
#ifdef ARDUINO
Serial.println("");
#else
printf("\n");

View File

@ -1,6 +1,6 @@
#pragma once
#ifndef NATIVE
#ifdef ARDUINO
#include <Arduino.h>
#endif
@ -17,6 +17,7 @@ namespace RNS {
LOG_VERBOSE = 5,
LOG_DEBUG = 6,
LOG_EXTREME = 7,
LOG_MEM = 8,
};
void loglevel(LogLevel level);
@ -25,7 +26,7 @@ namespace RNS {
void doLog(const char* msg, LogLevel level);
inline void log(const char* msg, LogLevel level = LOG_NOTICE) { doLog(msg, level); }
#ifndef NATIVE
#ifdef ARDUINO
inline void log(const String msg, LogLevel level = LOG_NOTICE) { doLog(msg.c_str(), level); }
#endif
inline void log(const std::string& msg, LogLevel level = LOG_NOTICE) { doLog(msg.c_str(), level); }
@ -54,6 +55,9 @@ namespace RNS {
inline void extreme(const char* msg) { doLog(msg, LOG_EXTREME); }
inline void extreme(const std::string& msg) { doLog(msg.c_str(), LOG_EXTREME); }
inline void mem(const char* msg) { doLog(msg, LOG_MEM); }
inline void mem(const std::string& msg) { doLog(msg.c_str(), LOG_MEM); }
void head(const char* msg, LogLevel level = LOG_NOTICE);
inline void head(const std::string& msg, LogLevel level = LOG_NOTICE) { head(msg.c_str(), level); }

View File

@ -41,11 +41,11 @@ Packet::Packet(const Destination& destination, const Interface& attached_interfa
_object->_fromPacked = true;
_object->_create_receipt = false;
}
extreme("Packet object created");
mem("Packet object created");
}
Packet::~Packet() {
extreme("Packet object destroyed");
mem("Packet object destroyed");
}

View File

@ -3,6 +3,7 @@
#include "Destination.h"
#include "Link.h"
#include "Interface.h"
#include "Log.h"
#include "Type.h"
#include "Utilities/OS.h"
@ -124,10 +125,10 @@ namespace RNS {
public:
Packet(Type::NoneConstructor none) {
extreme("Packet NONE object created");
mem("Packet NONE object created");
}
Packet(const Packet& packet) : _object(packet._object) {
extreme("Packet object copy created");
mem("Packet object copy created");
}
Packet(
const Destination& destination,
@ -154,7 +155,7 @@ namespace RNS {
inline Packet& operator = (const Packet& packet) {
_object = packet._object;
extreme("Packet object copy created by assignment, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
mem("Packet object copy created by assignment, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
return *this;
}
inline operator bool() const {

View File

@ -5,6 +5,11 @@
#include <RNG.h>
#ifdef ARDUINO
//#include <TransistorNoiseSource.h>
//#include <Ethernet.h>
#endif
using namespace RNS;
using namespace RNS::Type::Reticulum;
@ -13,6 +18,11 @@ using namespace RNS::Type::Reticulum;
/*static*/ bool Reticulum::__allow_probes = false;
/*static*/ bool Reticulum::panic_on_interface_error = false;
#ifdef ARDUINO
// Noise source to seed the random number generator.
//TransistorNoiseSource noise(A1);
#endif
/*
Initialises and starts a Reticulum instance. This must be
done before any other operations, and Reticulum will not
@ -22,10 +32,21 @@ pass any traffic before being instantiated.
*/
//def __init__(self,configdir=None, loglevel=None, logdest=None, verbosity=None):
Reticulum::Reticulum() : _object(new Object()) {
mem("Reticulum default object creating..., this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
// Initialkize random number generator
RNG.begin("Reticulum");
//RNG.stir(mac_address, sizeof(mac_address));
#ifdef ARDUINO
// Stir in the Ethernet MAC address.
//byte mac[6];
//Ethernet.begin(mac);
// WiFi.macAddress(mac);
//RNG.stir(mac, sizeof(mac));
// Add the noise source to the list of sources known to RNG.
//RNG.addNoiseSource(noise);
#endif
/*
RNS.vendor.platformutils.platform_checks()
@ -128,11 +149,7 @@ Reticulum::Reticulum() : _object(new Object()) {
signal.signal(signal.SIGTERM, Reticulum.sigterm_handler)
*/
extreme("Reticulum object created");
}
Reticulum::~Reticulum() {
extreme("Reticulum object destroyed");
mem("Reticulum default object created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
}

View File

@ -19,17 +19,19 @@ namespace RNS {
public:
Reticulum(Type::NoneConstructor none) {
extreme("Reticulum NONE object created");
mem("Reticulum NONE object created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
}
Reticulum(const Reticulum& reticulum) : _object(reticulum._object) {
extreme("Reticulum object copy created");
mem("Reticulum object copy created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
}
Reticulum();
virtual ~Reticulum();
virtual ~Reticulum() {
mem("Reticulum object destroyed, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
}
inline Reticulum& operator = (const Reticulum& reticulum) {
_object = reticulum._object;
extreme("Reticulum object copy created by assignment, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
mem("Reticulum object copy created by assignment, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
return *this;
}
inline operator bool() const {
@ -69,8 +71,12 @@ namespace RNS {
private:
class Object {
public:
Object() {}
virtual ~Object() {}
Object() {
mem("Reticulum data object created, this: " + std::to_string((uintptr_t)this));
}
virtual ~Object() {
mem("Reticulum data object destroyed, this: " + std::to_string((uintptr_t)this));
}
private:
bool _is_connected_to_shared_instance = false;
friend class Reticulum;

View File

@ -4,20 +4,9 @@
void test() {
//RNS::LogLevel loglevel = RNS::loglevel();
//RNS::loglevel(RNS::LOG_WARNING);
testBytes();
testCowBytes();
testBytesConversion();
testMap();
testCollections();
testReference();
testCrypto();
testHMAC();
testPKCS7();
//RNS::loglevel(loglevel);
}

View File

@ -1,13 +1,7 @@
void test();
void testMap();
void testBytes();
void testCowBytes();
void testBytesConversion();
void testCollections();
void testReference();
void testCrypto();
void testHMAC();
void testPKCS7();

View File

@ -3,7 +3,6 @@
#include "Bytes.h"
#include "Log.h"
#include <map>
#include <assert.h>
//void testBytesDefault(const RNS::Bytes& bytes = {RNS::Bytes::NONE}) {
@ -21,7 +20,7 @@ const RNS::Bytes& testBytesReference() {
return ref;
}
void testBytes() {
void testBytesMain() {
RNS::Bytes bytes;
assert(!bytes);
@ -32,7 +31,7 @@ void testBytes() {
const uint8_t prestr[] = "Hello";
const uint8_t poststr[] = " World";
RNS::Bytes prebuf(prestr, 5);
const RNS::Bytes prebuf(prestr, 5);
assert(prebuf);
assert(prebuf.size() == 5);
assert(memcmp(prebuf.data(), "Hello", prebuf.size()) == 0);
@ -40,7 +39,7 @@ void testBytes() {
assert(bytes != prebuf);
assert(bytes < prebuf);
RNS::Bytes postbuf(poststr, 6);
const RNS::Bytes postbuf(poststr, 6);
assert(postbuf);
assert(postbuf.size() == 6);
assert(memcmp(postbuf.data(), " World", postbuf.size()) == 0);
@ -152,9 +151,9 @@ void testBytes() {
{
RNS::Bytes strmbuf;
strmbuf << prebuf << postbuf;
RNS::extreme("stream strmbuf: " + strmbuf.toString());
RNS::extreme("stream prebuf: " + prebuf.toString());
RNS::extreme("stream postbuf: " + postbuf.toString());
RNS::extreme("stream strmbuf: " + strmbuf.toString());
assert(strmbuf.size() == 11);
assert(memcmp(strmbuf.data(), "Hello World", strmbuf.size()) == 0);
assert(prebuf.size() == 5);
@ -171,9 +170,9 @@ void testBytes() {
assert(memcmp(strmbuf.data(), "Stream ", strmbuf.size()) == 0);
strmbuf << prebuf << postbuf;
RNS::extreme("stream strmbuf: " + strmbuf.toString());
RNS::extreme("stream prebuf: " + prebuf.toString());
RNS::extreme("stream postbuf: " + postbuf.toString());
RNS::extreme("stream strmbuf: " + strmbuf.toString());
assert(strmbuf.size() == 18);
assert(memcmp(strmbuf.data(), "Stream Hello World", strmbuf.size()) == 0);
assert(prebuf.size() == 5);
@ -183,18 +182,23 @@ void testBytes() {
}
// stream with assignment
// (this is a known and correct but perhaps unexpected and non-intuitive side-effect of assignment with stream)
// (side effect of also updating pre - this is a known and correct but perhaps unexpected and non-intuitive side-effect of assignment with stream)
{
RNS::Bytes strmbuf = prebuf << postbuf;
// NOTE pre must be volatile in order for below stream with assignment to work (since it gets modified)
RNS::Bytes pre("Hello");
assert(pre.size() == 5);
const RNS::Bytes post(" World");
assert(post.size() == 6);
RNS::Bytes strmbuf = pre << post;
RNS::extreme("stream pre: " + prebuf.toString());
RNS::extreme("stream post: " + postbuf.toString());
RNS::extreme("stream strmbuf: " + strmbuf.toString());
RNS::extreme("stream prebuf: " + prebuf.toString());
RNS::extreme("stream postbuf: " + postbuf.toString());
assert(strmbuf.size() == 11);
assert(memcmp(strmbuf.data(), "Hello World", strmbuf.size()) == 0);
assert(prebuf.size() == 11);
assert(memcmp(prebuf.data(), "Hello World", prebuf.size()) == 0);
assert(postbuf.size() == 6);
assert(memcmp(postbuf.data(), " World", postbuf.size()) == 0);
assert(pre.size() == 11);
assert(memcmp(pre.data(), "Hello World", pre.size()) == 0);
assert(post.size() == 6);
assert(memcmp(post.data(), " World", post.size()) == 0);
}
// test creating bytes from default
@ -230,11 +234,11 @@ void testBytes() {
}
// function default argument
RNS::head("TestBytes: function default argument", RNS::LOG_EXTREME);
RNS::extreme("TestBytes: function default argument");
testBytesDefault();
// function reference return
RNS::head("TestBytes: function reference return", RNS::LOG_EXTREME);
RNS::extreme("TestBytes: function reference return");
{
RNS::Bytes test = testBytesReference();
RNS::extreme("returned");
@ -336,52 +340,11 @@ void testBytesConversion() {
}
void testMap()
{
const uint8_t prestr[] = "Hello";
const uint8_t poststr[] = "World";
RNS::Bytes prebuf(prestr, 5);
assert(prebuf.size() == 5);
assert(memcmp(prebuf.data(), "Hello", prebuf.size()) == 0);
RNS::Bytes postbuf(poststr, 5);
assert(postbuf.size() == 5);
assert(memcmp(postbuf.data(), "World", postbuf.size()) == 0);
std::map<RNS::Bytes, std::string> map;
map.insert({prebuf, "hello"});
map.insert({postbuf, "world"});
assert(map.size() == 2);
auto preit = map.find(prebuf);
assert(preit != map.end());
assert((*preit).second.compare("hello") == 0);
if (preit != map.end()) {
RNS::extreme(std::string("found prebuf: ") + (*preit).second);
}
auto postit = map.find(postbuf);
assert(postit != map.end());
assert((*postit).second.compare("world") == 0);
if (postit != map.end()) {
RNS::extreme(std::string("found postbuf: ") + (*postit).second);
}
const uint8_t newstr[] = "World";
RNS::Bytes newbuf(newstr, 5);
assert(newbuf.size() == 5);
assert(memcmp(newbuf.data(), "World", newbuf.size()) == 0);
auto newit = map.find(newbuf);
assert(newit != map.end());
assert((*newit).second.compare("world") == 0);
if (newit != map.end()) {
RNS::extreme(std::string("found newbuf: ") + (*newit).second);
}
std::string str = map["World"];
assert(str.size() == 5);
assert(str.compare("world") == 0);
void testBytes() {
RNS::head("Running testBytes...", RNS::LOG_EXTREME);
testBytesMain();
testCowBytes();
testBytesConversion();
}
/*

View File

@ -0,0 +1,136 @@
//#include <unity.h>
#include "Bytes.h"
#include "Log.h"
#include <map>
#include <string>
#include <assert.h>
void testBytesMap()
{
const uint8_t prestr[] = "Hello";
const uint8_t poststr[] = "World";
RNS::Bytes prebuf(prestr, 5);
assert(prebuf.size() == 5);
assert(memcmp(prebuf.data(), "Hello", prebuf.size()) == 0);
RNS::Bytes postbuf(poststr, 5);
assert(postbuf.size() == 5);
assert(memcmp(postbuf.data(), "World", postbuf.size()) == 0);
std::map<RNS::Bytes, std::string> map;
map.insert({prebuf, "hello"});
map.insert({postbuf, "world"});
assert(map.size() == 2);
auto preit = map.find(prebuf);
assert(preit != map.end());
assert((*preit).second.compare("hello") == 0);
if (preit != map.end()) {
RNS::extreme(std::string("found prebuf: ") + (*preit).second);
}
auto postit = map.find(postbuf);
assert(postit != map.end());
assert((*postit).second.compare("world") == 0);
if (postit != map.end()) {
RNS::extreme(std::string("found postbuf: ") + (*postit).second);
}
const uint8_t newstr[] = "World";
RNS::Bytes newbuf(newstr, 5);
assert(newbuf.size() == 5);
assert(memcmp(newbuf.data(), "World", newbuf.size()) == 0);
auto newit = map.find(newbuf);
assert(newit != map.end());
assert((*newit).second.compare("world") == 0);
if (newit != map.end()) {
RNS::extreme(std::string("found newbuf: ") + (*newit).second);
}
std::string str = map["World"];
assert(str.size() == 5);
assert(str.compare("world") == 0);
}
class Entry {
public:
// CBA for some reason default constructor is required for map index reference/asign to work
// ("error: no matching constructor for initialization of 'Entry'" results otherwise)
Entry() { RNS::extreme("Entry: default constructor"); }
Entry(const Entry& entry) : _hash(entry._hash) { RNS::extreme("Entry: copy constructor"); }
Entry(const char* hash) : _hash(hash) { RNS::extreme("Entry: hash constructor"); }
RNS::Bytes _hash;
};
void testNewMap() {
std::map<RNS::Bytes, Entry> entries;
std::map<RNS::Bytes, Entry> other_entries;
{
Entry some_entry("some hash");
entries.insert({some_entry._hash, some_entry});
Entry some_other_entry("some other hash");
other_entries.insert({some_entry._hash, some_entry});
other_entries.insert({some_other_entry._hash, some_other_entry});
}
assert(entries.size() == 1);
assert(other_entries.size() == 2);
for (auto& [hash, entry] : other_entries) {
if (entries.find(hash) == entries.end()) {
entries[hash] = other_entries[hash];
}
}
for (auto& [hash, entry] : entries) {
RNS::extreme("entries: " + entry._hash.toString());
}
assert(entries.size() == 2);
assert(other_entries.size() == 2);
}
void testCollections() {
RNS::head("Running testCollections...", RNS::LOG_EXTREME);
testBytesMap();
testNewMap();
}
/*
void setUp(void) {
// set stuff up here
}
void tearDown(void) {
// clean stuff up here
}
int runUnityTests(void) {
UNITY_BEGIN();
RUN_TEST(testCollections);
return UNITY_END();
}
// For native dev-platform or for some embedded frameworks
int main(void) {
return runUnityTests();
}
// For Arduino framework
void setup() {
// Wait ~2 seconds before the Unity test runner
// establishes connection with a board Serial interface
delay(2000);
runUnityTests();
}
void loop() {}
// For ESP-IDF framework
void app_main() {
runUnityTests();
}
*/

View File

@ -12,11 +12,13 @@
#include <assert.h>
void testCrypto() {
void testCryptoMain() {
RNS::Reticulum reticulum;
RNS::Reticulum reticulum_crypto;
assert(reticulum_crypto);
RNS::Identity identity;
assert(identity);
RNS::Destination destination(identity, RNS::Type::Destination::IN, RNS::Type::Destination::SINGLE, "appname", "aspects");
//assert(encryptionPrivateKey().toHex().compare("") == );
@ -126,6 +128,13 @@ void testPKCS7() {
}
}
void testCrypto() {
RNS::head("Running testCrypto...", RNS::LOG_EXTREME);
testCryptoMain();
testHMAC();
testPKCS7();
}
/*
int main(void)
{

View File

@ -6,6 +6,7 @@
#include <assert.h>
void testReference() {
RNS::head("Running testReference...", RNS::LOG_EXTREME);
RNS::Reticulum reticulum_default;
assert(reticulum_default);
@ -19,6 +20,101 @@ void testReference() {
RNS::Reticulum reticulum_none_copy(reticulum_none);
assert(!reticulum_none_copy);
/*
RNS::loglevel(RNS::LOG_EXTREME);
TestInterface testinterface;
std::set<std::reference_wrapper<RNS::Interface>, std::less<RNS::Interface>> interfaces;
interfaces.insert(testinterface);
for (auto iter = interfaces.begin(); iter != interfaces.end(); ++iter) {
RNS::Interface& interface = (*iter);
RNS::extreme("Found interface: " + interface.toString());
RNS::Bytes data;
const_cast<RNS::Interface&>(interface).processOutgoing(data);
}
return 0;
*/
/*
RNS::loglevel(RNS::LOG_EXTREME);
TestInterface testinterface;
std::set<std::reference_wrapper<RNS::Interface>, std::less<RNS::Interface>> interfaces;
interfaces.insert(testinterface);
for (auto& interface : interfaces) {
RNS::extreme("Found interface: " + interface.toString());
RNS::Bytes data;
const_cast<RNS::Interface&>(interface).processOutgoing(data);
}
return 0;
*/
/*
RNS::loglevel(RNS::LOG_EXTREME);
TestInterface testinterface;
std::list<std::reference_wrapper<RNS::Interface>> interfaces;
interfaces.push_back(testinterface);
for (auto iter = interfaces.begin(); iter != interfaces.end(); ++iter) {
RNS::Interface& interface = (*iter);
RNS::extreme("Found interface: " + interface.toString());
RNS::Bytes data;
const_cast<RNS::Interface&>(interface).processOutgoing(data);
}
return 0;
*/
/*
RNS::loglevel(RNS::LOG_EXTREME);
TestInterface testinterface;
std::list<std::reference_wrapper<RNS::Interface>> interfaces;
interfaces.push_back(testinterface);
//for (auto& interface : interfaces) {
for (RNS::Interface& interface : interfaces) {
RNS::extreme("Found interface: " + interface.toString());
RNS::Bytes data;
const_cast<RNS::Interface&>(interface).processOutgoing(data);
}
return 0;
*/
/*
std::list<std::reference_wrapper<RNS::Interface>> interfaces;
{
RNS::loglevel(RNS::LOG_EXTREME);
TestInterface testinterface;
interfaces.push_back(testinterface);
for (auto iter = interfaces.begin(); iter != interfaces.end(); ++iter) {
RNS::Interface& interface = (*iter);
RNS::extreme("1 Found interface: " + interface.toString());
RNS::Bytes data;
const_cast<RNS::Interface&>(interface).processOutgoing(data);
}
}
for (auto iter = interfaces.begin(); iter != interfaces.end(); ++iter) {
RNS::Interface& interface = (*iter);
RNS::extreme("2 Found interface: " + interface.toString());
RNS::Bytes data;
const_cast<RNS::Interface&>(interface).processOutgoing(data);
}
return 0;
*/
/*
RNS::head("Testing map...", RNS::LOG_EXTREME);
{
std::map<RNS::Bytes, RNS::Destination&> destinations;
destinations.insert({destination.hash(), destination});
//for (RNS::Destination& destination : destinations) {
for (auto& [hash, destination] : destinations) {
RNS::extreme("Iterated destination: " + destination.toString());
}
RNS::Bytes hash = destination.hash();
auto iter = destinations.find(hash);
if (iter != destinations.end()) {
RNS::Destination& destination = (*iter).second;
RNS::extreme("Found destination: " + destination.toString());
}
return;
}
*/
}
/*

View File

@ -39,10 +39,12 @@ using namespace RNS::Utilities;
/*static*/ std::map<Bytes, Transport::DestinationEntry> Transport::_destination_table;
/*static*/ std::map<Bytes, Transport::ReverseEntry> Transport::_reverse_table;
/*static*/ std::map<Bytes, Transport::LinkEntry> Transport::_link_table;
/*static*/ std::map<Bytes, Transport::AnnounceEntry> Transport::_held_announces;
/*static*/ std::set<HAnnounceHandler> Transport::_announce_handlers;
/*static*/ std::set<Bytes> Transport::_path_requests;
/*static*/ std::map<Bytes, uint64_t> Transport::_path_requests;
/*static*/ std::map<Bytes, Transport::PathRequestEntry> Transport::_discovery_path_requests;
/*static*/ std::set<Bytes> Transport::_discovery_pr_tags;
/*static*/ uint16_t Transport::_max_pr_taXgxs = 32000;
/*static*/ std::set<Destination> Transport::_control_destinations;
@ -73,6 +75,7 @@ using namespace RNS::Utilities;
/*static*/ Identity Transport::_identity({Type::NONE});
/*static*/ void Transport::start(const Reticulum& reticulum_instance) {
info("Transport starting...");
_jobs_running = true;
_owner = reticulum_instance;
@ -92,6 +95,7 @@ using namespace RNS::Utilities;
}
}
// TODO
/*
packet_hashlist_path = Reticulum::storagepath + "/packet_hashlist";
if (!owner.is_connected_to_shared_instance()) {
@ -106,21 +110,24 @@ using namespace RNS::Utilities;
}
}
}
*/
// Create transport-specific destinations
Transport.path_request_destination = RNS.Destination(None, RNS.Destination.IN, RNS.Destination.PLAIN, Transport.APP_NAME, "path", "request")
Transport.path_request_destination.set_packet_callback(Transport.path_request_handler)
Transport.control_destinations.append(Transport.path_request_destination)
Transport.control_hashes.append(Transport.path_request_destination.hash)
Destination path_request_destination({Type::NONE}, Type::Destination::IN, Type::Destination::PLAIN, APP_NAME, "path.request");
path_request_destination.set_packet_callback(path_request_handler);
_control_destinations.insert(path_request_destination);
_control_hashes.insert(path_request_destination.hash());
Transport.tunnel_synthesize_destination = RNS.Destination(None, RNS.Destination.IN, RNS.Destination.PLAIN, Transport.APP_NAME, "tunnel", "synthesize")
Transport.tunnel_synthesize_destination.set_packet_callback(Transport.tunnel_synthesize_handler)
Transport.control_destinations.append(Transport.tunnel_synthesize_handler)
Transport.control_hashes.append(Transport.tunnel_synthesize_destination.hash)
*/
Destination tunnel_synthesize_destination({Type::NONE}, Type::Destination::IN, Type::Destination::PLAIN, APP_NAME, "tunnel.synthesize");
tunnel_synthesize_destination.set_packet_callback(tunnel_synthesize_handler);
// CBA BUG?
//p Transport.control_destinations.append(Transport.tunnel_synthesize_handler)
_control_destinations.insert(tunnel_synthesize_destination);
_control_hashes.insert(tunnel_synthesize_destination.hash());
_jobs_running = false;
// TODO
/*
thread = threading.Thread(target=Transport.jobloop, daemon=True)
thread.start()
@ -256,6 +263,7 @@ using namespace RNS::Utilities;
_jobs_running = true;
try {
// TODO
/*
if (!Transport.jobs_locked) {
@ -586,6 +594,7 @@ using namespace RNS::Utilities;
try {
//if hasattr(interface, "ifac_identity") and interface.ifac_identity != None:
if (interface.ifac_identity()) {
// TODO
/*
// Calculate packet access code
ifac = interface.ifac_identity.sign(raw)[-interface.ifac_size:]
@ -816,7 +825,7 @@ using namespace RNS::Utilities;
// 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});
//Destination local_destination({Type::Destination::NONE});
bool found_local = false;
for (auto& destination : _destinations) {
if (destination.hash() == packet.destination_hash()) {
@ -859,6 +868,7 @@ using namespace RNS::Utilities;
// TODO: Rethink whether this is actually optimal.
if (packet.hops() > 0) {
// TODO
/*
if not hasattr(interface, "announce_cap"):
interface.announce_cap = RNS.Reticulum.ANNOUNCE_CAP
@ -1089,6 +1099,7 @@ using namespace RNS::Utilities;
/*static*/ void Transport::inbound(const Bytes& raw, const Interface& interface /*= {Type::NONE}*/) {
extreme("Transport::inbound()");
// TODO
/*
// If interface access codes are enabled,
// we must authenticate each packet.
@ -1179,6 +1190,7 @@ using namespace RNS::Utilities;
packet.receiving_interface(interface);
packet.hops(packet.hops() + 1);
// TODO
/*
if (interface) {
if hasattr(interface, "r_stat_rssi"):
@ -1517,6 +1529,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
// CBA TODO determine why packet desitnation hash is being searched in destinations again since we entered this logic becuase it did not exist above
//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;
@ -1531,11 +1544,10 @@ using namespace RNS::Utilities;
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(Type::Identity::KEYSIZE/8 + Type::Identity::NAME_HASH_LENGTH/8, 10);
Bytes random_blob = packet.data().mid(Type::Identity::KEYSIZE/8 + Type::Identity::NAME_HASH_LENGTH/8, Type::Identity::RANDOM_HASH_LENGTH/8);
//p random_blobs = []
std::set<Bytes> empty_random_blobs;
std::set<Bytes>& random_blobs = empty_random_blobs;
@ -1573,6 +1585,7 @@ using namespace RNS::Utilities;
uint64_t path_announce_emitted = 0;
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"))
// CBA TODO
//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;
@ -1617,6 +1630,7 @@ using namespace RNS::Utilities;
bool rate_blocked = false;
// TODO
/*
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:
@ -1658,7 +1672,7 @@ using namespace RNS::Utilities;
bool block_rebroadcasts = false;
Interface attached_interface = {Type::NONE};
uint64_t retransmit_timeout = now + (RNS::Cryptography::random() * PATHFINDER_RW);
uint64_t retransmit_timeout = now + (Cryptography::random() * PATHFINDER_RW);
uint64_t expires;
if (packet.receiving_interface().mode() == Type::Interface::MODE_ACCESS_POINT) {
@ -1823,7 +1837,10 @@ using namespace RNS::Utilities;
_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());
extreme("Transport::inbound: Destination " + packet.destination_hash().toHex() + " has data: " + packet.data().toHex());
//extreme("Transport::inbound: Destination " + packet.destination_hash().toHex() + " has text: " + packet.data().toString());
// TODO
/*
// If the receiving interface is a tunnel, we add the
// announce to the tunnels table
@ -1840,7 +1857,9 @@ using namespace RNS::Utilities;
// Call externally registered callbacks from apps
// wanting to know when an announce arrives
if (packet.context() != Type::Packet::PATH_RESPONSE) {
extreme("Transport::inbound: Not path response, sending to announce handler...");
for (auto& handler : _announce_handlers) {
extreme("Transport::inbound: Checking filter of announce handler...");
try {
// Check that the announced destination matches
// the handlers aspect filter
@ -1912,6 +1931,7 @@ using namespace RNS::Utilities;
else if (packet.packet_type() == Type::Packet::DATA) {
extreme("Transport::inbound: Packet is DATA");
if (packet.destination_type() == Type::Destination::LINK) {
extreme("Transport::inbound: Packet is for LINK");
for (auto& link : _active_links) {
if (link.link_id() == packet.destination_hash()) {
packet.link(link);
@ -1926,8 +1946,10 @@ using namespace RNS::Utilities;
#elif defined(DESTINATIONS_MAP)
auto iter = _destinations.find(packet.destination_hash());
if (iter != _destinations.end()) {
debug("Transport::inbound: Packet destination " + packet.destination_hash().toHex() + " found");
auto& destination = (*iter).second;
if (destination.type() == packet.destination_type()) {
debug("Transport::inbound: Packet destination type " + std::to_string(packet.destination_type()) + " matched, processing");
#endif
packet.destination(destination);
#if defined(DESTINATIONS_SET)
@ -1952,6 +1974,12 @@ using namespace RNS::Utilities;
}
}
}
else {
debug("Transport::inbound: Packet destination type " + std::to_string(packet.destination_type()) + " mismatch, ignoring");
}
}
else {
debug("Transport::inbound: Packet destination " + packet.destination_hash().toHex() + " not found, ignoring");
}
}
}
@ -1959,6 +1987,7 @@ using namespace RNS::Utilities;
// Handling for proofs and link-request proofs
else if (packet.packet_type() == Type::Packet::PROOF) {
extreme("Transport::inbound: Packet is PROOF");
// TODO
/*
if packet.context == RNS.Packet.LRPROOF:
// This is a link request proof, check if it
@ -2050,6 +2079,7 @@ using namespace RNS::Utilities;
}
/*static*/ void Transport::synthesize_tunnel(const Interface& interface) {
// TODO
/*
Bytes interface_hash = interface.get_hash();
Bytes public_key = _identity.get_public_key();
@ -2073,6 +2103,7 @@ using namespace RNS::Utilities;
}
/*static*/ void Transport::tunnel_synthesize_handler(const Bytes& data, const Packet& packet) {
// TODO
/*
try:
expected_length = RNS.Identity.KEYSIZE//8+RNS.Identity.HASHLENGTH//8+RNS.Reticulum.TRUNCATED_HASHLENGTH//8+RNS.Identity.SIGLENGTH//8
@ -2099,6 +2130,7 @@ using namespace RNS::Utilities;
}
/*static*/ void Transport::handle_tunnel(const Bytes& tunnel_id, const Interface& interface) {
// TODO
/*
expires = time.time() + Transport.DESTINATION_TIMEOUT
if not tunnel_id in Transport.tunnels:
@ -2191,20 +2223,21 @@ using namespace RNS::Utilities;
#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());
extreme("Transport::deregister_interface: Found and removed interface " + (*iter).second.toString());
_interfaces.erase(iter);
}
#endif
}
/*static*/ void Transport::register_destination(Destination& destination) {
extreme("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
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.")
//p raise KeyError("Attempt to register an already registered destination.")
throw std::runtime_error("Attempt to register an already registered destination.");
}
}
@ -2213,19 +2246,29 @@ using namespace RNS::Utilities;
#elif defined(DESTINATIONS_MAP)
auto iter = _destinations.find(destination.hash());
if (iter != _destinations.end()) {
//raise KeyError("Attempt to register an already registered destination.")
//p 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 && _owner.is_connected_to_shared_instance()) {
if (destination.type() == Type::Destination::SINGLE) {
extreme("Transport:register_destination: Announcing destination " + destination.toString());
destination.announce({}, true);
}
}
}
#if defined(DESTINATIONS_SET)
for (const Destination& destination : _destinations) {
#elif defined(DESTINATIONS_MAP)
for (auto& [hash, destination] : _destinations) {
#endif
extreme("Transport::register_destination: Listed destination " + destination.toString());
}
extreme("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
}
/*static*/ void Transport::deregister_destination(const Destination& destination) {
@ -2233,16 +2276,19 @@ using namespace RNS::Utilities;
#if defined(DESTINATIONS_SET)
if (_destinations.find(destination) != _destinations.end()) {
_destinations.erase(destination);
extreme("Transport::deregister_destination: Found and removed destination " + destination.toString());
}
#elif defined(DESTINATIONS_MAP)
auto iter = _destinations.find(destination.hash());
if (iter != _destinations.end()) {
_destinations.erase(iter);
extreme("Transport::deregister_destination: Found and removed destination " + (*iter).second.toString());
}
#endif
}
/*static*/ void Transport::register_link(const Link& link) {
// TODO
/*
extreme("Transport: Registering link " + link.toString());
if (link.initiator()) {
@ -2255,6 +2301,7 @@ using namespace RNS::Utilities;
}
/*static*/ void Transport::activate_link(Link& link) {
// TODO
/*
extreme("Transport: Activating link " + link.toString());
if (_pending_links.find(link) != _pending_links.end()) {
@ -2298,18 +2345,21 @@ Deregisters an announce handler.
#if defined(INTERFACES_SET)
for (const Interface& interface : _interfaces) {
if (interface.get_hash() == interface_hash) {
extreme("Transport::find_interface_from_hash: Found interface " + interface.toString());
return interface;
}
}
#elif defined(INTERFACES_LIST)
for (Interface& interface : _interfaces) {
if (interface.get_hash() == interface_hash) {
extreme("Transport::find_interface_from_hash: Found interface " + interface.toString());
return interface;
}
}
#elif defined(INTERFACES_MAP)
auto iter = _interfaces.find(interface_hash);
if (iter != _interfaces.end()) {
extreme("Transport::find_interface_from_hash: Found interface " + (*iter).second.toString());
return (*iter).second;
}
#endif
@ -2333,6 +2383,7 @@ Deregisters an announce handler.
// increased yet! Take note of this when reading from
// the packet cache.
/*static*/ void Transport::cache(const Packet& packet, bool force_cache /*= false*/) {
// TODO
/*
if (should_cache(packet) || force_cache) {
try {
@ -2356,6 +2407,7 @@ Deregisters an announce handler.
}
/*static*/ Packet Transport::get_cached_packet(const Bytes& packet_hash) {
// TODO
/*
try {
//packet_hash = RNS.hexrep(packet_hash, delimit=False)
@ -2504,21 +2556,28 @@ will announce it.
*/
///*static*/ void Transport::request_path(const Bytes& destination_hash, const Interface& on_interface /*= {Type::NONE}*/, const Bytes& tag /*= {}*/, bool recursive /*= false*/) {
/*static*/ void Transport::request_path(const Bytes& destination_hash, const Interface& on_interface, const Bytes& tag /*= {}*/, bool recursive /*= false*/) {
Bytes request_tag;
if (tag) {
request_tag = Identity::get_random_hash();
}
else {
request_tag = tag;
}
Bytes path_request_data;
if (Reticulum::transport_enabled()) {
path_request_data = destination_hash + _identity.hash() + request_tag;
}
else {
path_request_data = destination_hash + request_tag;
}
Destination path_request_dst({Type::NONE}, Type::Destination::OUT, Type::Destination::PLAIN, Type::Transport::APP_NAME, "path.request");
Packet packet(path_request_dst, on_interface, path_request_data, Type::Packet::DATA, Type::Packet::CONTEXT_NONE, Type::Transport::BROADCAST, Type::Packet::HEADER_1);
if (on_interface && recursive) {
// TODO
/*
if tag == None:
request_tag = RNS.Identity.get_random_hash()
else:
request_tag = tag
if RNS.Reticulum.transport_enabled():
path_request_data = destination_hash+Transport.identity.hash+request_tag
else:
path_request_data = destination_hash+request_tag
path_request_dst = RNS.Destination(None, RNS.Destination.OUT, RNS.Destination.PLAIN, Transport.APP_NAME, "path", "request")
packet = RNS.Packet(path_request_dst, path_request_data, packet_type = RNS.Packet.DATA, transport_type = RNS.Transport.BROADCAST, header_type = RNS.Packet.HEADER_1, attached_interface = on_interface)
if on_interface != None and recursive:
if not hasattr(on_interface, "announce_cap"):
on_interface.announce_cap = RNS.Reticulum.ANNOUNCE_CAP
@ -2527,24 +2586,30 @@ will announce it.
if not hasattr(on_interface, "announce_queue"):
on_interface.announce_queue = []
queued_announces = True if len(on_interface.announce_queue) > 0 else False
if queued_announces:
RNS.log("Blocking recursive path request on "+str(on_interface)+" due to queued announces", RNS.LOG_EXTREME)
return
else:
now = time.time()
if now < on_interface.announce_allowed_at:
RNS.log("Blocking recursive path request on "+str(on_interface)+" due to active announce cap", RNS.LOG_EXTREME)
return
else:
tx_time = ((len(path_request_data)+RNS.Reticulum.HEADER_MINSIZE)*8) / on_interface.bitrate
wait_time = (tx_time / on_interface.announce_cap)
on_interface.announce_allowed_at = now + wait_time
packet.send()
Transport.path_requests[destination_hash] = time.time()
*/
bool queued_announces = (on_interface.announce_queue().size() > 0);
if (queued_announces) {
extreme("Blocking recursive path request on " + on_interface.toString() + " due to queued announces");
return;
}
else {
uint64_t now = OS::time();
if (now < on_interface.announce_allowed_at()) {
extreme("Blocking recursive path request on " + on_interface.toString() + " due to active announce cap");
return;
}
else {
//p tx_time = ((len(path_request_data)+RNS.Reticulum.HEADER_MINSIZE)*8) / on_interface.bitrate
uint32_t tx_time = ((path_request_data.size() + Type::Reticulum::HEADER_MINSIZE)*8) / on_interface.bitrate();
uint32_t wait_time = (tx_time / on_interface.announce_cap());
const_cast<Interface&>(on_interface).announce_allowed_at(now + wait_time);
}
}
}
packet.send();
_path_requests[destination_hash] = OS::time();
}
/*static*/ void Transport::request_path(const Bytes& destination_hash) {
@ -2552,80 +2617,98 @@ will announce it.
}
/*static*/ void Transport::path_request_handler(const Bytes& data, const Packet& packet) {
/*
try:
extreme("Transport::path_request_handler");
try {
// If there is at least bytes enough for a destination
// hash in the packet, we assume those bytes are the
// destination being requested.
if len(data) >= RNS.Identity.TRUNCATED_HASHLENGTH//8:
destination_hash = data[:RNS.Identity.TRUNCATED_HASHLENGTH//8]
if (data.size() >= Type::Identity::TRUNCATED_HASHLENGTH/8) {
Bytes destination_hash = data.left(Type::Identity::TRUNCATED_HASHLENGTH/8);
extreme("Transport::path_request_handler: destination_hash: " + destination_hash.toHex());
// If there is also enough bytes for a transport
// instance ID and at least one tag byte, we
// assume the next bytes to be the trasport ID
// of the requesting transport instance.
if len(data) > (RNS.Identity.TRUNCATED_HASHLENGTH//8)*2:
requesting_transport_instance = data[RNS.Identity.TRUNCATED_HASHLENGTH//8:(RNS.Identity.TRUNCATED_HASHLENGTH//8)*2]
else:
requesting_transport_instance = None
Bytes requesting_transport_instance;
if (data.size() > (Type::Identity::TRUNCATED_HASHLENGTH/8)*2) {
requesting_transport_instance = data.mid(Type::Identity::TRUNCATED_HASHLENGTH/8, Type::Identity::TRUNCATED_HASHLENGTH/8);
extreme("Transport::path_request_handler: requesting_transport_instance: " + requesting_transport_instance.toHex());
}
tag_bytes = None
if len(data) > (RNS.Identity.TRUNCATED_HASHLENGTH//8)*2:
tag_bytes = data[RNS.Identity.TRUNCATED_HASHLENGTH//8*2:]
Bytes tag_bytes;
if (data.size() > Type::Identity::TRUNCATED_HASHLENGTH/8*2) {
tag_bytes = data.mid(Type::Identity::TRUNCATED_HASHLENGTH/8*2);
}
else if (data.size() > Type::Identity::TRUNCATED_HASHLENGTH/8) {
tag_bytes = data.mid(Type::Identity::TRUNCATED_HASHLENGTH/8);
}
elif len(data) > (RNS.Identity.TRUNCATED_HASHLENGTH//8):
tag_bytes = data[RNS.Identity.TRUNCATED_HASHLENGTH//8:]
if (tag_bytes) {
extreme("Transport::path_request_handler: tag_bytes: " + tag_bytes.toHex());
if (tag_bytes.size() > Type::Identity::TRUNCATED_HASHLENGTH/8) {
tag_bytes = tag_bytes.left(Type::Identity::TRUNCATED_HASHLENGTH/8);
}
if tag_bytes != None:
if len(tag_bytes) > RNS.Identity.TRUNCATED_HASHLENGTH//8:
tag_bytes = tag_bytes[:RNS.Identity.TRUNCATED_HASHLENGTH//8]
Bytes unique_tag = destination_hash + tag_bytes;
extreme("Transport::path_request_handler: unique_tag: " + unique_tag.toHex());
unique_tag = destination_hash+tag_bytes
if (_discovery_pr_tags.find(unique_tag) == _discovery_pr_tags.end()) {
_discovery_pr_tags.insert(unique_tag);
if not unique_tag in Transport.discovery_pr_tags:
Transport.discovery_pr_tags.append(unique_tag)
Transport.path_request(
path_request(
destination_hash,
Transport.from_local_client(packet),
packet.receiving_interface,
requestor_transport_id = requesting_transport_instance,
tag=tag_bytes
)
else:
RNS.log("Ignoring duplicate path request for "+RNS.prettyhexrep(destination_hash)+" with tag "+RNS.prettyhexrep(unique_tag), RNS.LOG_DEBUG)
else:
RNS.log("Ignoring tagless path request for "+RNS.prettyhexrep(destination_hash), RNS.LOG_DEBUG)
except Exception as e:
RNS.log("Error while handling path request. The contained exception was: "+str(e), RNS.LOG_ERROR)
*/
from_local_client(packet),
packet.receiving_interface(),
requesting_transport_instance,
tag_bytes
);
}
else {
debug("Ignoring duplicate path request for " + destination_hash.toHex() + " with tag " + unique_tag.toHex());
}
}
else {
debug("Ignoring tagless path request for " + destination_hash.toHex());
}
}
}
catch (std::exception& e) {
error("Error while handling path request. The contained exception was: " + std::string(e.what()));
}
}
/*static*/ void Transport::path_request(const Bytes& destination_hash, bool is_from_local_client, const Interface& attached_interface, const Bytes& requestor_transport_id /*= {}*/, const Bytes& tag /*= {}*/) {
/*
should_search_for_unknown = False
extreme("Transport::path_request");
bool should_search_for_unknown = false;
std::string interface_str;
if attached_interface != None:
if RNS.Reticulum.transport_enabled() and attached_interface.mode in RNS.Interfaces.Interface.Interface.DISCOVER_PATHS_FOR:
should_search_for_unknown = True
if (attached_interface) {
if (Reticulum::transport_enabled() && (attached_interface.mode() & Interface::DISCOVER_PATHS_FOR) > 0) {
should_search_for_unknown = true;
}
interface_str = " on "+str(attached_interface)
else:
interface_str = ""
interface_str = " on " + attached_interface.toString();
}
RNS.log("Path request for "+RNS.prettyhexrep(destination_hash)+interface_str, RNS.LOG_DEBUG)
debug("Path request for destination " + destination_hash.toHex() + interface_str);
destination_exists_on_local_client = False
if len(Transport.local_client_interfaces) > 0:
if destination_hash in Transport.destination_table:
destination_interface = Transport.destination_table[destination_hash][5]
if Transport.is_local_client_interface(destination_interface):
destination_exists_on_local_client = True
Transport.pending_local_path_requests[destination_hash] = attached_interface
bool destination_exists_on_local_client = false;
if (_local_client_interfaces.size() > 0) {
auto iter = _destination_table.find(destination_hash);
if (iter != _destination_table.end()) {
extreme("Transport::path_request_handler: entry found for destination " + destination_hash.toHex());
DestinationEntry& destination_entry = (*iter).second;
if (is_local_client_interface(destination_entry._receiving_interface)) {
destination_exists_on_local_client = true;
_pending_local_path_requests.insert({destination_hash, attached_interface});
}
}
else {
extreme("Transport::path_request_handler: entry not found for destination " + destination_hash.toHex());
}
}
auto destination_iter = _destination_table.find(destination_hash);
//local_destination = next((d for d in Transport.destinations if d.hash == destination_hash), None)
#if defined(DESTINATIONS_SET)
Destination local_destination({Type::NONE});
@ -2642,40 +2725,46 @@ will announce it.
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");
local_destination.announce({Bytes::NONE}, true, attached_interface, tag);
debug("Answering path request for destination " + 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()) {
packet = Transport.destination_table[destination_hash][6]
next_hop = Transport.destination_table[destination_hash][1]
received_from = Transport.destination_table[destination_hash][5]
//p elif (RNS.Reticulum.transport_enabled() or is_from_local_client) and (destination_hash in Transport.destination_table):
else if ((Reticulum::transport_enabled() || is_from_local_client) && destination_iter != _destination_table.end()) {
DestinationEntry& destination_entry = (*destination_iter).second;
const Packet& packet = destination_entry._announce_packet;
const Bytes& next_hop = destination_entry._received_from;
const Interface& received_from = destination_entry._receiving_interface;
if attached_interface.mode == RNS.Interfaces.Interface.Interface.MODE_ROAMING and attached_interface == received_from:
RNS.log("Not answering path request on roaming-mode interface, since next hop is on same roaming-mode interface", RNS.LOG_DEBUG)
else:
if requestor_transport_id != None and next_hop == requestor_transport_id:
if (attached_interface.mode() == Type::Interface::MODE_ROAMING && attached_interface == destination_entry._receiving_interface) {
debug("Not answering path request on roaming-mode interface, since next hop is on same roaming-mode interface");
}
else {
if (requestor_transport_id && destination_entry._received_from == requestor_transport_id) {
// TODO: Find a bandwidth efficient way to invalidate our
// known path on this signal. The obvious way of signing
// path requests with transport instance keys is quite
// inefficient. There is probably a better way. Doing
// path invalidation here would decrease the network
// convergence time. Maybe just drop it?
RNS.log("Not answering path request for "+RNS.prettyhexrep(destination_hash)+interface_str+", since next hop is the requestor", RNS.LOG_DEBUG)
else:
RNS.log("Answering path request for "+RNS.prettyhexrep(destination_hash)+interface_str+", path is known", RNS.LOG_DEBUG)
debug("Not answering path request for destination " + destination_hash.toHex() + interface_str + ", since next hop is the requestor");
}
else {
debug("Answering path request for destination " + destination_hash.toHex() + interface_str + ", path is known");
now = time.time()
retries = Transport.PATHFINDER_R
local_rebroadcasts = 0
block_rebroadcasts = True
announce_hops = packet.hops
uint64_t now = OS::time();
uint8_t retries = Type::Transport::PATHFINDER_R;
uint8_t local_rebroadcasts = 0;
bool block_rebroadcasts = true;
uint8_t announce_hops = destination_entry._announce_packet.hops();
if is_from_local_client:
retransmit_timeout = now
else:
uint64_t retransmit_timeout = 0;
if (is_from_local_client) {
retransmit_timeout = now;
}
else {
// TODO: Look at this timing
retransmit_timeout = now + Transport.PATH_REQUEST_GRACE // + (RNS.rand() * Transport.PATHFINDER_RW)
retransmit_timeout = now + Type::Transport::PATH_REQUEST_GRACE /*+ (RNS.rand() * Transport.PATHFINDER_RW)*/;
}
// This handles an edge case where a peer sends a past
// request for a destination just after an announce for
@ -2683,86 +2772,123 @@ will announce it.
// rebroadcast locally. In such a case the actual announce
// is temporarily held, and then reinserted when the path
// request has been served to the peer.
if packet.destination_hash in Transport.announce_table:
held_entry = Transport.announce_table[packet.destination_hash]
Transport.held_announces[packet.destination_hash] = held_entry
auto announce_iter = _announce_table.find(destination_entry._announce_packet.destination_hash());
if (announce_iter != _announce_table.end()) {
AnnounceEntry& held_entry = (*announce_iter).second;
_held_announces.insert({destination_entry._announce_packet.destination_hash(), held_entry});
}
Transport.announce_table[packet.destination_hash] = [now, retransmit_timeout, retries, received_from, announce_hops, packet, local_rebroadcasts, block_rebroadcasts, attached_interface]
elif is_from_local_client:
_announce_table.insert({destination_entry._announce_packet.destination_hash(), {
now,
retransmit_timeout,
retries,
// BUG?
//destination_entry.receiving_interface,
destination_entry._received_from,
announce_hops,
destination_entry._announce_packet,
local_rebroadcasts,
block_rebroadcasts,
attached_interface
}});
}
}
}
else if (is_from_local_client) {
// Forward path request on all interfaces
// except the local client
RNS.log("Forwarding path request from local client for "+RNS.prettyhexrep(destination_hash)+interface_str+" to all other interfaces", RNS.LOG_DEBUG)
request_tag = RNS.Identity.get_random_hash()
for interface in Transport.interfaces:
if not interface == attached_interface:
Transport.request_path(destination_hash, interface, tag = request_tag)
elif should_search_for_unknown:
if destination_hash in Transport.discovery_path_requests:
RNS.log("There is already a waiting path request for "+RNS.prettyhexrep(destination_hash)+" on behalf of path request"+interface_str, RNS.LOG_DEBUG)
else:
debug("Forwarding path request from local client for destination " + destination_hash.toHex() + interface_str + " to all other interfaces");
Bytes request_tag = Identity::get_random_hash();
#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 != attached_interface) {
request_path(destination_hash, interface, request_tag);
}
}
}
else if (should_search_for_unknown) {
if (_discovery_path_requests.find(destination_hash) != _discovery_path_requests.end()) {
debug("There is already a waiting path request for destination " + destination_hash.toHex() + " on behalf of path request " + interface_str);
}
else {
// Forward path request on all interfaces
// except the requestor interface
RNS.log("Attempting to discover unknown path to "+RNS.prettyhexrep(destination_hash)+" on behalf of path request"+interface_str, RNS.LOG_DEBUG)
pr_entry = { "destination_hash": destination_hash, "timeout": time.time()+Transport.PATH_REQUEST_TIMEOUT, "requesting_interface": attached_interface }
Transport.discovery_path_requests[destination_hash] = pr_entry
debug("Attempting to discover unknown path to destination " + destination_hash.toHex() + " on behalf of path request " + interface_str);
//p pr_entry = { "destination_hash": destination_hash, "timeout": time.time()+Transport.PATH_REQUEST_TIMEOUT, "requesting_interface": attached_interface }
//p _discovery_path_requests[destination_hash] = pr_entry;
_discovery_path_requests.insert({destination_hash, {
destination_hash,
OS::time() + Type::Transport::PATH_REQUEST_TIMEOUT,
attached_interface
}});
for interface in Transport.interfaces:
if not interface == attached_interface:
#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 != attached_interface) {
// Use the previously extracted tag from this path request
// on the new path requests as well, to avoid potential loops
Transport.request_path(destination_hash, on_interface=interface, tag=tag, recursive=True)
elif not is_from_local_client and len(Transport.local_client_interfaces) > 0:
request_path(destination_hash, interface, tag, true);
}
}
}
}
else if (!is_from_local_client && _local_client_interfaces.size() > 0) {
// Forward the path request on all local
// client interfaces
RNS.log("Forwarding path request for "+RNS.prettyhexrep(destination_hash)+interface_str+" to local clients", RNS.LOG_DEBUG)
for interface in Transport.local_client_interfaces:
Transport.request_path(destination_hash, on_interface=interface)
else:
RNS.log("Ignoring path request for "+RNS.prettyhexrep(destination_hash)+interface_str+", no path known", RNS.LOG_DEBUG)
*/
debug("Forwarding path request for destination " + destination_hash.toHex() + interface_str + " to local clients");
for (const Interface& interface : _local_client_interfaces) {
request_path(destination_hash, interface);
}
}
else {
debug("Ignoring path request for destination " + destination_hash.toHex() + interface_str + ", no path known");
}
}
/*static*/ bool Transport::from_local_client(const Packet& packet) {
/*
if hasattr(packet.receiving_interface, "parent_interface"):
return Transport.is_local_client_interface(packet.receiving_interface)
else:
return False
*/
// MOCK
if (packet.receiving_interface().parent_interface()) {
return is_local_client_interface(packet.receiving_interface());
}
else {
return false;
}
}
/*static*/ bool Transport::is_local_client_interface(const Interface& interface) {
/*
if hasattr(interface, "parent_interface"):
if hasattr(interface.parent_interface, "is_local_shared_instance"):
return True
else:
return False
else:
return False
*/
// MOCK
if (interface.parent_interface()) {
if (interface.parent_interface()->is_local_shared_instance()) {
return true;
}
else {
return false;
}
}
else {
return false;
}
}
/*static*/ bool Transport::interface_to_shared_instance(const Interface& interface) {
/*
if hasattr(interface, "is_connected_to_shared_instance"):
return True
else:
return False
*/
// MOCK
if (interface.is_connected_to_shared_instance()) {
return true;
}
else {
return false;
}
}
/*static*/ void Transport::detach_interfaces() {
// TODO
/*
detachable_interfaces = []
@ -2790,6 +2916,7 @@ will announce it.
}
/*static*/ void Transport::shared_connection_disappeared() {
// TODO
/*
for link in Transport.active_links:
link.teardown()
@ -2808,6 +2935,7 @@ will announce it.
}
/*static*/ void Transport::shared_connection_reappeared() {
// TODO
/*
if Transport.owner.is_connected_to_shared_instance:
for registered_destination in Transport.destinations:
@ -2817,6 +2945,7 @@ will announce it.
}
/*static*/ void Transport::drop_announce_queues() {
// TODO
/*
for interface in Transport.interfaces:
if hasattr(interface, "announce_queue") and interface.announce_queue != None:
@ -2833,6 +2962,7 @@ will announce it.
}
/*static*/ bool Transport::announce_emitted(const Packet& packet) {
// TODO
/*
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]
announce_emitted = int.from_bytes(random_blob[5:10], "big")
@ -2844,6 +2974,7 @@ will announce it.
}
/*static*/ void Transport::save_packet_hashlist() {
// TODO
/*
if not Transport.owner.is_connected_to_shared_instance:
if hasattr(Transport, "saving_packet_hashlist"):
@ -2885,6 +3016,7 @@ will announce it.
}
/*static*/ void Transport::save_path_table() {
// TODO
/*
if not Transport.owner.is_connected_to_shared_instance:
if hasattr(Transport, "saving_path_table"):
@ -2956,6 +3088,7 @@ will announce it.
}
/*static*/ void Transport::save_tunnel_table() {
// TODO
/*
if not Transport.owner.is_connected_to_shared_instance:
if hasattr(Transport, "saving_tunnel_table"):
@ -3047,15 +3180,18 @@ will announce it.
}
/*static*/ Destination Transport::find_destination_from_hash(const Bytes& destination_hash) {
extreme("Transport: Searching for destination " + destination_hash.toHex());
#if defined(DESTINATIONS_SET)
for (const Destination& destination : _destinations) {
if (destination.get_hash() == destination_hash) {
extreme("Transport::find_destination_from_hash: Found destination " + destination.toString());
return destination;
}
}
#elif defined(DESTINATIONS_MAP)
auto iter = _destinations.find(destination_hash);
if (iter != _destinations.end()) {
extreme("Transport::find_destination_from_hash: Found destination " + (*iter).second.toString());
return (*iter).second;
}
#endif

View File

@ -35,7 +35,7 @@ namespace RNS {
// 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; }
AnnounceHandler(const char* aspect_filter = nullptr) { if (aspect_filter != nullptr) _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,
@ -65,7 +65,7 @@ namespace RNS {
_expires(expires),
_random_blobs(random_blobs),
_receiving_interface(receiving_interface),
_packet(packet)
_announce_packet(packet)
{
}
public:
@ -75,14 +75,14 @@ namespace RNS {
uint64_t _expires = 0;
std::set<Bytes> _random_blobs;
Interface& _receiving_interface;
const Packet& _packet;
const Packet& _announce_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, const Bytes& received_from, uint8_t hops, const Packet& packet, uint8_t local_rebroadcasts, bool block_rebroadcasts, const Interface& attached_interface) :
AnnounceEntry(uint64_t timestamp, uint64_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),
@ -96,7 +96,7 @@ namespace RNS {
}
public:
uint64_t _timestamp = 0;
uint16_t _retransmit_timeout = 0;
uint64_t _retransmit_timeout = 0;
uint8_t _retries = 0;
Bytes _received_from;
uint8_t _hops = 0;
@ -251,10 +251,10 @@ namespace RNS {
static std::set<HAnnounceHandler> _announce_handlers; // A table storing externally registered announce handlers
//z _tunnels = {} // A table storing tunnels to other transport instances
//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::map<Bytes, uint64_t> _path_requests; // A table for storing path request timestamps
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 std::set<Bytes> _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
// Transport control destinations are used

View File

@ -95,6 +95,7 @@ namespace RNS { namespace Type {
static const uint16_t SIGLENGTH = KEYSIZE; // In bits
static const uint8_t NAME_HASH_LENGTH = 80;
static const uint8_t RANDOM_HASH_LENGTH = 80;
static const uint16_t TRUNCATED_HASHLENGTH = Reticulum::TRUNCATED_HASHLENGTH; // In bits
// Constant specifying the truncated hash length (in bits) used by Reticulum
// for addressable hashes and other purposes. Non-configurable.

View File

@ -14,9 +14,16 @@ namespace RNS { namespace Utilities {
// sleep for specified milliseconds
static inline void sleep(float seconds) { ::sleep(seconds); }
//static inline void sleep(uint32_t milliseconds) { ::sleep((float)milliseconds / 1000.0); }
// return current time in milliseconds since 00:00:00, January 1, 1970 (Unix Epoch)
static uint64_t time() { timeval time; ::gettimeofday(&time, NULL); return (uint64_t)(time.tv_sec * 1000) + (uint64_t)(time.tv_usec / 1000); }
static inline float round(float value, uint8_t precision) { return std::round(value / precision) * precision; }
// return current time in float seconds since 00:00:00, January 1, 1970 (Unix Epoch)
static double dtime() { timeval time; ::gettimeofday(&time, NULL); return (double)time.tv_sec + ((double)time.tv_usec / 1000000); }
// round decimal number to specified precision
//static inline float round(float value, uint8_t precision) { return std::round(value / precision) * precision; }
static inline double round(double value, uint8_t precision) { return std::round(value / precision) * precision; }
};

View File

@ -8,10 +8,13 @@
#include "Packet.h"
#include "Transport.h"
#include "Interface.h"
#include "Log.h"
#include "Bytes.h"
#include "Type.h"
#include "Interfaces/UDPInterface.h"
#include "Utilities/OS.h"
#ifndef NATIVE
#ifdef ARDUINO
#include <Arduino.h>
#endif
@ -23,6 +26,13 @@
#include <functional>
//#include <sstream>
#ifndef NDEBUG
//#define RUN_TESTS
#endif
#define RUN_RETICULUM
//#define RETICULUM_PACKET_TEST
// Let's define an app name. We'll use this for all
// destinations we create. Since this basic example
// is part of a range of example utilities, we'll put
@ -124,105 +134,111 @@ public:
// Test AnnounceHandler
class ExampleAnnounceHandler : public RNS::AnnounceHandler {
public:
ExampleAnnounceHandler(const char* aspect_filter) : AnnounceHandler(aspect_filter) {}
ExampleAnnounceHandler(const char* aspect_filter = nullptr) : AnnounceHandler(aspect_filter) {}
virtual ~ExampleAnnounceHandler() {}
virtual void received_announce(const RNS::Bytes& destination_hash, const RNS::Identity& announced_identity, const RNS::Bytes& app_data) {
RNS::info("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
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());
if (announced_identity) {
RNS::info("ExampleAnnounceHandler: announced identity hash: " + announced_identity.hash().toHex());
RNS::info("ExampleAnnounceHandler: announced identity app data: " + announced_identity.app_data().toHex());
}
RNS::info("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
if (app_data) {
RNS::info("ExampleAnnounceHandler: app data text: \"" + app_data.toString() + "\"");
}
RNS::info("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
}
};
// Test packet receive callback
void onPacket(const RNS::Bytes& data, const RNS::Packet& packet) {
RNS::info("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
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() {
#ifndef NATIVE
Serial.begin(115200);
Serial.print("Hello from T-Beam on PlatformIO!\n");
#if defined(RUN_RETICULUM)
RNS::Reticulum reticulum({RNS::Type::NONE});
//TestInterface interface;
TestOutInterface outinterface;
TestInInterface ininterface;
TestLoopbackInterface loopinterface(ininterface);
RNS::Interfaces::UDPInterface udpinterface;
//ExampleAnnounceHandler announce_handler((const char*)"example_utilities.announcesample.fruits");
//RNS::HAnnounceHandler announce_handler(new ExampleAnnounceHandler("example_utilities.announcesample.fruits"));
RNS::HAnnounceHandler announce_handler(new ExampleAnnounceHandler());
#endif
#if defined(RUN_TESTS)
void run_tests() {
try {
#ifndef NDEBUG
RNS::loglevel(RNS::LOG_WARNING);
//RNS::loglevel(RNS::LOG_EXTREME);
RNS::extreme("Running tests...");
RNS::LogLevel loglevel = RNS::loglevel();
//RNS::loglevel(RNS::LOG_WARNING);
RNS::loglevel(RNS::LOG_EXTREME);
test();
//testReference();
//testCrypto();
RNS::loglevel(loglevel);
RNS::extreme("Finished running tests");
//return;
}
catch (std::exception& e) {
RNS::error(std::string("!!! Exception in test: ") + e.what() + " !!!");
}
}
#endif
#if defined(RUN_RETICULUM)
void setup_reticulum() {
RNS::info("Setting up Reticulum...");
try {
//std::stringstream test;
// !!! just adding this single stringstream alone (not even using it) adds a whopping 17.1% !!!
// !!! JUST SAY NO TO STRINGSTREAM !!!
RNS::loglevel(RNS::LOG_EXTREME);
// 18.5% completely empty program
// 21.8% baseline here with serial
RNS::head("Creating Reticulum instance...", RNS::LOG_EXTREME);
RNS::Reticulum reticulum;
//RNS::Reticulum reticulum;
reticulum = RNS::Reticulum();
//return;
// 21.9% (+0.1%)
RNS::head("Creating Interface instances...", RNS::LOG_EXTREME);
//TestInterface interface;
TestOutInterface outinterface;
TestInInterface ininterface;
TestLoopbackInterface loopinterface(ininterface);
RNS::head("Registering Interface instances with Transport...", RNS::LOG_EXTREME);
//RNS::Transport::register_interface(interface);
RNS::Transport::register_interface(outinterface);
RNS::Transport::register_interface(ininterface);
RNS::Transport::register_interface(loopinterface);
RNS::Transport::register_interface(udpinterface);
RNS::head("Starting UDPInterface...", RNS::LOG_EXTREME);
udpinterface.start();
RNS::head("Creating Identity instance...", RNS::LOG_EXTREME);
RNS::Identity identity;
// 22.6% (+0.7%)
RNS::head("Creating Destination instance...", RNS::LOG_EXTREME);
RNS::Destination destination(identity, RNS::Type::Destination::IN, RNS::Type::Destination::SINGLE, "test", "context");
RNS::Destination destination(identity, RNS::Type::Destination::IN, RNS::Type::Destination::SINGLE, "app", "aspects");
// 23.0% (+0.4%)
/*
RNS::head("Testing map...", RNS::LOG_EXTREME);
{
std::map<RNS::Bytes, RNS::Destination&> destinations;
destinations.insert({destination.hash(), destination});
//for (RNS::Destination& destination : destinations) {
for (auto& [hash, destination] : destinations) {
RNS::extreme("Iterated destination: " + destination.toString());
}
RNS::Bytes hash = destination.hash();
auto iter = destinations.find(hash);
if (iter != destinations.end()) {
RNS::Destination& destination = (*iter).second;
RNS::extreme("Found destination: " + destination.toString());
}
return;
}
*/
destination.set_proof_strategy(RNS::Type::Destination::PROVE_ALL);
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);
@ -233,7 +249,7 @@ void setup() {
destination.announce(RNS::bytesFromString(fruits[rand() % 7]));
// 23.9% (+0.8%)
/*
#if defined (RETICULUM_PACKET_TEST)
// 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");
@ -253,12 +269,24 @@ void setup() {
RNS::head("Spoofing recv packet to destination...", RNS::LOG_EXTREME);
destination.receive(recv_packet);
*/
#endif
}
catch (std::exception& e) {
RNS::error(std::string("!!! Exception in setup_reticulum: ") + e.what() + " !!!");
}
}
void teardown_reticulum() {
RNS::info("Tearing down Reticulum...");
try {
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(udpinterface);
RNS::Transport::deregister_interface(loopinterface);
RNS::Transport::deregister_interface(ininterface);
RNS::Transport::deregister_interface(outinterface);
@ -266,97 +294,52 @@ void setup() {
}
catch (std::exception& e) {
RNS::error(std::string("!!! Exception in main: ") + e.what() + " !!!");
RNS::error(std::string("!!! Exception in teardown_reticulum: ") + e.what() + " !!!");
}
}
#endif
#ifndef NATIVE
void setup() {
#ifdef ARDUINO
Serial.begin(115200);
Serial.print("Hello from T-Beam on PlatformIO!\n");
#endif
RNS::loglevel(RNS::LOG_EXTREME);
/*
{
//RNS::Reticulum reticulum_test;
RNS::Destination destination_test({RNS::Type::NONE}, RNS::Type::Destination::IN, RNS::Type::Destination::SINGLE, "test", "test");
}
*/
#if defined(RUN_TESTS)
run_tests();
#endif
#if defined(RUN_RETICULUM)
setup_reticulum();
#endif
#ifdef ARDUINO
Serial.print("Goodbye from T-Beam on PlatformIO!\n");
#endif
}
void loop() {
#if defined(RUN_RETICULUM)
reticulum.loop();
udpinterface.loop();
#endif
}
int main(void) {
printf("Hello from Native on PlatformIO!\n");
/*
RNS::loglevel(RNS::LOG_EXTREME);
TestInterface testinterface;
std::set<std::reference_wrapper<RNS::Interface>, std::less<RNS::Interface>> interfaces;
interfaces.insert(testinterface);
for (auto iter = interfaces.begin(); iter != interfaces.end(); ++iter) {
RNS::Interface& interface = (*iter);
RNS::extreme("Found interface: " + interface.toString());
RNS::Bytes data;
const_cast<RNS::Interface&>(interface).processOutgoing(data);
}
return 0;
*/
/*
RNS::loglevel(RNS::LOG_EXTREME);
TestInterface testinterface;
std::set<std::reference_wrapper<RNS::Interface>, std::less<RNS::Interface>> interfaces;
interfaces.insert(testinterface);
for (auto& interface : interfaces) {
RNS::extreme("Found interface: " + interface.toString());
RNS::Bytes data;
const_cast<RNS::Interface&>(interface).processOutgoing(data);
}
return 0;
*/
/*
RNS::loglevel(RNS::LOG_EXTREME);
TestInterface testinterface;
std::list<std::reference_wrapper<RNS::Interface>> interfaces;
interfaces.push_back(testinterface);
for (auto iter = interfaces.begin(); iter != interfaces.end(); ++iter) {
RNS::Interface& interface = (*iter);
RNS::extreme("Found interface: " + interface.toString());
RNS::Bytes data;
const_cast<RNS::Interface&>(interface).processOutgoing(data);
}
return 0;
*/
/*
RNS::loglevel(RNS::LOG_EXTREME);
TestInterface testinterface;
std::list<std::reference_wrapper<RNS::Interface>> interfaces;
interfaces.push_back(testinterface);
//for (auto& interface : interfaces) {
for (RNS::Interface& interface : interfaces) {
RNS::extreme("Found interface: " + interface.toString());
RNS::Bytes data;
const_cast<RNS::Interface&>(interface).processOutgoing(data);
}
return 0;
*/
/*
std::list<std::reference_wrapper<RNS::Interface>> interfaces;
{
RNS::loglevel(RNS::LOG_EXTREME);
TestInterface testinterface;
interfaces.push_back(testinterface);
for (auto iter = interfaces.begin(); iter != interfaces.end(); ++iter) {
RNS::Interface& interface = (*iter);
RNS::extreme("1 Found interface: " + interface.toString());
RNS::Bytes data;
const_cast<RNS::Interface&>(interface).processOutgoing(data);
}
}
for (auto iter = interfaces.begin(); iter != interfaces.end(); ++iter) {
RNS::Interface& interface = (*iter);
RNS::extreme("2 Found interface: " + interface.toString());
RNS::Bytes data;
const_cast<RNS::Interface&>(interface).processOutgoing(data);
}
return 0;
*/
setup();
//while (true) {