From ea7b4603edd657e337b1078493bd7484c7dadd10 Mon Sep 17 00:00:00 2001 From: attermann Date: Sun, 26 Nov 2023 18:10:46 -0700 Subject: [PATCH] WIP: Added super basic UDP interface for testing Basic UDP interface enabled testing with RNS reference implementation. Added to basic Transport implementation. --- src/Bytes.h | 50 ++-- src/Cryptography/CBC.cpp | 8 +- src/Cryptography/CBC.h | 8 +- src/Cryptography/Fernet.cpp | 4 +- src/Destination.cpp | 61 ++-- src/Destination.h | 29 +- src/Identity.cpp | 261 ++++++++++------- src/Identity.h | 32 +- src/Interface.cpp | 2 + src/Interface.h | 37 ++- src/Interfaces/UDPInterface.cpp | 134 +++++++++ src/Interfaces/UDPInterface.h | 61 ++++ src/Link.cpp | 2 +- src/Link.h | 6 +- src/Log.cpp | 13 +- src/Log.h | 30 +- src/Packet.cpp | 6 +- src/Packet.h | 7 +- src/Reticulum.cpp | 29 +- src/Reticulum.h | 18 +- src/Test/Test.cpp | 13 +- src/Test/Test.h | 8 +- src/Test/TestBytes.cpp | 87 ++---- src/Test/TestCollections.cpp | 136 +++++++++ src/Test/TestCrypto.cpp | 13 +- src/Test/TestReference.cpp | 96 ++++++ src/Transport.cpp | 504 ++++++++++++++++++++------------ src/Transport.h | 14 +- src/Type.h | 1 + src/Utilities/OS.h | 9 +- src/main.cpp | 243 +++++++-------- 31 files changed, 1276 insertions(+), 646 deletions(-) create mode 100644 src/Interfaces/UDPInterface.cpp create mode 100644 src/Interfaces/UDPInterface.h create mode 100644 src/Test/TestCollections.cpp diff --git a/src/Bytes.h b/src/Bytes.h index 3e1d149..aa6fb0c 100644 --- a/src/Bytes.h +++ b/src/Bytes.h @@ -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) { + 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) { + 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)); } @@ -124,7 +124,7 @@ namespace RNS { _data->insert(_data->begin(), bytes._data->begin(), bytes._data->end()); #endif } - inline void assign(const uint8_t *chunk, size_t size) { + inline void assign(const uint8_t* chunk, size_t size) { // if assignment is empty then clear data and don't bother creating new if (chunk == nullptr || size <= 0) { _data = nullptr; @@ -142,7 +142,7 @@ namespace RNS { return; } newData(); - _data->insert(_data->begin(), (uint8_t *)string, (uint8_t *)string + strlen(string)); + _data->insert(_data->begin(), (uint8_t* )string, (uint8_t* )string + strlen(string)); } inline void assign(const std::string& string) { assign(string.c_str()); } void assignHex(const char* hex); @@ -155,7 +155,7 @@ namespace RNS { ownData(); _data->insert(_data->end(), bytes._data->begin(), bytes._data->end()); } - inline void append(const uint8_t *chunk, size_t size) { + inline void append(const uint8_t* chunk, size_t size) { // if append is empty then do nothing if (chunk == nullptr || size <= 0) { return; @@ -169,7 +169,7 @@ namespace RNS { return; } ownData(); - _data->insert(_data->end(), (uint8_t *)string, (uint8_t *)string + strlen(string)); + _data->insert(_data->end(), (uint8_t* )string, (uint8_t* )string + strlen(string)); } inline void append(const std::string& string) { append(string.c_str()); } inline void append(uint8_t byte) { @@ -187,7 +187,7 @@ namespace RNS { _data->resize(newsize); } - inline uint8_t *writable(size_t size) { + inline uint8_t* writable(size_t size) { newData(size); return _data->data(); } @@ -197,7 +197,7 @@ namespace RNS { inline size_t size() const { if (!_data) return 0; return _data->size(); } inline bool empty() const { if (!_data) return true; return _data->empty(); } inline size_t capacity() const { if (!_data) return 0; return _data->capacity(); } - inline const uint8_t *data() const { if (!_data) return nullptr; return _data->data(); } + inline const uint8_t* data() const { if (!_data) return nullptr; return _data->data(); } inline std::string toString() const { if (!_data) return ""; return {(const char*)data(), size()}; } std::string toHex(bool upper = true) const; @@ -236,10 +236,10 @@ namespace RNS { // following array function doesn't work without size since it's past as a pointer to the array sizeof() is of the pointer //inline Bytes bytesFromArray(const uint8_t arr[]) { return Bytes(arr, sizeof(arr)); } - //inline Bytes bytesFromChunk(const uint8_t *ptr, size_t len) { return Bytes(ptr, len); } - inline Bytes bytesFromChunk(const uint8_t *ptr, size_t len) { return {ptr, len}; } - //inline Bytes bytesFromString(const char *str) { return Bytes((uint8_t*)str, strlen(str)); } - inline Bytes bytesFromString(const char *str) { return {(uint8_t*)str, strlen(str)}; } + //inline Bytes bytesFromChunk(const uint8_t* ptr, size_t len) { return Bytes(ptr, len); } + inline Bytes bytesFromChunk(const uint8_t* ptr, size_t len) { return {ptr, len}; } + //inline Bytes bytesFromString(const char* str) { return Bytes((uint8_t*)str, strlen(str)); } + inline Bytes bytesFromString(const char* str) { return {(uint8_t*)str, strlen(str)}; } //z inline Bytes bytesFromInt(const int) { return {(uint8_t*)str, strlen(str)}; } inline std::string stringFromBytes(const Bytes& bytes) { return bytes.toString(); } diff --git a/src/Cryptography/CBC.cpp b/src/Cryptography/CBC.cpp index 8419e0e..99ea859 100644 --- a/src/Cryptography/CBC.cpp +++ b/src/Cryptography/CBC.cpp @@ -64,7 +64,7 @@ size_t CBCCommon::ivSize() const return 16; } -bool CBCCommon::setKey(const uint8_t *key, size_t len) +bool CBCCommon::setKey(const uint8_t* key, size_t len) { // Verify the cipher's block size, just in case. if (blockCipher->blockSize() != 16) @@ -74,7 +74,7 @@ bool CBCCommon::setKey(const uint8_t *key, size_t len) return blockCipher->setKey(key, len); } -bool CBCCommon::setIV(const uint8_t *iv, size_t len) +bool CBCCommon::setIV(const uint8_t* iv, size_t len) { if (len != 16) return false; @@ -83,7 +83,7 @@ bool CBCCommon::setIV(const uint8_t *iv, size_t len) return true; } -void CBCCommon::encrypt(uint8_t *output, const uint8_t *input, size_t len) +void CBCCommon::encrypt(uint8_t* output, const uint8_t* input, size_t len) { uint8_t posn; while (len >= 16) { @@ -96,7 +96,7 @@ void CBCCommon::encrypt(uint8_t *output, const uint8_t *input, size_t len) } } -void CBCCommon::decrypt(uint8_t *output, const uint8_t *input, size_t len) +void CBCCommon::decrypt(uint8_t* output, const uint8_t* input, size_t len) { uint8_t posn; while (len >= 16) { diff --git a/src/Cryptography/CBC.h b/src/Cryptography/CBC.h index 884568e..f42c82d 100644 --- a/src/Cryptography/CBC.h +++ b/src/Cryptography/CBC.h @@ -34,11 +34,11 @@ public: size_t keySize() const; size_t ivSize() const; - bool setKey(const uint8_t *key, size_t len); - bool setIV(const uint8_t *iv, size_t len); + bool setKey(const uint8_t* key, size_t len); + bool setIV(const uint8_t* iv, size_t len); - void encrypt(uint8_t *output, const uint8_t *input, size_t len); - void decrypt(uint8_t *output, const uint8_t *input, size_t len); + void encrypt(uint8_t* output, const uint8_t* input, size_t len); + void decrypt(uint8_t* output, const uint8_t* input, size_t len); void clear(); diff --git a/src/Cryptography/Fernet.cpp b/src/Cryptography/Fernet.cpp index 6dc57e1..089bca7 100644 --- a/src/Cryptography/Fernet.cpp +++ b/src/Cryptography/Fernet.cpp @@ -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) { diff --git a/src/Destination.cpp b/src/Destination.cpp index 3aaafd3..07aa4d6 100644 --- a/src/Destination.cpp +++ b/src/Destination.cpp @@ -12,8 +12,9 @@ using namespace RNS; using namespace RNS::Type::Destination; -Destination::Destination(const Identity& identity, const directions direction, const types type, const char* app_name, const char *aspects) : _object(new Object(identity)) { +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") - addr_hash_material << identity.hash(); +/*static*/ Bytes Destination::hash(const Identity& identity, 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)] + //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. */ @@ -97,7 +117,7 @@ Destination::Destination(const Identity& identity, const directions direction, c /* :returns: A string containing the full human-readable name of the destination, for an app_name and a number of aspects. */ -/*static*/ std::string Destination::expand_name(const Identity& identity, const char *app_name, const char *aspects) { +/*static*/ std::string Destination::expand_name(const Identity& identity, const char* app_name, const char* aspects) { if (strchr(app_name, '.') != nullptr) { throw std::invalid_argument("Dots can't be used in app names"); @@ -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()) { diff --git a/src/Destination.h b/src/Destination.h index 399181c..0103d77 100644 --- a/src/Destination.h +++ b/src/Destination.h @@ -40,7 +40,7 @@ namespace RNS { class Callbacks { public: using link_established = void(*)(const Link& link); - //using packet = void(*)(uint8_t *data, uint16_t data_len, Packet *packet); + //using packet = void(*)(uint8_t* data, uint16_t data_len, Packet *packet); using packet = void(*)(const Bytes& data, const Packet& packet); using proof_requested = bool(*)(const Packet& packet); public: @@ -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 { @@ -79,8 +83,9 @@ 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 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; diff --git a/src/Identity.cpp b/src/Identity.cpp index 378cea8..8be1656 100644 --- a/src/Identity.cpp +++ b/src/Identity.cpp @@ -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 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` instance that can be used to create an outgoing :ref:`RNS.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 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,29 +352,34 @@ 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 - return true; + + 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; } /* @@ -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; } diff --git a/src/Identity.h b/src/Identity.h index 5ecaac5..19abbe4 100644 --- a/src/Identity.h +++ b/src/Identity.h @@ -36,21 +36,25 @@ namespace RNS { Bytes _app_data; }; + public: + static std::map _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; - static std::map _known_destinations; - }; } \ No newline at end of file diff --git a/src/Interface.cpp b/src/Interface.cpp index b44458e..7f00eda 100644 --- a/src/Interface.cpp +++ b/src/Interface.cpp @@ -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); diff --git a/src/Interface.h b/src/Interface.h index f33388b..6aaad80 100644 --- a/src/Interface.h +++ b/src/Interface.h @@ -30,31 +30,34 @@ namespace RNS { Bytes _raw; }; + protected: + using HInterface = std::shared_ptr; + 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"); + Interface(const char* name) : _object(new Object(name)) { + 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 { @@ -80,20 +83,26 @@ namespace RNS { inline void OUT(bool OUT) { assert(_object); _object->_OUT = OUT; } 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 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& 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 + "]"; } @@ -101,7 +110,7 @@ namespace RNS { class Object { public: Object() {} - Object(const char *name) : _name(name) {} + Object(const char* name) : _name(name) {} virtual ~Object() {} private: bool _IN = false; @@ -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 _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; + friend class Transport; }; } diff --git a/src/Interfaces/UDPInterface.cpp b/src/Interfaces/UDPInterface.cpp new file mode 100644 index 0000000..693aee4 --- /dev/null +++ b/src/Interfaces/UDPInterface.cpp @@ -0,0 +1,134 @@ +#include "UDPInterface.h" + +#include "../Log.h" + +#include + +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()); + } +} diff --git a/src/Interfaces/UDPInterface.h b/src/Interfaces/UDPInterface.h new file mode 100644 index 0000000..0c3a05a --- /dev/null +++ b/src/Interfaces/UDPInterface.h @@ -0,0 +1,61 @@ +#pragma once + +#include "../Interface.h" +#include "../Bytes.h" +#include "../Type.h" + +#ifdef ARDUINO +#include +#include +//#include +#endif + +#include + +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 + + }; + +} } diff --git a/src/Link.cpp b/src/Link.cpp index e1cadd5..ff4e8b0 100644 --- a/src/Link.cpp +++ b/src/Link.cpp @@ -9,7 +9,7 @@ using namespace RNS::Type::Link; Link::Link() : _object(new Object()) { assert(_object); - extreme("Link object created"); + mem("Link object created"); } diff --git a/src/Link.h b/src/Link.h index be93f0e..521c8d5 100644 --- a/src/Link.h +++ b/src/Link.h @@ -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) { diff --git a/src/Log.cpp b/src/Log.cpp index 8c77d24..6478b42 100644 --- a/src/Log.cpp +++ b/src/Log.cpp @@ -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; @@ -37,11 +40,11 @@ LogLevel RNS::loglevel() { return _level; } -void RNS::doLog(const char *msg, LogLevel level) { +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); @@ -51,11 +54,11 @@ void RNS::doLog(const char *msg, LogLevel level) { #endif } -void RNS::head(const char *msg, LogLevel level) { +void RNS::head(const char* msg, LogLevel level) { if (level > _level) { return; } -#ifndef NATIVE +#ifdef ARDUINO Serial.println(""); #else printf("\n"); diff --git a/src/Log.h b/src/Log.h index 0bacb67..76fc0b6 100644 --- a/src/Log.h +++ b/src/Log.h @@ -1,6 +1,6 @@ #pragma once -#ifndef NATIVE +#ifdef ARDUINO #include #endif @@ -17,44 +17,48 @@ namespace RNS { LOG_VERBOSE = 5, LOG_DEBUG = 6, LOG_EXTREME = 7, + LOG_MEM = 8, }; void loglevel(LogLevel level); LogLevel loglevel(); - void doLog(const char *msg, LogLevel level); + void doLog(const char* msg, LogLevel level); - inline void log(const char *msg, LogLevel level = LOG_NOTICE) { doLog(msg, level); } -#ifndef NATIVE + inline void log(const char* msg, LogLevel level = LOG_NOTICE) { doLog(msg, level); } +#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); } - inline void critical(const char *msg) { doLog(msg, LOG_CRITICAL); } + inline void critical(const char* msg) { doLog(msg, LOG_CRITICAL); } inline void critical(const std::string& msg) { doLog(msg.c_str(), LOG_CRITICAL); } - inline void error(const char *msg) { doLog(msg, LOG_ERROR); } + inline void error(const char* msg) { doLog(msg, LOG_ERROR); } inline void error(const std::string& msg) { doLog(msg.c_str(), LOG_ERROR); } - inline void warning(const char *msg) { doLog(msg, LOG_WARNING); } + inline void warning(const char* msg) { doLog(msg, LOG_WARNING); } inline void warning(const std::string& msg) { doLog(msg.c_str(), LOG_WARNING); } - inline void notice(const char *msg) { doLog(msg, LOG_NOTICE); } + inline void notice(const char* msg) { doLog(msg, LOG_NOTICE); } inline void notice(const std::string& msg) { doLog(msg.c_str(), LOG_NOTICE); } - inline void info(const char *msg) { doLog(msg, LOG_INFO); } + inline void info(const char* msg) { doLog(msg, LOG_INFO); } inline void info(const std::string& msg) { doLog(msg.c_str(), LOG_INFO); } - inline void verbose(const char *msg) { doLog(msg, LOG_VERBOSE); } + inline void verbose(const char* msg) { doLog(msg, LOG_VERBOSE); } inline void verbose(const std::string& msg) { doLog(msg.c_str(), LOG_VERBOSE); } - inline void debug(const char *msg) { doLog(msg, LOG_DEBUG); } + inline void debug(const char* msg) { doLog(msg, LOG_DEBUG); } inline void debug(const std::string& msg) { doLog(msg.c_str(), LOG_DEBUG); } - inline void extreme(const char *msg) { doLog(msg, LOG_EXTREME); } + inline void extreme(const char* msg) { doLog(msg, LOG_EXTREME); } inline void extreme(const std::string& msg) { doLog(msg.c_str(), LOG_EXTREME); } - void head(const char *msg, LogLevel level = LOG_NOTICE); + 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); } } diff --git a/src/Packet.cpp b/src/Packet.cpp index 820192a..f6d7031 100644 --- a/src/Packet.cpp +++ b/src/Packet.cpp @@ -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"); } @@ -328,7 +328,7 @@ bool Packet::unpack() { throw std::length_error("Packet size of " + std::to_string(_object->_raw.size()) + " does not meet minimum header size of " + std::to_string(Type::Reticulum::HEADER_MINSIZE) +" bytes"); } - const uint8_t *raw = _object->_raw.data(); + const uint8_t* raw = _object->_raw.data(); // read header _object->_flags = raw[0]; diff --git a/src/Packet.h b/src/Packet.h index 5483326..7f2dc27 100644 --- a/src/Packet.h +++ b/src/Packet.h @@ -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 { diff --git a/src/Reticulum.cpp b/src/Reticulum.cpp index b93d01a..a2c001e 100644 --- a/src/Reticulum.cpp +++ b/src/Reticulum.cpp @@ -5,6 +5,11 @@ #include +#ifdef ARDUINO +//#include +//#include +#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())); } diff --git a/src/Reticulum.h b/src/Reticulum.h index 30e7e6d..dbcbe43 100644 --- a/src/Reticulum.h +++ b/src/Reticulum.h @@ -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; diff --git a/src/Test/Test.cpp b/src/Test/Test.cpp index 8e69688..d7c6767 100644 --- a/src/Test/Test.cpp +++ b/src/Test/Test.cpp @@ -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); } diff --git a/src/Test/Test.h b/src/Test/Test.h index ad96306..88df2d4 100644 --- a/src/Test/Test.h +++ b/src/Test/Test.h @@ -1,13 +1,7 @@ void test(); -void testMap(); void testBytes(); -void testCowBytes(); -void testBytesConversion(); - +void testCollections(); void testReference(); - void testCrypto(); -void testHMAC(); -void testPKCS7(); diff --git a/src/Test/TestBytes.cpp b/src/Test/TestBytes.cpp index 72d77ce..753fc25 100644 --- a/src/Test/TestBytes.cpp +++ b/src/Test/TestBytes.cpp @@ -3,7 +3,6 @@ #include "Bytes.h" #include "Log.h" -#include #include //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 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(); } /* diff --git a/src/Test/TestCollections.cpp b/src/Test/TestCollections.cpp new file mode 100644 index 0000000..c6322b9 --- /dev/null +++ b/src/Test/TestCollections.cpp @@ -0,0 +1,136 @@ +//#include + +#include "Bytes.h" +#include "Log.h" + +#include +#include +#include + +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 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 entries; + std::map 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(); +} +*/ diff --git a/src/Test/TestCrypto.cpp b/src/Test/TestCrypto.cpp index f71dbc4..aa02cc0 100644 --- a/src/Test/TestCrypto.cpp +++ b/src/Test/TestCrypto.cpp @@ -12,11 +12,13 @@ #include -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) { diff --git a/src/Test/TestReference.cpp b/src/Test/TestReference.cpp index 55d9dec..402ad02 100644 --- a/src/Test/TestReference.cpp +++ b/src/Test/TestReference.cpp @@ -6,6 +6,7 @@ #include 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::less> 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(interface).processOutgoing(data); + } + return 0; +*/ +/* + RNS::loglevel(RNS::LOG_EXTREME); + TestInterface testinterface; + + std::set, std::less> interfaces; + interfaces.insert(testinterface); + for (auto& interface : interfaces) { + RNS::extreme("Found interface: " + interface.toString()); + RNS::Bytes data; + const_cast(interface).processOutgoing(data); + } + return 0; +*/ +/* + RNS::loglevel(RNS::LOG_EXTREME); + TestInterface testinterface; + + std::list> 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(interface).processOutgoing(data); + } + return 0; +*/ +/* + RNS::loglevel(RNS::LOG_EXTREME); + TestInterface testinterface; + + std::list> 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(interface).processOutgoing(data); + } + return 0; +*/ +/* + std::list> 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(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(interface).processOutgoing(data); + } + return 0; +*/ +/* + RNS::head("Testing map...", RNS::LOG_EXTREME); + { + std::map 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; + } +*/ + } /* diff --git a/src/Transport.cpp b/src/Transport.cpp index 40ae488..393fa68 100644 --- a/src/Transport.cpp +++ b/src/Transport.cpp @@ -39,10 +39,12 @@ using namespace RNS::Utilities; /*static*/ std::map Transport::_destination_table; /*static*/ std::map Transport::_reverse_table; /*static*/ std::map Transport::_link_table; +/*static*/ std::map Transport::_held_announces; /*static*/ std::set Transport::_announce_handlers; -/*static*/ std::set Transport::_path_requests; +/*static*/ std::map Transport::_path_requests; /*static*/ std::map Transport::_discovery_path_requests; +/*static*/ std::set Transport::_discovery_pr_tags; /*static*/ uint16_t Transport::_max_pr_taXgxs = 32000; /*static*/ std::set 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 empty_random_blobs; std::set& 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(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 - return false; + 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 - return false; + 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 - return false; + 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 diff --git a/src/Transport.h b/src/Transport.h index 6feed78..08b4417 100644 --- a/src/Transport.h +++ b/src/Transport.h @@ -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 _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 _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 _path_requests; // A table for storing path request timestamps + static std::map _path_requests; // A table for storing path request timestamps static std::map _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 _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 diff --git a/src/Type.h b/src/Type.h index 407341d..2e17a3a 100644 --- a/src/Type.h +++ b/src/Type.h @@ -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. diff --git a/src/Utilities/OS.h b/src/Utilities/OS.h index e0f5739..c86e109 100644 --- a/src/Utilities/OS.h +++ b/src/Utilities/OS.h @@ -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; } }; diff --git a/src/main.cpp b/src/main.cpp index fd42547..96f31ea 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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 #endif @@ -23,6 +26,13 @@ #include //#include + +#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 @@ -39,7 +49,7 @@ public: IN(true); OUT(true); } - TestInterface(const char *name) : RNS::Interface(name) { + TestInterface(const char* name) : RNS::Interface(name) { IN(true); OUT(true); } @@ -61,7 +71,7 @@ public: IN(true); OUT(true); } - TestLoopbackInterface(RNS::Interface& loopback_interface, const char *name) : RNS::Interface(name), _loopback_interface(loopback_interface) { + TestLoopbackInterface(RNS::Interface& loopback_interface, const char* name) : RNS::Interface(name), _loopback_interface(loopback_interface) { IN(true); OUT(true); } @@ -87,7 +97,7 @@ public: OUT(true); IN(false); } - TestOutInterface(const char *name) : RNS::Interface(name) { + TestOutInterface(const char* name) : RNS::Interface(name) { OUT(true); IN(false); } @@ -107,7 +117,7 @@ public: OUT(false); IN(true); } - TestInInterface(const char *name) : RNS::Interface(name) { + TestInInterface(const char* name) : RNS::Interface(name) { OUT(false); IN(true); } @@ -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 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::less> 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(interface).processOutgoing(data); - } - return 0; -*/ -/* - RNS::loglevel(RNS::LOG_EXTREME); - TestInterface testinterface; - - std::set, std::less> interfaces; - interfaces.insert(testinterface); - for (auto& interface : interfaces) { - RNS::extreme("Found interface: " + interface.toString()); - RNS::Bytes data; - const_cast(interface).processOutgoing(data); - } - return 0; -*/ -/* - RNS::loglevel(RNS::LOG_EXTREME); - TestInterface testinterface; - - std::list> 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(interface).processOutgoing(data); - } - return 0; -*/ -/* - RNS::loglevel(RNS::LOG_EXTREME); - TestInterface testinterface; - - std::list> 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(interface).processOutgoing(data); - } - return 0; -*/ -/* - std::list> 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(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(interface).processOutgoing(data); - } - return 0; -*/ - setup(); //while (true) {