diff --git a/platformio.ini b/platformio.ini index a9a2be3..520afd3 100644 --- a/platformio.ini +++ b/platformio.ini @@ -19,6 +19,7 @@ build_flags = -Wextra -Wno-missing-field-initializers -Wno-format + -Wno-unused-parameter -Isrc -DNATIVE lib_deps = diff --git a/src/Cryptography/Ed25519.h b/src/Cryptography/Ed25519.h index bffca0a..0c46665 100644 --- a/src/Cryptography/Ed25519.h +++ b/src/Cryptography/Ed25519.h @@ -65,6 +65,8 @@ namespace RNS { namespace Cryptography { public: // creates a new instance with a random seed static inline Ptr generate() { + // CBA TODO determine why below is confused with (implicit) copy constructor + //return Ptr(new Ed25519PrivateKey({Bytes::NONE})); return Ptr(new Ed25519PrivateKey(Bytes::NONE)); } diff --git a/src/Cryptography/HKDF.cpp b/src/Cryptography/HKDF.cpp index eaba240..f614131 100644 --- a/src/Cryptography/HKDF.cpp +++ b/src/Cryptography/HKDF.cpp @@ -5,7 +5,7 @@ using namespace RNS; -Bytes RNS::Cryptography::hkdf(size_t length, const Bytes &derive_from, const Bytes &salt /*= Bytes::NONE*/, const Bytes &context /*= Bytes::NONE*/) { +Bytes RNS::Cryptography::hkdf(size_t length, const Bytes &derive_from, const Bytes &salt /*= {Bytes::NONE}*/, const Bytes &context /*= {Bytes::NONE}*/) { if (length <= 0) { throw std::invalid_argument("Invalid output key length"); diff --git a/src/Cryptography/HKDF.h b/src/Cryptography/HKDF.h index 7510d31..f3f9039 100644 --- a/src/Cryptography/HKDF.h +++ b/src/Cryptography/HKDF.h @@ -4,6 +4,6 @@ namespace RNS { namespace Cryptography { - Bytes hkdf(size_t length, const Bytes &derive_from, const Bytes &salt = Bytes::NONE, const Bytes &context = Bytes::NONE); + Bytes hkdf(size_t length, const Bytes &derive_from, const Bytes &salt = {Bytes::NONE}, const Bytes &context = {Bytes::NONE}); } } diff --git a/src/Cryptography/HMAC.h b/src/Cryptography/HMAC.h index e59acd0..980fc11 100644 --- a/src/Cryptography/HMAC.h +++ b/src/Cryptography/HMAC.h @@ -28,7 +28,7 @@ namespace RNS { namespace Cryptography { msg: bytes or buffer, Initial input for the hash or None. digest: The underlying hash algorithm to use */ - HMAC(const Bytes &key, const Bytes &msg = Bytes::NONE, Digest digest = DIGEST_SHA256) { + HMAC(const Bytes &key, const Bytes &msg = {Bytes::NONE}, Digest digest = DIGEST_SHA256) { if (digest == DIGEST_NONE) { throw std::invalid_argument("Cannot derive key from empty input material"); @@ -83,7 +83,7 @@ namespace RNS { namespace Cryptography { method, and can ask for the hash value at any time by calling its digest() method. */ - static inline Ptr generate(const Bytes &key, const Bytes &msg = Bytes::NONE, Digest digest = DIGEST_SHA256) { + static inline Ptr generate(const Bytes &key, const Bytes &msg = {Bytes::NONE}, Digest digest = DIGEST_SHA256) { return Ptr(new HMAC(key, msg, digest)); } diff --git a/src/Cryptography/X25519.h b/src/Cryptography/X25519.h index 488b661..bf1832d 100644 --- a/src/Cryptography/X25519.h +++ b/src/Cryptography/X25519.h @@ -97,7 +97,7 @@ namespace RNS { namespace Cryptography { } */ static inline Ptr generate() { - return from_private_bytes(Bytes::NONE); + return from_private_bytes({Bytes::NONE}); } // creates a new instance with specified seed diff --git a/src/Destination.cpp b/src/Destination.cpp index ac6c893..c66c88d 100644 --- a/src/Destination.cpp +++ b/src/Destination.cpp @@ -10,6 +10,7 @@ #include using namespace RNS; +using namespace RNS::Type::Destination; Destination::Destination(const Identity &identity, const directions direction, const types type, const char* app_name, const char *aspects) : _object(new Object(identity)) { assert(_object); @@ -23,7 +24,7 @@ Destination::Destination(const Identity &identity, const directions direction, c _object->_direction = direction; std::string fullaspects(aspects); - if (!identity && direction == Destination::IN && _object->_type != Destination::PLAIN) { + if (!identity && direction == IN && _object->_type != PLAIN) { debug("Destination::Destination: identity not provided, creating new one"); _object->_identity = Identity(); // CBA TODO should following include a "." delimiter? @@ -31,7 +32,7 @@ Destination::Destination(const Identity &identity, const directions direction, c } debug("Destination::Destination: full aspects: " + fullaspects); - if (_object->_identity && _object->_type == Destination::PLAIN) { + if (_object->_identity && _object->_type == PLAIN) { throw std::invalid_argument("Selected destination type PLAIN cannot hold an identity"); } @@ -45,7 +46,7 @@ Destination::Destination(const Identity &identity, const directions direction, c debug("Destination::Destination: hash: " + _object->_hash.toHex()); // CBA TEST CRASH debug("Destination::Destination: creating name hash..."); - _object->_name_hash = Identity::truncated_hash(expand_name(Identity::NONE, app_name, fullaspects.c_str())); + _object->_name_hash = Identity::truncated_hash(expand_name({Type::NONE}, app_name, fullaspects.c_str())); debug("Destination::Destination: name hash: " + _object->_name_hash.toHex()); debug("Destination::Destination: calling register_destination"); @@ -60,7 +61,7 @@ Destination::Destination(const Identity &identity, const directions direction, c /*static*/ Bytes Destination::hash(const Identity &identity, const char *app_name, const char *aspects) { //name_hash = Identity::full_hash(Destination.expand_name(None, app_name, *aspects).encode("utf-8"))[:(RNS.Identity.NAME_HASH_LENGTH//8)] //addr_hash_material = name_hash - Bytes addr_hash_material = Identity::truncated_hash(expand_name(Identity::NONE, app_name, aspects)); + Bytes addr_hash_material = Identity::truncated_hash(expand_name({Type::NONE}, app_name, aspects)); //if identity != None: // if isinstance(identity, RNS.Identity): // addr_hash_material += identity.hash @@ -121,7 +122,7 @@ Packet Destination::announce(const Bytes &app_data, bool path_response, Interfac //Response &entry = *it; // map PathResponse &entry = (*it).second; - if (now > (entry.first + Destination::PR_TAG_WINDOW)) { + if (now > (entry.first + PR_TAG_WINDOW)) { it = _object->_path_responses.erase(it); } else { @@ -205,18 +206,18 @@ Packet Destination::announce(const Bytes &app_data, bool path_response, Interfac } debug("Destination::announce: announce_data:" + announce_data.toHex()); - Packet::context_types announce_context = Packet::CONTEXT_NONE; + Type::Packet::context_types announce_context = Type::Packet::CONTEXT_NONE; if (path_response) { - announce_context = Packet::PATH_RESPONSE; + announce_context = Type::Packet::PATH_RESPONSE; } debug("Destination::announce: creating announce packet..."); - Packet announce_packet(*this, announce_data, Packet::ANNOUNCE, announce_context, Transport::BROADCAST, Packet::HEADER_1, nullptr, attached_interface); + Packet announce_packet(*this, announce_data, Type::Packet::ANNOUNCE, announce_context, Type::Transport::BROADCAST, Type::Packet::HEADER_1, nullptr, attached_interface); if (send) { debug("Destination::announce: sending announce packet..."); announce_packet.send(); - return Packet::NONE; + return {Type::NONE}; } else { return announce_packet; @@ -267,7 +268,7 @@ bool Destination::deregister_request_handler(const Bytes &path) { void Destination::receive(const Packet &packet) { assert(_object); - if (packet.packet_type() == Packet::LINKREQUEST) { + if (packet.packet_type() == Type::Packet::LINKREQUEST) { Bytes plaintext(packet.data()); incoming_link_request(plaintext, packet); } @@ -276,7 +277,7 @@ void Destination::receive(const Packet &packet) { Bytes plaintext(decrypt(packet.data())); extreme("Destination::receive: decrypted data: " + plaintext.toHex()); if (plaintext) { - if (packet.packet_type() == RNS::Packet::DATA) { + if (packet.packet_type() == Type::Packet::DATA) { if (_object->_callbacks._packet) { try { _object->_callbacks._packet(plaintext, packet); @@ -293,10 +294,10 @@ void Destination::receive(const Packet &packet) { void Destination::incoming_link_request(const Bytes &data, const Packet &packet) { assert(_object); if (_object->_accept_link_requests) { - //zlink = RNS::Link::validate_request(data, packet); - //zif (link) { + //z link = Link::validate_request(data, packet); + //z if (link) { //z _links.append(link); - //z} + //z } } } @@ -310,16 +311,16 @@ Bytes Destination::encrypt(const Bytes &data) { assert(_object); debug("Destination::encrypt: encrypting data..."); - if (_object->_type == Destination::PLAIN) { + if (_object->_type == PLAIN) { return data; } - if (_object->_type == Destination::SINGLE && _object->_identity) { + if (_object->_type == SINGLE && _object->_identity) { return _object->_identity.encrypt(data); } /* - if (_object->_type == Destination::GROUP { + if (_object->_type == GROUP { if hasattr(self, "prv") and self.prv != None: try: return self.prv.encrypt(plaintext) @@ -331,7 +332,7 @@ Bytes Destination::encrypt(const Bytes &data) { } */ // MOCK - return Bytes::NONE; + return {Bytes::NONE}; } /* @@ -344,16 +345,16 @@ Bytes Destination::decrypt(const Bytes &data) { assert(_object); debug("Destination::decrypt: decrypting data..."); - if (_object->_type == Destination::PLAIN) { + if (_object->_type == PLAIN) { return data; } - if (_object->_type == Destination::SINGLE && _object->_identity) { + if (_object->_type == SINGLE && _object->_identity) { return _object->_identity.decrypt(data); } /* - if (_object->_type == Destination::GROUP) { + if (_object->_type == GROUP) { if hasattr(self, "prv") and self.prv != None: try: return self.prv.decrypt(ciphertext) @@ -365,7 +366,7 @@ Bytes Destination::decrypt(const Bytes &data) { } */ // MOCK - return Bytes::NONE; + return {Bytes::NONE}; } /* @@ -376,8 +377,8 @@ Signs information for ``RNS.Destination.SINGLE`` type destination. */ Bytes Destination::sign(const Bytes &message) { assert(_object); - if (_object->_type == Destination::SINGLE && _object->_identity) { + if (_object->_type == SINGLE && _object->_identity) { return _object->_identity.sign(message); } - return Bytes::NONE; + return {Bytes::NONE}; } diff --git a/src/Destination.h b/src/Destination.h index 21bf012..bd5d4f1 100644 --- a/src/Destination.h +++ b/src/Destination.h @@ -4,7 +4,7 @@ #include "Link.h" #include "Identity.h" #include "Bytes.h" -#include "None.h" +#include "Type.h" #include #include @@ -54,48 +54,14 @@ namespace RNS { using PathResponse = std::pair; //using PathResponse = std::pair>; - enum NoneConstructor { - NONE - }; - - // Constants - enum types { - SINGLE = 0x00, - GROUP = 0x01, - PLAIN = 0x02, - LINK = 0x03, - }; - - enum proof_strategies { - PROVE_NONE = 0x21, - PROVE_APP = 0x22, - PROVE_ALL = 0x23, - }; - - enum request_policies { - ALLOW_NONE = 0x00, - ALLOW_ALL = 0x01, - ALLOW_LIST = 0x02, - }; - - enum directions { - IN = 0x11, - OUT = 0x12, - }; - - const uint8_t PR_TAG_WINDOW = 30; - public: - Destination(NoneConstructor none) { - extreme("Destination NONE object created"); - } - Destination(RNS::NoneConstructor none) { + Destination(Type::NoneConstructor none) { extreme("Destination NONE object created"); } Destination(const Destination &destination) : _object(destination._object) { extreme("Destination object copy created"); } - Destination(const Identity &identity, const directions direction, const types type, const char* app_name, const char *aspects); + Destination(const Identity &identity, const Type::Destination::directions direction, const Type::Destination::types type, const char* app_name, const char *aspects); virtual ~Destination() { extreme("Destination object destroyed"); } @@ -165,7 +131,7 @@ namespace RNS { :param proof_strategy: One of ``RNS.Destination.PROVE_NONE``, ``RNS.Destination.PROVE_ALL`` or ``RNS.Destination.PROVE_APP``. If ``RNS.Destination.PROVE_APP`` is set, the `proof_requested_callback` will be called to determine whether a proof should be sent or not. */ - inline void set_proof_strategy(proof_strategies proof_strategy) { + inline void set_proof_strategy(Type::Destination::proof_strategies proof_strategy) { assert(_object); //if (proof_strategy <= PROOF_NONE) { // throw throw std::invalid_argument("Unsupported proof strategy"); @@ -181,14 +147,14 @@ namespace RNS { Bytes sign(const Bytes &message); // getters/setters - inline types type() const { assert(_object); return _object->_type; } - inline directions direction() const { assert(_object); return _object->_direction; } - inline proof_strategies proof_strategy() const { assert(_object); return _object->_proof_strategy; } + inline Type::Destination::types type() const { assert(_object); return _object->_type; } + inline Type::Destination::directions direction() const { assert(_object); return _object->_direction; } + inline Type::Destination::proof_strategies proof_strategy() const { assert(_object); return _object->_proof_strategy; } inline Bytes hash() const { assert(_object); return _object->_hash; } inline Bytes link_id() const { assert(_object); return _object->_link_id; } inline uint16_t mtu() const { assert(_object); return _object->_mtu; } inline void mtu(uint16_t mtu) { assert(_object); _object->_mtu = mtu; } - inline Link::status status() const { assert(_object); return _object->_status; } + inline Type::Link::status status() const { assert(_object); return _object->_status; } inline const Callbacks &callbacks() const { assert(_object); return _object->_callbacks; } inline const Identity &identity() const { assert(_object); return _object->_identity; } @@ -203,9 +169,9 @@ namespace RNS { bool _accept_link_requests = true; Callbacks _callbacks; //z_request_handlers = {} - types _type; - directions _direction; - proof_strategies _proof_strategy = PROVE_NONE; + Type::Destination::types _type; + Type::Destination::directions _direction; + Type::Destination::proof_strategies _proof_strategy = Type::Destination::PROVE_NONE; uint16_t _mtu = 0; //std::vector _path_responses; @@ -229,7 +195,7 @@ namespace RNS { // CBA TODO determine if Link needs to inherit from Destination or vice-versa Bytes _link_id; - Link::status _status; + Type::Link::status _status; friend class Destination; }; diff --git a/src/Identity.cpp b/src/Identity.cpp index b375287..70c5eb8 100644 --- a/src/Identity.cpp +++ b/src/Identity.cpp @@ -11,6 +11,7 @@ #include using namespace RNS; +using namespace RNS::Type::Identity; Identity::Identity(bool create_keys) : _object(new Object()) { if (create_keys) { @@ -177,14 +178,14 @@ Bytes Identity::decrypt(const Bytes &ciphertext_token) { if (!_object->_prv) { throw std::runtime_error("Decryption failed because identity does not hold a private key"); } - if (ciphertext_token.size() <= Identity::KEYSIZE/8/2) { + if (ciphertext_token.size() <= Type::Identity::KEYSIZE/8/2) { debug("Decryption failed because the token size " + std::to_string(ciphertext_token.size()) + " was invalid."); - return Bytes::NONE; + return {Bytes::NONE}; } Bytes plaintext; try { //peer_pub_bytes = ciphertext_token[:Identity.KEYSIZE//8//2] - Bytes peer_pub_bytes = ciphertext_token.left(Identity::KEYSIZE/8/2); + Bytes peer_pub_bytes = ciphertext_token.left(Type::Identity::KEYSIZE/8/2); //peer_pub = X25519PublicKey.from_public_bytes(peer_pub_bytes) //Cryptography::X25519PublicKey::Ptr peer_pub = Cryptography::X25519PublicKey::from_public_bytes(peer_pub_bytes); debug("Identity::decrypt: peer public key: " + peer_pub_bytes.toHex()); @@ -204,7 +205,7 @@ Bytes Identity::decrypt(const Bytes &ciphertext_token) { Cryptography::Fernet fernet(derived_key); //ciphertext = ciphertext_token[Identity.KEYSIZE//8//2:] - Bytes ciphertext(ciphertext_token.mid(Identity::KEYSIZE/8/2)); + Bytes ciphertext(ciphertext_token.mid(Type::Identity::KEYSIZE/8/2)); debug("Identity::decrypt: Fernet decrypting data of length " + std::to_string(ciphertext.size())); extreme("Identity::decrypt: ciphertext: " + ciphertext.toHex()); plaintext = fernet.decrypt(ciphertext); @@ -263,7 +264,7 @@ bool Identity::validate(const Bytes &signature, const Bytes &message) { } } -void Identity::prove(const Packet &packet, const Destination &destination /*= Destination::NONE*/) { +void Identity::prove(const Packet &packet, const Destination &destination /*= {Destination::NONE}*/) { assert(_object); Bytes signature(sign(packet.packet_hash())); Bytes proof_data; @@ -278,6 +279,6 @@ void Identity::prove(const Packet &packet, const Destination &destination /*= De //z destination = packet.generate_proof_destination(); //z} - Packet proof(destination, packet.receiving_interface(), proof_data, RNS::Packet::PROOF); + Packet proof(destination, packet.receiving_interface(), proof_data, Type::Packet::PROOF); proof.send(); } diff --git a/src/Identity.h b/src/Identity.h index d55e757..b156c61 100644 --- a/src/Identity.h +++ b/src/Identity.h @@ -1,15 +1,14 @@ #pragma once #include "Reticulum.h" -// CBA TODO determine why including Destination.h here causes build errors //#include "Destination.h" #include "Log.h" #include "Bytes.h" -#include "None.h" #include "Cryptography/Hashes.h" #include "Cryptography/Ed25519.h" #include "Cryptography/X25519.h" #include "Cryptography/Fernet.h" +#include "Type.h" #include @@ -23,33 +22,7 @@ namespace RNS { class Identity { public: - enum NoneConstructor { - NONE - }; - - //static const char CURVE[] = "Curve25519"; - static constexpr const char* CURVE = "Curve25519"; - // The curve used for Elliptic Curve DH key exchanges - - static const uint16_t KEYSIZE = 256*2; - // X25519 key size in bits. A complete key is the concatenation of a 256 bit encryption key, and a 256 bit signing key. - - // Non-configurable constants - static const uint8_t FERNET_OVERHEAD = RNS::Cryptography::Fernet::FERNET_OVERHEAD; - static const uint8_t AES128_BLOCKSIZE = 16; // In bytes - static const uint16_t HASHLENGTH = Reticulum::HASHLENGTH; // In bits - static const uint16_t SIGLENGTH = KEYSIZE; // In bits - - static const uint8_t NAME_HASH_LENGTH = 80; - static const uint16_t TRUNCATED_HASHLENGTH = Reticulum::TRUNCATED_HASHLENGTH; // In bits - // Constant specifying the truncated hash length (in bits) used by Reticulum - // for addressable hashes and other purposes. Non-configurable. - - public: - Identity(NoneConstructor none) { - extreme("Identity NONE object created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get())); - } - Identity(RNS::NoneConstructor none) { + Identity(Type::NoneConstructor none) { extreme("Identity NONE object created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get())); } Identity(const Identity &identity) : _object(identity._object) { @@ -105,7 +78,7 @@ namespace RNS { */ static inline Bytes truncated_hash(const Bytes &data) { //return Identity.full_hash(data)[:(Identity.TRUNCATED_HASHLENGTH//8)] - return full_hash(data).left(TRUNCATED_HASHLENGTH/8); + return full_hash(data).left(Type::Identity::TRUNCATED_HASHLENGTH/8); } /* Get a random SHA-256 hash. @@ -114,19 +87,19 @@ namespace RNS { :returns: Truncated SHA-256 hash of random data as *bytes* */ static inline Bytes get_random_hash() { - return truncated_hash(Cryptography::random(Identity::TRUNCATED_HASHLENGTH/8)); + return truncated_hash(Cryptography::random(Type::Identity::TRUNCATED_HASHLENGTH/8)); } static bool validate_announce(const Packet &packet); inline Bytes get_salt() { assert(_object); return _object->_hash; } - inline Bytes get_context() { return Bytes::NONE; } + inline Bytes get_context() { return {Bytes::NONE}; } Bytes encrypt(const Bytes &plaintext); Bytes decrypt(const Bytes &ciphertext_token); Bytes sign(const Bytes &message); bool validate(const Bytes &signature, const Bytes &message); - //void prove(const Packet &packet, const Destination &destination = Destination::NONE); + //void prove(const Packet &packet, const Destination &destination = {Destination::NONE}); void prove(const Packet &packet, const Destination &destination); // getters/setters diff --git a/src/Interfaces/Interface.cpp b/src/Interfaces/Interface.cpp index 030e667..a617e0c 100644 --- a/src/Interfaces/Interface.cpp +++ b/src/Interfaces/Interface.cpp @@ -3,7 +3,7 @@ #include "../Transport.h" using namespace RNS; - +using namespace RNS::Type::Interface; /*virtual*/ inline void Interface::processIncoming(const Bytes &data) { extreme("Interface::processIncoming: data: " + data.toHex()); diff --git a/src/Interfaces/Interface.h b/src/Interfaces/Interface.h index 2a8e6a2..e55cde8 100644 --- a/src/Interfaces/Interface.h +++ b/src/Interfaces/Interface.h @@ -2,7 +2,7 @@ #include "../Log.h" #include "../Bytes.h" -#include "../None.h" +#include "../Type.h" #include #include @@ -31,31 +31,12 @@ namespace RNS { }; public: - enum NoneConstructor { - NONE - }; - - public: - // Interface mode definitions - enum modes { - MODE_NONE = 0x00, - MODE_FULL = 0x01, - MODE_POINT_TO_POINT = 0x04, - MODE_ACCESS_POINT = 0x08, - MODE_ROAMING = 0x10, - MODE_BOUNDARY = 0x20, - MODE_GATEWAY = 0x40, - }; - // Which interface modes a Transport Node // should actively discover paths for. - uint8_t DISCOVER_PATHS_FOR = MODE_ACCESS_POINT | MODE_GATEWAY; + uint8_t DISCOVER_PATHS_FOR = Type::Interface::MODE_ACCESS_POINT | Type::Interface::MODE_GATEWAY; public: - Interface(NoneConstructor none) { - extreme("Interface object NONE created"); - } - Interface(RNS::NoneConstructor none) { + Interface(Type::NoneConstructor none) { extreme("Interface object NONE created"); } Interface(const Interface &interface) : _object(interface._object) { @@ -107,7 +88,7 @@ namespace RNS { inline bool RPT() const { assert(_object); return _object->_RPT; } inline std::string name() const { assert(_object); return _object->_name; } inline Bytes ifac_identity() const { assert(_object); return _object->_ifac_identity; } - inline modes mode() const { assert(_object); return _object->_mode; } + inline Type::Interface::modes mode() const { assert(_object); return _object->_mode; } inline uint32_t bitrate() const { assert(_object); return _object->_bitrate; } inline uint64_t announce_allowed_at() const { assert(_object); return _object->_announce_allowed_at; } inline void announce_allowed_at(uint64_t announce_allowed_at) { assert(_object); _object->_announce_allowed_at = announce_allowed_at; } @@ -132,7 +113,7 @@ namespace RNS { size_t _txb = 0; bool online = false; Bytes _ifac_identity; - modes _mode = MODE_NONE; + Type::Interface::modes _mode = Type::Interface::MODE_NONE; uint32_t _bitrate = 0; uint64_t _announce_allowed_at = 0; float _announce_cap = 0.0; diff --git a/src/Link.cpp b/src/Link.cpp index 6c4fe3b..ad34a23 100644 --- a/src/Link.cpp +++ b/src/Link.cpp @@ -4,6 +4,7 @@ #include "Log.h" using namespace RNS; +using namespace RNS::Type::Link; Link::Link() : _object(new Object()) { assert(_object); diff --git a/src/Link.h b/src/Link.h index 59da8d3..de0fdd5 100644 --- a/src/Link.h +++ b/src/Link.h @@ -5,7 +5,7 @@ // CBA TODO resolve circular dependency with following header file //#include "Packet.h" #include "Bytes.h" -#include "None.h" +#include "Type.h" #include @@ -20,63 +20,8 @@ namespace RNS { typedef void (*closed)(Link *link); }; - enum NoneConstructor { - NONE - }; - - static constexpr const char* CURVE = Identity::CURVE; - // The curve used for Elliptic Curve DH key exchanges - - static const uint16_t ECPUBSIZE = 32+32; - static const uint8_t KEYSIZE = 32; - - //static const uint16_t MDU = floor((Reticulum::MTU-Reticulum::IFAC_MIN_SIZE-Reticulum::HEADER_MINSIZE-Identity::FERNET_OVERHEAD)/Identity::AES128_BLOCKSIZE)*Identity::AES128_BLOCKSIZE - 1; - static const uint16_t MDU = ((Reticulum::MTU-Reticulum::IFAC_MIN_SIZE-Reticulum::HEADER_MINSIZE-Identity::FERNET_OVERHEAD)/Identity::AES128_BLOCKSIZE)*Identity::AES128_BLOCKSIZE - 1; - - static const uint8_t ESTABLISHMENT_TIMEOUT_PER_HOP = Reticulum::DEFAULT_PER_HOP_TIMEOUT; - // Timeout for link establishment in seconds per hop to destination. - - static const uint16_t TRAFFIC_TIMEOUT_FACTOR = 6; - static const uint16_t KEEPALIVE_TIMEOUT_FACTOR = 4; - // RTT timeout factor used in link timeout calculation. - static const uint8_t STALE_GRACE = 2; - // Grace period in seconds used in link timeout calculation. - static const uint16_t KEEPALIVE = 360; - // Interval for sending keep-alive packets on established links in seconds. - static const uint16_t STALE_TIME = 2*KEEPALIVE; - /* - If no traffic or keep-alive packets are received within this period, the - link will be marked as stale, and a final keep-alive packet will be sent. - If after this no traffic or keep-alive packets are received within ``RTT`` * - ``KEEPALIVE_TIMEOUT_FACTOR`` + ``STALE_GRACE``, the link is considered timed out, - and will be torn down. - */ - - enum status { - PENDING = 0x00, - HANDSHAKE = 0x01, - ACTIVE = 0x02, - STALE = 0x03, - CLOSED = 0x04 - }; - - enum teardown_reasons { - TIMEOUT = 0x01, - INITIATOR_CLOSED = 0x02, - DESTINATION_CLOSED = 0x03, - }; - - enum resource_strategies { - ACCEPT_NONE = 0x00, - ACCEPT_APP = 0x01, - ACCEPT_ALL = 0x02, - }; - public: - Link(NoneConstructor none) { - extreme("Link NONE object created"); - } - Link(RNS::NoneConstructor none) { + Link(Type::NoneConstructor none) { extreme("Link NONE object created"); } Link(const Link &link) : _object(link._object) { diff --git a/src/None.h b/src/None.h deleted file mode 100644 index e435419..0000000 --- a/src/None.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -namespace RNS { - - // generic empty object constructor type - enum NoneConstructor { - NONE - }; - -} diff --git a/src/Packet.cpp b/src/Packet.cpp index 3345028..18b48ca 100644 --- a/src/Packet.cpp +++ b/src/Packet.cpp @@ -7,14 +7,16 @@ #include using namespace RNS; +using namespace RNS::Type::PacketReceipt; +using namespace RNS::Type::Packet; -Packet::Packet(const Destination &destination, const Interface &attached_interface, const Bytes &data, types packet_type /*= DATA*/, context_types context /*= CONTEXT_NONE*/, Transport::types transport_type /*= Transport::BROADCAST*/, header_types header_type /*= HEADER_1*/, const Bytes &transport_id /*= Bytes::NONE*/, bool create_receipt /*= true*/) : _object(new Object(destination, attached_interface)) { +Packet::Packet(const Destination &destination, const Interface &attached_interface, const Bytes &data, types packet_type /*= DATA*/, context_types context /*= CONTEXT_NONE*/, Type::Transport::types transport_type /*= Type::Transport::BROADCAST*/, header_types header_type /*= HEADER_1*/, const Bytes &transport_id /*= {Bytes::NONE}*/, bool create_receipt /*= true*/) : _object(new Object(destination, attached_interface)) { if (_object->_destination) { extreme("Creating packet with destination..."); // CBA TODO handle NONE if (transport_type == -1) { - transport_type = Transport::BROADCAST; + transport_type = Type::Transport::BROADCAST; } // following moved to object constructor to avoid extra NONE object //_destination = destination; @@ -50,7 +52,7 @@ uint8_t Packet::get_packed_flags() { assert(_object); uint8_t packed_flags = 0; if (_object->_context == LRPROOF) { - packed_flags = (_object->_header_type << 6) | (_object->_transport_type << 4) | (Destination::LINK << 2) | _object->_packet_type; + packed_flags = (_object->_header_type << 6) | (_object->_transport_type << 4) | (Type::Destination::LINK << 2) | _object->_packet_type; } else { packed_flags = (_object->_header_type << 6) | (_object->_transport_type << 4) | (_object->_destination.type() << 2) | _object->_packet_type; @@ -61,8 +63,8 @@ uint8_t Packet::get_packed_flags() { void Packet::unpack_flags(uint8_t flags) { assert(_object); _object->_header_type = static_cast((flags & 0b01000000) >> 6); - _object->_transport_type = static_cast((flags & 0b00110000) >> 4); - _object->_destination_type = static_cast((flags & 0b00001100) >> 2); + _object->_transport_type = static_cast((flags & 0b00110000) >> 4); + _object->_destination_type = static_cast((flags & 0b00001100) >> 2); _object->_packet_type = static_cast(flags & 0b00000011); } @@ -267,7 +269,7 @@ void Packet::pack() { // Resource proofs are not encrypted _object->_raw << _object->_data; } - else if (_object->_packet_type == PROOF && _object->_destination.type() == Destination::LINK) { + else if (_object->_packet_type == PROOF && _object->_destination.type() == Type::Destination::LINK) { // Packet proofs over links are not encrypted _object->_raw << _object->_data; } @@ -321,8 +323,8 @@ bool Packet::unpack() { assert(_object); debug("Packet::unpack: unpacking packet..."); try { - if (_object->_raw.size() < Reticulum::HEADER_MINSIZE) { - throw std::length_error("Packet size of " + std::to_string(_object->_raw.size()) + " does not meet minimum header size of " + std::to_string(Reticulum::HEADER_MINSIZE) +" bytes"); + if (_object->_raw.size() < Type::Reticulum::HEADER_MINSIZE) { + throw std::length_error("Packet size of " + std::to_string(_object->_raw.size()) + " does not meet minimum header size of " + std::to_string(Type::Reticulum::HEADER_MINSIZE) +" bytes"); } const uint8_t *raw = _object->_raw.data(); @@ -340,21 +342,21 @@ bool Packet::unpack() { } if (_object->_header_type == HEADER_2) { - if (_object->_raw.size() < Reticulum::HEADER_MAXSIZE) { - throw std::length_error("Packet size of " + std::to_string(_object->_raw.size()) + " does not meet minimum header size of " + std::to_string(Reticulum::HEADER_MAXSIZE) +" bytes"); + if (_object->_raw.size() < Type::Reticulum::HEADER_MAXSIZE) { + throw std::length_error("Packet size of " + std::to_string(_object->_raw.size()) + " does not meet minimum header size of " + std::to_string(Type::Reticulum::HEADER_MAXSIZE) +" bytes"); } - _object->_transport_id.assign(raw+2, Reticulum::DESTINATION_LENGTH); - _object->_destination_hash.assign(raw+Reticulum::DESTINATION_LENGTH+2, Reticulum::DESTINATION_LENGTH); - _object->_context = static_cast(raw[2*Reticulum::DESTINATION_LENGTH+2]); - _object->_data.assign(raw+2*Reticulum::DESTINATION_LENGTH+3, _object->_raw.size()-(2*Reticulum::DESTINATION_LENGTH+3)); + _object->_transport_id.assign(raw+2, Type::Reticulum::DESTINATION_LENGTH); + _object->_destination_hash.assign(raw+Type::Reticulum::DESTINATION_LENGTH+2, Type::Reticulum::DESTINATION_LENGTH); + _object->_context = static_cast(raw[2*Type::Reticulum::DESTINATION_LENGTH+2]); + _object->_data.assign(raw+2*Type::Reticulum::DESTINATION_LENGTH+3, _object->_raw.size()-(2*Type::Reticulum::DESTINATION_LENGTH+3)); // uknown at this point whether data is encrypted or not _object->_encrypted = true; } else { _object->_transport_id.clear(); - _object->_destination_hash.assign(raw+2, Reticulum::DESTINATION_LENGTH); - _object->_context = static_cast(raw[Reticulum::DESTINATION_LENGTH+2]); - _object->_data.assign(raw+Reticulum::DESTINATION_LENGTH+3, _object->_raw.size()-(Reticulum::DESTINATION_LENGTH+3)); + _object->_destination_hash.assign(raw+2, Type::Reticulum::DESTINATION_LENGTH); + _object->_context = static_cast(raw[Type::Reticulum::DESTINATION_LENGTH+2]); + _object->_data.assign(raw+Type::Reticulum::DESTINATION_LENGTH+3, _object->_raw.size()-(Type::Reticulum::DESTINATION_LENGTH+3)); // uknown at this point whether data is encrypted or not _object->_encrypted = true; } @@ -383,7 +385,7 @@ bool Packet::send() { } /* if (_destination->type == RNS::Destination::LINK) { - if (_destination->status == RNS::Link::CLOSED) { + if (_destination->status == Type::Link::CLOSED) { throw std::runtime_error("Attempt to transmit over a closed link"); } else { @@ -398,7 +400,7 @@ bool Packet::send() { pack(); } - if (RNS::Transport::outbound(*this)) { + if (Transport::outbound(*this)) { debug("Packet::send: successfully sent packet!!!"); //zreturn self.receipt // MOCK @@ -427,7 +429,7 @@ bool Packet::resend() { // encrypted destinations pack(); - if (RNS::Transport::outbound(*this)) { + if (Transport::outbound(*this)) { debug("Packet::resend: successfully sent packet!!!"); //zreturn self.receipt // MOCK @@ -441,7 +443,7 @@ bool Packet::resend() { } } -void Packet::prove(const Destination &destination /*= {Destination::NONE}*/) { +void Packet::prove(const Destination &destination /*= {Type::NONE}*/) { /* assert(_object); if (_object->_fromPacked && _object->_destination) { @@ -479,9 +481,9 @@ const Bytes Packet::get_hashable_part() const { assert(_object); Bytes hashable_part; hashable_part << (uint8_t)(_object->_raw.data()[0] & 0b00001111); - if (_object->_header_type == Packet::HEADER_2) { + if (_object->_header_type == HEADER_2) { //hashable_part += self.raw[(RNS.Identity.TRUNCATED_HASHLENGTH//8)+2:] - hashable_part << _object->_raw.mid((Identity::TRUNCATED_HASHLENGTH/8)+2); + hashable_part << _object->_raw.mid((Type::Identity::TRUNCATED_HASHLENGTH/8)+2); } else { //hashable_part += self.raw[2:]; @@ -517,14 +519,14 @@ std::string Packet::debugString() const { dump += "data: " + _object->_data.toHex() + "\n"; dump += " length: " + std::to_string(_object->_data.size()) + "\n"; if (_object->_encrypted && _object->_raw.size() > 0) { - size_t header_len = Reticulum::HEADER_MINSIZE; + size_t header_len = Type::Reticulum::HEADER_MINSIZE; if (_object->_header_type == HEADER_2) { - header_len = Reticulum::HEADER_MAXSIZE; + header_len = Type::Reticulum::HEADER_MAXSIZE; } dump += "encrypted:\n"; dump += " header: " + _object->_raw.left(header_len).toHex() + "\n"; - dump += " key: " + _object->_raw.mid(header_len, Identity::KEYSIZE/8/2).toHex() + "\n"; - Bytes ciphertext(_object->_raw.mid(header_len+Identity::KEYSIZE/8/2)); + dump += " key: " + _object->_raw.mid(header_len, Type::Identity::KEYSIZE/8/2).toHex() + "\n"; + Bytes ciphertext(_object->_raw.mid(header_len+Type::Identity::KEYSIZE/8/2)); dump += " ciphertext: " + ciphertext.toHex() + "\n"; dump += " length: " + std::to_string(ciphertext.size()) + "\n"; dump += " iv: " + ciphertext.left(16).toHex() + "\n"; diff --git a/src/Packet.h b/src/Packet.h index 51ef17f..0ec5258 100644 --- a/src/Packet.h +++ b/src/Packet.h @@ -2,12 +2,12 @@ #include "Transport.h" #include "Reticulum.h" -#include "Link.h" +//#include "Link.h" #include "Identity.h" #include "Destination.h" -#include "None.h" #include "Interfaces/Interface.h" #include "Utilities/OS.h" +#include "Type.h" #include #include @@ -43,23 +43,8 @@ namespace RNS { friend class PacketReceipt; }; - enum NoneConstructor { - NONE - }; - - // Receipt status constants - enum Status { - FAILED = 0x00, - SENT = 0x01, - DELIVERED = 0x02, - CULLED = 0xFF - }; - - static const uint16_t EXPL_LENGTH = Identity::HASHLENGTH / 8 + Identity::SIGLENGTH / 8; - static const uint16_t IMPL_LENGTH = Identity::SIGLENGTH / 8; - public: - PacketReceipt(NoneConstructor none) {} + PacketReceipt(Type::NoneConstructor none) {} PacketReceipt(const PacketReceipt &packet_receipt) : _object(packet_receipt._object) {} PacketReceipt() : _object(new Object()) {} PacketReceipt(const Packet &packet) {} @@ -119,14 +104,14 @@ namespace RNS { Object() {} virtual ~Object() {} private: - bool _sent = true; - uint64_t _sent_at = Utilities::OS::time(); - bool _proved = false; - Status _status = SENT; - Destination _destination = Destination::NONE; + bool _sent = true; + uint64_t _sent_at = Utilities::OS::time(); + bool _proved = false; + Type::PacketReceipt::Status _status = Type::PacketReceipt::SENT; + Destination _destination = {Type::NONE}; Callbacks _callbacks; - uint64_t _concluded_at = 0; - //zPacket _proof_packet; + uint64_t _concluded_at = 0; + //z Packet _proof_packet; int16_t _timeout = 0; friend class PacketReceipt; }; @@ -138,81 +123,18 @@ namespace RNS { class Packet { public: - enum NoneConstructor { - NONE - }; - - // Packet types - enum types { - DATA = 0x00, // Data packets - ANNOUNCE = 0x01, // Announces - LINKREQUEST = 0x02, // Link requests - PROOF = 0x03, // Proofs - }; - - // Header types - enum header_types { - HEADER_1 = 0x00, // Normal header format - HEADER_2 = 0x01, // Header format used for packets in transport - }; - - // Packet context types - enum context_types { - CONTEXT_NONE = 0x00, // Generic data packet - RESOURCE = 0x01, // Packet is part of a resource - RESOURCE_ADV = 0x02, // Packet is a resource advertisement - RESOURCE_REQ = 0x03, // Packet is a resource part request - RESOURCE_HMU = 0x04, // Packet is a resource hashmap update - RESOURCE_PRF = 0x05, // Packet is a resource proof - RESOURCE_ICL = 0x06, // Packet is a resource initiator cancel message - RESOURCE_RCL = 0x07, // Packet is a resource receiver cancel message - CACHE_REQUEST = 0x08, // Packet is a cache request - REQUEST = 0x09, // Packet is a request - RESPONSE = 0x0A, // Packet is a response to a request - PATH_RESPONSE = 0x0B, // Packet is a response to a path request - COMMAND = 0x0C, // Packet is a command - COMMAND_STATUS = 0x0D, // Packet is a status of an executed command - CHANNEL = 0x0E, // Packet contains link channel data - KEEPALIVE = 0xFA, // Packet is a keepalive packet - LINKIDENTIFY = 0xFB, // Packet is a link peer identification proof - LINKCLOSE = 0xFC, // Packet is a link close message - LINKPROOF = 0xFD, // Packet is a link packet proof - LRRTT = 0xFE, // Packet is a link request round-trip time measurement - LRPROOF = 0xFF, // Packet is a link request proof - }; - - // This is used to calculate allowable - // payload sizes - static const uint16_t HEADER_MAXSIZE = Reticulum::HEADER_MAXSIZE; - static const uint16_t MDU = Reticulum::MDU; - - // With an MTU of 500, the maximum of data we can - // send in a single encrypted packet is given by - // the below calculation; 383 bytes. - //static const uint16_t ENCRYPTED_MDU = floor((Reticulum::MDU-Identity::FERNET_OVERHEAD-Identity::KEYSIZE/16)/Identity::AES128_BLOCKSIZE)*Identity::AES128_BLOCKSIZE - 1; - //static const uint16_t ENCRYPTED_MDU; - static const uint16_t ENCRYPTED_MDU = ((Reticulum::MDU-Identity::FERNET_OVERHEAD-Identity::KEYSIZE/16)/Identity::AES128_BLOCKSIZE)*Identity::AES128_BLOCKSIZE - 1; - // The maximum size of the payload data in a single encrypted packet - static const uint16_t PLAIN_MDU = MDU; - // The maximum size of the payload data in a single unencrypted packet - - static const uint8_t TIMEOUT_PER_HOP = Reticulum::DEFAULT_PER_HOP_TIMEOUT; - - //static constexpr const uint8_t EMPTY_DESTINATION[Reticulum::DESTINATION_LENGTH] = {0}; - uint8_t EMPTY_DESTINATION[Reticulum::DESTINATION_LENGTH] = {0}; + //static constexpr const uint8_t EMPTY_DESTINATION[Type::Reticulum::DESTINATION_LENGTH] = {0}; + uint8_t EMPTY_DESTINATION[Type::Reticulum::DESTINATION_LENGTH] = {0}; public: - Packet(NoneConstructor none) { - extreme("Packet NONE object created"); - } - Packet(RNS::NoneConstructor none) { + Packet(Type::NoneConstructor none) { extreme("Packet NONE object created"); } Packet(const Packet &packet) : _object(packet._object) { extreme("Packet object copy created"); } - Packet(const Destination &destination, const Interface &attached_interface, const Bytes &data, types packet_type = DATA, context_types context = CONTEXT_NONE, Transport::types transport_type = Transport::BROADCAST, header_types header_type = HEADER_1, const Bytes &transport_id = Bytes::NONE, bool create_receipt = true); - Packet(const Destination &destination, const Bytes &data, types packet_type = DATA, context_types context = CONTEXT_NONE, Transport::types transport_type = Transport::BROADCAST, header_types header_type = HEADER_1, const Bytes &transport_id = Bytes::NONE, bool create_receipt = true) : Packet(destination, Interface::NONE, data, packet_type, context, transport_type, header_type, transport_id, create_receipt) {} + Packet(const Destination &destination, const Interface &attached_interface, const Bytes &data, Type::Packet::types packet_type = Type::Packet::DATA, Type::Packet::context_types context = Type::Packet::CONTEXT_NONE, Type::Transport::types transport_type = Type::Transport::BROADCAST, Type::Packet::header_types header_type = Type::Packet::HEADER_1, const Bytes &transport_id = {Bytes::NONE}, bool create_receipt = true); + Packet(const Destination &destination, const Bytes &data, Type::Packet::types packet_type = Type::Packet::DATA, Type::Packet::context_types context = Type::Packet::CONTEXT_NONE, Type::Transport::types transport_type = Type::Transport::BROADCAST, Type::Packet::header_types header_type = Type::Packet::HEADER_1, const Bytes &transport_id = {Bytes::NONE}, bool create_receipt = true) : Packet(destination, {Type::NONE}, data, packet_type, context, transport_type, header_type, transport_id, create_receipt) {} virtual ~Packet(); inline Packet& operator = (const Packet &packet) { @@ -242,7 +164,7 @@ namespace RNS { bool unpack(); bool send(); bool resend(); - void prove(const Destination &destination = Destination::NONE); + void prove(const Destination &destination = {Type::NONE}); void update_hash(); const Bytes get_hash() const; const Bytes getTruncatedHash() const; @@ -257,11 +179,11 @@ namespace RNS { inline const Interface &attached_interface() const { assert(_object); return _object->_attached_interface; } inline const Interface &receiving_interface() const { assert(_object); return _object->_receiving_interface; } inline void receiving_interface(const Interface &receiving_interface) { assert(_object); _object->_receiving_interface = receiving_interface; } - inline header_types header_type() const { assert(_object); return _object->_header_type; } - inline Transport::types transport_type() const { assert(_object); return _object->_transport_type; } - inline Destination::types destination_type() const { assert(_object); return _object->_destination_type; } - inline types packet_type() const { assert(_object); return _object->_packet_type; } - inline context_types context() const { assert(_object); return _object->_context; } + inline Type::Packet::header_types header_type() const { assert(_object); return _object->_header_type; } + inline Type::Transport::types transport_type() const { assert(_object); return _object->_transport_type; } + inline Type::Destination::types destination_type() const { assert(_object); return _object->_destination_type; } + inline Type::Packet::types packet_type() const { assert(_object); return _object->_packet_type; } + inline Type::Packet::context_types context() const { assert(_object); return _object->_context; } inline bool sent() const { assert(_object); return _object->_sent; } inline void sent(bool sent) { assert(_object); _object->_sent = sent; } inline time_t sent_at() const { assert(_object); return _object->_sent_at; } @@ -289,17 +211,17 @@ namespace RNS { Object(const Destination &destination, const Interface &attached_interface) : _destination(destination), _attached_interface(attached_interface) {} virtual ~Object() {} private: - Destination _destination = {Destination::NONE}; - Link _link = {Link::NONE}; + Destination _destination = {Type::NONE}; + Link _link = {Type::NONE}; - Interface _attached_interface = {Interface::NONE}; - Interface _receiving_interface = {Interface::NONE}; + Interface _attached_interface = {Type::NONE}; + Interface _receiving_interface = {Type::NONE}; - header_types _header_type = HEADER_1; - Transport::types _transport_type = Transport::BROADCAST; - Destination::types _destination_type = Destination::SINGLE; - types _packet_type = DATA; - context_types _context = CONTEXT_NONE; + Type::Packet::header_types _header_type = Type::Packet::HEADER_1; + Type::Transport::types _transport_type = Type::Transport::BROADCAST; + Type::Destination::types _destination_type = Type::Destination::SINGLE; + Type::Packet::types _packet_type = Type::Packet::DATA; + Type::Packet::context_types _context = Type::Packet::CONTEXT_NONE; uint8_t _flags = 0; uint8_t _hops = 0; @@ -312,7 +234,7 @@ namespace RNS { bool _encrypted = false; // whether data is encrytpted PacketReceipt _receipt; - uint16_t _mtu = Reticulum::MTU; + uint16_t _mtu = Type::Reticulum::MTU; time_t _sent_at = 0; float _rssi = 0.0; diff --git a/src/Reticulum.cpp b/src/Reticulum.cpp index c47dccd..b93d01a 100644 --- a/src/Reticulum.cpp +++ b/src/Reticulum.cpp @@ -6,6 +6,12 @@ #include using namespace RNS; +using namespace RNS::Type::Reticulum; + +/*static*/ bool Reticulum::__transport_enabled = false; +/*static*/ bool Reticulum::__use_implicit_proof = true; +/*static*/ bool Reticulum::__allow_probes = false; +/*static*/ bool Reticulum::panic_on_interface_error = false; /* Initialises and starts a Reticulum instance. This must be diff --git a/src/Reticulum.h b/src/Reticulum.h index 7e1ec2b..eb529cf 100644 --- a/src/Reticulum.h +++ b/src/Reticulum.h @@ -1,7 +1,7 @@ #pragma once #include "Log.h" -#include "None.h" +#include "Type.h" #include #include @@ -12,85 +12,13 @@ namespace RNS { class Reticulum { public: - enum NoneConstructor { - NONE - }; - - // Future minimum will probably be locked in at 251 bytes to support - // networks with segments of different MTUs. Absolute minimum is 219. - static const uint16_t MTU = 500; - /* - The MTU that Reticulum adheres to, and will expect other peers to - adhere to. By default, the MTU is 507 bytes. In custom RNS network - implementations, it is possible to change this value, but doing so will - completely break compatibility with all other RNS networks. An identical - MTU is a prerequisite for peers to communicate in the same network. - - Unless you really know what you are doing, the MTU should be left at - the default value. - */ - - static const uint16_t MAX_QUEUED_ANNOUNCES = 16384; - static const uint32_t QUEUED_ANNOUNCE_LIFE = 60*60*24; - - static const uint8_t ANNOUNCE_CAP = 2; - /* - The maximum percentage of interface bandwidth that, at any given time, - may be used to propagate announces. If an announce was scheduled for - broadcasting on an interface, but doing so would exceed the allowed - bandwidth allocation, the announce will be queued for transmission - when there is bandwidth available. - - Reticulum will always prioritise propagating announces with fewer - hops, ensuring that distant, large networks with many peers on fast - links don't overwhelm the capacity of smaller networks on slower - mediums. If an announce remains queued for an extended amount of time, - it will eventually be dropped. - - This value will be applied by default to all created interfaces, - but it can be configured individually on a per-interface basis. - */ - - static const uint16_t MINIMUM_BITRATE = 500; - - // TODO: To reach the 300bps level without unreasonably impacting - // performance on faster links, we need a mechanism for setting - // this value more intelligently. One option could be inferring it - // from interface speed, but a better general approach would most - // probably be to let Reticulum somehow continously build a map of - // per-hop latencies and use this map for the timeout calculation. - static const uint8_t DEFAULT_PER_HOP_TIMEOUT = 6; - - static const uint16_t HASHLENGTH = 256; // In bits - // Length of truncated hashes in bits. - static const uint16_t TRUNCATED_HASHLENGTH = 128; // In bits - - static const uint16_t HEADER_MINSIZE = 2+1+(TRUNCATED_HASHLENGTH/8)*1; // In bytes - static const uint16_t HEADER_MAXSIZE = 2+1+(TRUNCATED_HASHLENGTH/8)*2; // In bytes - static const uint16_t IFAC_MIN_SIZE = 1; - //zIFAC_SALT = bytes.fromhex("adf54d882c9a9b80771eb4995d702d4a3e733391b2a0f53f416d9f907e55cff8") - - static const uint16_t MDU = MTU - HEADER_MAXSIZE - IFAC_MIN_SIZE; - - static const uint32_t RESOURCE_CACHE = 24*60*60; - static const uint16_t JOB_INTERVAL = 5*60; - static const uint16_t CLEAN_INTERVAL = 15*60; - static const uint16_t PERSIST_INTERVAL = 60*60*12; - static const uint16_t GRACIOUS_PERSIST_INTERVAL = 60*5; - - static const uint8_t DESTINATION_LENGTH = TRUNCATED_HASHLENGTH/8; // In bytes - - static const bool __transport_enabled = false; - static const bool __use_implicit_proof = true; - static const bool __allow_probes = false; - - static const bool panic_on_interface_error = false; + static bool __transport_enabled; + static bool __use_implicit_proof; + static bool __allow_probes; + static bool panic_on_interface_error; public: - Reticulum(NoneConstructor none) { - extreme("Reticulum NONE object created"); - } - Reticulum(RNS::NoneConstructor none) { + Reticulum(Type::NoneConstructor none) { extreme("Reticulum NONE object created"); } Reticulum(const Reticulum &reticulum) : _object(reticulum._object) { diff --git a/src/Test/TestBytes.cpp b/src/Test/TestBytes.cpp index 82250ed..4e149e2 100644 --- a/src/Test/TestBytes.cpp +++ b/src/Test/TestBytes.cpp @@ -183,7 +183,7 @@ void testBytes() { // test creating bytes from NONE { - RNS::Bytes bytes(RNS::Bytes::NONE); + RNS::Bytes bytes({RNS::Bytes::NONE}); assert(!bytes); assert(bytes.size() == 0); assert(bytes.data() == nullptr); diff --git a/src/Test/TestCrypto.cpp b/src/Test/TestCrypto.cpp index 7d44371..f71dbc4 100644 --- a/src/Test/TestCrypto.cpp +++ b/src/Test/TestCrypto.cpp @@ -18,7 +18,7 @@ void testCrypto() { RNS::Identity identity; - RNS::Destination destination(identity, RNS::Destination::IN, RNS::Destination::SINGLE, "appname", "aspects"); + RNS::Destination destination(identity, RNS::Type::Destination::IN, RNS::Type::Destination::SINGLE, "appname", "aspects"); //assert(encryptionPrivateKey().toHex().compare("") == ); //assert(signingPrivateKey().toHex().compare("") == ); //assert(encryptionPublicKey().toHex().compare("") == ); diff --git a/src/Test/TestReference.cpp b/src/Test/TestReference.cpp index d183902..55d9dec 100644 --- a/src/Test/TestReference.cpp +++ b/src/Test/TestReference.cpp @@ -10,7 +10,7 @@ void testReference() { RNS::Reticulum reticulum_default; assert(reticulum_default); - RNS::Reticulum reticulum_none(RNS::Reticulum::NONE); + RNS::Reticulum reticulum_none({RNS::Type::NONE}); assert(!reticulum_none); RNS::Reticulum reticulum_default_copy(reticulum_default); diff --git a/src/Transport.cpp b/src/Transport.cpp index b2dd6b4..0e816a9 100644 --- a/src/Transport.cpp +++ b/src/Transport.cpp @@ -54,8 +54,8 @@ using namespace RNS::Utilities; /*static*/ uint64_t Transport::_tables_last_culled = 0; /*static*/ uint32_t Transport::_tables_cull_interval = 5000; -/*static*/ Reticulum Transport::_owner(Reticulum::NONE); -/*static*/ Identity Transport::_identity(Identity::NONE); +/*static*/ Reticulum Transport::_owner({Type::NONE}); +/*static*/ Identity Transport::_identity({Type::NONE}); /*static*/ void Transport::start(const Reticulum &reticulum_instance) { _jobs_running = true; @@ -634,7 +634,7 @@ using namespace RNS::Utilities; // Check if we have a known path for the destination in the path table //if packet.packet_type != RNS.Packet.ANNOUNCE and packet.destination.type != RNS.Destination.PLAIN and packet.destination.type != RNS.Destination.GROUP and packet.destination_hash in Transport.destination_table: - if (packet.packet_type() != Packet::ANNOUNCE && packet.destination().type() != Destination::PLAIN && packet.destination().type() != Destination::GROUP && _destination_table.find(packet.destination_hash()) != _destination_table.end()) { + if (packet.packet_type() != Type::Packet::ANNOUNCE && packet.destination().type() != Type::Destination::PLAIN && packet.destination().type() != Type::Destination::GROUP && _destination_table.find(packet.destination_hash()) != _destination_table.end()) { extreme("Transport::outbound: Path to destination is known"); //outbound_interface = Transport.destination_table[packet.destination_hash][5] DestinationEntry destination_entry = (*_destination_table.find(packet.destination_hash())).second; @@ -648,10 +648,10 @@ using namespace RNS::Utilities; //if Transport.destination_table[packet.destination_hash][2] > 1: if (destination_entry._hops > 1) { extreme("Forwarding packet to next closest interface..."); - if (packet.header_type() == Packet::HEADER_1) { + if (packet.header_type() == Type::Packet::HEADER_1) { // Insert packet into transport //new_flags = (RNS.Packet.HEADER_2) << 6 | (Transport.TRANSPORT) << 4 | (packet.flags & 0b00001111) - uint8_t new_flags = (Packet::HEADER_2) << 6 | (Transport::TRANSPORT) << 4 | (packet.flags() & 0b00001111); + uint8_t new_flags = (Type::Packet::HEADER_2) << 6 | (Type::Transport::TRANSPORT) << 4 | (packet.flags() & 0b00001111); Bytes new_raw; //new_raw = struct.pack("!B", new_flags) new_raw << new_flags; @@ -678,10 +678,10 @@ using namespace RNS::Utilities; //elif Transport.destination_table[packet.destination_hash][2] == 1 and Transport.owner.is_connected_to_shared_instance: else if (destination_entry._hops == 1 && _owner.is_connected_to_shared_instance()) { extreme("Transport::outbound: Sending packet for directly connected interface to shared instance..."); - if (packet.header_type() == Packet::HEADER_1) { + if (packet.header_type() == Type::Packet::HEADER_1) { // Insert packet into transport //new_flags = (RNS.Packet.HEADER_2) << 6 | (Transport.TRANSPORT) << 4 | (packet.flags & 0b00001111) - uint8_t new_flags = (Packet::HEADER_2) << 6 | (Transport::TRANSPORT) << 4 | (packet.flags() & 0b00001111); + uint8_t new_flags = (Type::Packet::HEADER_2) << 6 | (Type::Transport::TRANSPORT) << 4 | (packet.flags() & 0b00001111); Bytes new_raw; //new_raw = struct.pack("!B", new_flags) new_raw << new_flags; @@ -719,8 +719,8 @@ using namespace RNS::Utilities; if (interface.OUT()) { bool should_transmit = true; - if (packet.destination().type() == Destination::LINK) { - if (packet.destination().status() == Link::CLOSED) { + if (packet.destination().type() == Type::Destination::LINK) { + if (packet.destination().status() == Type::Link::CLOSED) { should_transmit = false; } // CBA Destination has no member attached_interface @@ -733,16 +733,16 @@ using namespace RNS::Utilities; should_transmit = false; } - if (packet.packet_type() == Packet::ANNOUNCE) { + if (packet.packet_type() == Type::Packet::ANNOUNCE) { if (!packet.attached_interface()) { extreme("Transport::outbound: Packet has no attached interface"); - if (interface.mode() == Interface::MODE_ACCESS_POINT) { + if (interface.mode() == Type::Interface::MODE_ACCESS_POINT) { extreme("Blocking announce broadcast on " + interface.toString() + " due to AP mode"); should_transmit = false; } - else if (interface.mode() == Interface::MODE_ROAMING) { + else if (interface.mode() == Type::Interface::MODE_ROAMING) { //local_destination = next((d for d in Transport.destinations if d.hash == packet.destination_hash), None) - //Destination local_destination(Destination::NONE); + //Destination local_destination({Type::NONE}); bool found_local = false; for (auto &destination : _destinations) { if (destination.hash() == packet.destination_hash()) { @@ -759,34 +759,34 @@ using namespace RNS::Utilities; else { const Interface &from_interface = next_hop_interface(packet.destination_hash()); //if from_interface == None or not hasattr(from_interface, "mode"): - if (!from_interface || from_interface.mode() == Interface::MODE_NONE) { + if (!from_interface || from_interface.mode() == Type::Interface::MODE_NONE) { should_transmit = false; if (!from_interface) { extreme("Blocking announce broadcast on " + interface.toString() + " since next hop interface doesn't exist"); } - else if (from_interface.mode() == Interface::MODE_NONE) { + else if (from_interface.mode() == Type::Interface::MODE_NONE) { extreme("Blocking announce broadcast on " + interface.toString() + " since next hop interface has no mode configured"); } } else { - if (from_interface.mode() == Interface::MODE_ROAMING) { + if (from_interface.mode() == Type::Interface::MODE_ROAMING) { extreme("Blocking announce broadcast on " + interface.toString() + " due to roaming-mode next-hop interface"); should_transmit = false; } - else if (from_interface.mode() == Interface::MODE_BOUNDARY) { + else if (from_interface.mode() == Type::Interface::MODE_BOUNDARY) { extreme("Blocking announce broadcast on " + interface.toString() + " due to boundary-mode next-hop interface"); should_transmit = false; } } } } - else if (interface.mode() == Interface::MODE_BOUNDARY) { + else if (interface.mode() == Type::Interface::MODE_BOUNDARY) { //local_destination = next((d for d in Transport.destinations if d.hash == packet.destination_hash), None) // next and filter pattern? // next(iterable, default) // list comprehension: [x for x in xyz if x in a] // CBA TODO confirm that above pattern just selects the first matching destination - //Destination local_destination(Destination::NONE); + //Destination local_destination({Typeestination::NONE}); bool found_local = false; for (auto &destination : _destinations) { if (destination.hash() == packet.destination_hash()) { @@ -802,17 +802,17 @@ using namespace RNS::Utilities; } else { const Interface &from_interface = next_hop_interface(packet.destination_hash()); - if (!from_interface || from_interface.mode() == Interface::MODE_NONE) { + if (!from_interface || from_interface.mode() == Type::Interface::MODE_NONE) { should_transmit = false; if (!from_interface) { extreme("Blocking announce broadcast on " + interface.toString() + " since next hop interface doesn't exist"); } - else if (from_interface.mode() == Interface::MODE_NONE) { + else if (from_interface.mode() == Type::Interface::MODE_NONE) { extreme("Blocking announce broadcast on " + interface.toString() + " since next hop interface has no mode configured"); } } else { - if (from_interface.mode() == Interface::MODE_ROAMING) { + if (from_interface.mode() == Type::Interface::MODE_ROAMING) { extreme("Blocking announce broadcast on " + interface.toString() + " due to roaming-mode next-hop interface"); should_transmit = false; } @@ -844,7 +844,7 @@ using namespace RNS::Utilities; } else { should_transmit = false; - if (interface.announce_queue().size() < Reticulum::MAX_QUEUED_ANNOUNCES) { + if (interface.announce_queue().size() < Type::Reticulum::MAX_QUEUED_ANNOUNCES) { bool should_queue = true; for (auto &entry : interface.announce_queue()) { if (entry._destination == packet.destination_hash()) { @@ -947,13 +947,13 @@ using namespace RNS::Utilities; // Don't generate receipt if it has been explicitly disabled if (packet.create_receipt() && // Only generate receipts for DATA packets - packet.packet_type() == Packet::DATA && + packet.packet_type() == Type::Packet::DATA && // Don't generate receipts for PLAIN destinations - packet.destination().type() != Destination::PLAIN && + packet.destination().type() != Type::Destination::PLAIN && // Don't generate receipts for link-related packets - !(packet.context() >= Packet::KEEPALIVE && packet.context() <= Packet::LRPROOF) && + !(packet.context() >= Type::Packet::KEEPALIVE && packet.context() <= Type::Packet::LRPROOF) && // Don't generate receipts for resource packets - !(packet.context() >= Packet::RESOURCE && packet.context() <= Packet::RESOURCE_RCL)) { + !(packet.context() >= Type::Packet::RESOURCE && packet.context() <= Type::Packet::RESOURCE_RCL)) { PacketReceipt receipt(packet); packet.receipt(receipt); @@ -971,27 +971,27 @@ using namespace RNS::Utilities; // TODO: Think long and hard about this. // Is it even strictly necessary with the current // transport rules? - if (packet.context() == Packet::KEEPALIVE) { + if (packet.context() == Type::Packet::KEEPALIVE) { return true; } - if (packet.context() == Packet::RESOURCE_REQ) { + if (packet.context() == Type::Packet::RESOURCE_REQ) { return true; } - if (packet.context() == Packet::RESOURCE_PRF) { + if (packet.context() == Type::Packet::RESOURCE_PRF) { return true; } - if (packet.context() == Packet::RESOURCE) { + if (packet.context() == Type::Packet::RESOURCE) { return true; } - if (packet.context() == Packet::CACHE_REQUEST) { + if (packet.context() == Type::Packet::CACHE_REQUEST) { return true; } - if (packet.context() == Packet::CHANNEL) { + if (packet.context() == Type::Packet::CHANNEL) { return true; } - if (packet.destination_type() == Destination::PLAIN) { - if (packet.packet_type() != Packet::ANNOUNCE) { + if (packet.destination_type() == Type::Destination::PLAIN) { + if (packet.packet_type() != Type::Packet::ANNOUNCE) { if (packet.hops() > 1) { debug("Dropped PLAIN packet " + packet.packet_hash().toHex() + " with " + std::to_string(packet.hops()) + " hops"); return false; @@ -1006,8 +1006,8 @@ using namespace RNS::Utilities; } } - if (packet.destination_type() == Destination::GROUP) { - if (packet.packet_type() != Packet::ANNOUNCE) { + if (packet.destination_type() == Type::Destination::GROUP) { + if (packet.packet_type() != Type::Packet::ANNOUNCE) { if (packet.hops() > 1) { debug("Dropped GROUP packet " + packet.packet_hash().toHex() + " with " + std::to_string(packet.hops()) + " hops"); return false; @@ -1026,8 +1026,8 @@ using namespace RNS::Utilities; return true; } else { - if (packet.packet_type() == Packet::ANNOUNCE) { - if (packet.destination_type() == Destination::SINGLE) { + if (packet.packet_type() == Type::Packet::ANNOUNCE) { + if (packet.destination_type() == Type::Destination::SINGLE) { return true; } else { @@ -1041,7 +1041,7 @@ using namespace RNS::Utilities; return false; } -/*static*/ void Transport::inbound(const Bytes &raw, const Interface &interface /*= Interface::NONE*/) { +/*static*/ void Transport::inbound(const Bytes &raw, const Interface &interface /*= {Type::NONE}*/) { extreme("Transport::inbound()"); /* // If interface access codes are enabled, @@ -1122,7 +1122,7 @@ using namespace RNS::Utilities; _jobs_locked = true; - Packet packet(Destination::NONE, raw); + Packet packet({Type::NONE}, raw); if (!packet.unpack()) { warning("Transport::inbound: Pscket unpack failed!"); return; @@ -1178,7 +1178,7 @@ using namespace RNS::Utilities; //for_local_client_link |= (packet.packet_type != RNS.Packet.ANNOUNCE) and (packet.destination_hash in Transport.link_table and Transport.link_table[packet.destination_hash][2] in Transport.local_client_interfaces) bool for_local_client = false; bool for_local_client_link = false; - if (packet.packet_type() != Packet::ANNOUNCE) { + if (packet.packet_type() != Type::Packet::ANNOUNCE) { auto destination_iter = _destination_table.find(packet.destination_hash()); if (destination_iter != _destination_table.end()) { DestinationEntry destination_entry = (*destination_iter).second; @@ -1211,7 +1211,7 @@ using namespace RNS::Utilities; // directly on all attached interfaces, since they are // never injected into transport. if (_control_hashes.find(packet.destination_hash()) == _control_hashes.end()) { - if (packet.destination_type() == Destination::PLAIN && packet.transport_type() == Transport::BROADCAST) { + if (packet.destination_type() == Type::Destination::PLAIN && packet.transport_type() == Type::Transport::BROADCAST) { // Send to all interfaces except the originator if (from_local_client) { for (const Interface &interface : _interfaces) { @@ -1252,7 +1252,7 @@ using namespace RNS::Utilities; // If this is a cache request, and we can fullfill // it, do so and stop processing. Otherwise resume // normal processing. - if (packet.context() == Packet::CACHE_REQUEST) { + if (packet.context() == Type::Packet::CACHE_REQUEST) { if (cache_request_packet(packet)) { extreme("Transport::inbound: Cached packet"); return; @@ -1262,7 +1262,7 @@ using namespace RNS::Utilities; // If the packet is in transport, check whether we // are the designated next hop, and process it // accordingly if we are. - if (packet.transport_id() && packet.packet_type() != Packet::ANNOUNCE) { + if (packet.transport_id() && packet.packet_type() != Type::Packet::ANNOUNCE) { if (packet.transport_id() == _identity.hash()) { auto destination_iter = _destination_table.find(packet.destination_hash()); if (destination_iter != _destination_table.end()) { @@ -1280,18 +1280,18 @@ using namespace RNS::Utilities; //new_raw += next_hop new_raw << next_hop; //new_raw += packet.raw[(RNS.Identity.TRUNCATED_HASHLENGTH//8)+2:] - new_raw << packet.raw().mid((Identity::TRUNCATED_HASHLENGTH/8)+2); + new_raw << packet.raw().mid((Type::Identity::TRUNCATED_HASHLENGTH/8)+2); } else if (remaining_hops == 1) { // Strip transport headers and transmit //new_flags = (RNS.Packet.HEADER_1) << 6 | (Transport.BROADCAST) << 4 | (packet.flags & 0b00001111) - uint8_t new_flags = (Packet::HEADER_1) << 6 | (Transport::BROADCAST) << 4 | (packet.flags() & 0b00001111); + uint8_t new_flags = (Type::Packet::HEADER_1) << 6 | (Type::Transport::BROADCAST) << 4 | (packet.flags() & 0b00001111); //new_raw = struct.pack("!B", new_flags) new_raw << new_flags; //new_raw += struct.pack("!B", packet.hops) new_raw << packet.hops(); //new_raw += packet.raw[(RNS.Identity.TRUNCATED_HASHLENGTH//8)+2:] - new_raw << packet.raw().mid((Identity::TRUNCATED_HASHLENGTH/8)+2); + new_raw << packet.raw().mid((Type::Identity::TRUNCATED_HASHLENGTH/8)+2); } else if (remaining_hops == 0) { // Just increase hop count and transmit @@ -1305,9 +1305,9 @@ using namespace RNS::Utilities; Interface &outbound_interface = destination_entry._receiving_interface; - if (packet.packet_type() == Packet::LINKREQUEST) { + if (packet.packet_type() == Type::Packet::LINKREQUEST) { uint64_t now = OS::time(); - uint64_t proof_timeout = now + Link::ESTABLISHMENT_TIMEOUT_PER_HOP*1000 * std::max((uint8_t)1, remaining_hops); + uint64_t proof_timeout = now + Type::Link::ESTABLISHMENT_TIMEOUT_PER_HOP*1000 * std::max((uint8_t)1, remaining_hops); LinkEntry link_entry( now, next_hop, @@ -1343,14 +1343,14 @@ using namespace RNS::Utilities; // Link transport handling. Directs packets according // to entries in the link tables - if (packet.packet_type() != Packet::ANNOUNCE && packet.packet_type() != Packet::LINKREQUEST && packet.context() == Packet::LRPROOF) { + if (packet.packet_type() != Type::Packet::ANNOUNCE && packet.packet_type() != Type::Packet::LINKREQUEST && packet.context() == Type::Packet::LRPROOF) { auto link_iter = _link_table.find(packet.destination_hash()); if (link_iter != _link_table.end()) { LinkEntry link_entry = (*link_iter).second; // If receiving and outbound interface is // the same for this link, direction doesn't // matter, and we simply send the packet on. - Interface outbound_interface(Interface::NONE); + Interface outbound_interface({Type::NONE}); if (link_entry._outbound_interface == link_entry._receiving_interface) { // But check that taken hops matches one // of the expectede values. @@ -1397,11 +1397,11 @@ using namespace RNS::Utilities; // Announce handling. Handles logic related to incoming // announces, queueing rebroadcasts of these, and removal // of queued announce rebroadcasts once handed to the next node. - if (packet.packet_type() == Packet::ANNOUNCE) { + if (packet.packet_type() == Type::Packet::ANNOUNCE) { extreme("Transport::inbound: Packet is ANNOUNCE"); Bytes received_from; //p local_destination = next((d for d in Transport.destinations if d.hash == packet.destination_hash), None) - //Destination local_destination(Destination::NONE); + //Destination local_destination({Type::NONE}); bool found_local = false; for (auto &destination : _destinations) { if (destination.hash() == packet.destination_hash()) { @@ -1585,15 +1585,15 @@ using namespace RNS::Utilities; uint8_t announce_hops = packet.hops(); uint8_t local_rebroadcasts = 0; bool block_rebroadcasts = false; - Interface attached_interface = Interface::NONE; + Interface attached_interface = {Type::NONE}; uint64_t retransmit_timeout = now + (RNS::Cryptography::random() * Transport::PATHFINDER_RW); uint64_t expires; - if (packet.receiving_interface().mode() == Interface::MODE_ACCESS_POINT) { + if (packet.receiving_interface().mode() == Type::Interface::MODE_ACCESS_POINT) { expires = now + Transport::AP_PATH_TIME; } - else if (packet.receiving_interface().mode() == Interface::MODE_ROAMING) { + else if (packet.receiving_interface().mode() == Type::Interface::MODE_ROAMING) { expires = now + Transport::ROAMING_PATH_TIME; } else { @@ -1603,7 +1603,7 @@ using namespace RNS::Utilities; std::set random_blobs; random_blobs.insert(random_blob); - if (Reticulum::transport_enabled() || from_local_client(packet) && packet.context() != Packet::PATH_RESPONSE) { + if (Reticulum::transport_enabled() || from_local_client(packet) && packet.context() != Type::Packet::PATH_RESPONSE) { // Insert announce into announce table for retransmission if (rate_blocked) { @@ -1630,7 +1630,7 @@ using namespace RNS::Utilities; } } // TODO: Check from_local_client once and store result - else if (from_local_client(packet) && packet.context() == Packet::PATH_RESPONSE) { + else if (from_local_client(packet) && packet.context() == Type::Packet::PATH_RESPONSE) { // If this is a path response from a local client, // check if any external interfaces have pending // path requests. @@ -1661,7 +1661,7 @@ using namespace RNS::Utilities; announce_destination = Destination(announce_identity, Destination.OUT, Destination.SINGLE, "unknown", "unknown"); announce_destination.hash(packet.destination_hash()); announce_destination.hexhash = announce_destination.hash().toHex(); - announce_context = Packet::NONE; + announce_context = {Type::NONE}; announce_data = packet.data(); // TODO: Shouldn't the context be PATH_RESPONSE in the first case here? @@ -1671,7 +1671,7 @@ using namespace RNS::Utilities; Packet new_announce( announce_destination, announce_data, - Packet::ANNOUNCE, + Type::Packet::ANNOUNCE, context = announce_context, header_type = RNS.Packet.HEADER_2, transport_type = Transport.TRANSPORT, @@ -1690,7 +1690,7 @@ using namespace RNS::Utilities; Packet new_announce( announce_destination, announce_data, - Packet::ANNOUNCE, + Type::Packet::ANNOUNCE, context = announce_context, header_type = RNS.Packet.HEADER_2, transport_type = Transport.TRANSPORT, @@ -1720,16 +1720,16 @@ using namespace RNS::Utilities; Destination announce_destination(announce_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, "unknown", "unknown"); announce_destination.hash(packet.destination_hash()); announce_destination.hexhash = announce_destination.hash().toHex(); - announce_context = Packet::NONE; + announce_context = {Type::NONE}; announce_data = packet.data(); Packet new_announce( announce_destination, announce_data, - Packet::ANNOUNCE, - context = Packet::PATH_RESPONSE, - header_type = Packet::HEADER_2, - transport_type = Transport::TRANSPORT, + Type::Packet::ANNOUNCE, + context = Type::Packet::PATH_RESPONSE, + header_type = Type::Packet::HEADER_2, + transport_type = Type::Transport::TRANSPORT, transport_id = _identity.hash(), attached_interface = attached_interface ); @@ -1763,7 +1763,7 @@ using namespace RNS::Utilities; // Call externally registered callbacks from apps // wanting to know when an announce arrives - if (packet.context() != Packet::PATH_RESPONSE) { + if (packet.context() != Type::Packet::PATH_RESPONSE) { for (auto &handler : Transport.announce_handlers) { try { // Check that the announced destination matches @@ -1808,7 +1808,7 @@ using namespace RNS::Utilities; } // Handling for link requests to local destinations - else if (packet.packet_type() == Packet::LINKREQUEST) { + else if (packet.packet_type() == Type::Packet::LINKREQUEST) { extreme("Transport::inbound: Packet is LINKREQUEST"); if (!packet.transport_id() || packet.transport_id() == _identity.hash()) { for (auto &destination : _destinations) { @@ -1823,9 +1823,9 @@ using namespace RNS::Utilities; } // Handling for local data packets - else if (packet.packet_type() == Packet::DATA) { + else if (packet.packet_type() == Type::Packet::DATA) { extreme("Transport::inbound: Packet is DATA"); - if (packet.destination_type() == Destination::LINK) { + if (packet.destination_type() == Type::Destination::LINK) { for (auto &link : _active_links) { if (link.link_id() == packet.destination_hash()) { packet.link(link); @@ -1839,10 +1839,10 @@ using namespace RNS::Utilities; packet.destination(destination); const_cast(destination).receive(packet); - if (destination.proof_strategy() == Destination::PROVE_ALL) { + if (destination.proof_strategy() == Type::Destination::PROVE_ALL) { packet.prove(); } - else if (destination.proof_strategy() == Destination::PROVE_APP) { + else if (destination.proof_strategy() == Type::Destination::PROVE_APP) { if (destination.callbacks()._proof_requested) { try { if (destination.callbacks()._proof_requested(packet)) { @@ -1860,7 +1860,7 @@ using namespace RNS::Utilities; } // Handling for proofs and link-request proofs - else if (packet.packet_type() == Packet::PROOF) { + else if (packet.packet_type() == Type::Packet::PROOF) { extreme("Transport::inbound: Packet is PROOF"); /* if packet.context == RNS.Packet.LRPROOF: @@ -2080,8 +2080,8 @@ using namespace RNS::Utilities; /*static*/ void Transport::register_destination(Destination &destination) { extreme("Transport: Registering destination " + destination.toString()); - destination.mtu(Reticulum::MTU); - if (destination.direction() == Destination::IN) { + destination.mtu(Type::Reticulum::MTU); + if (destination.direction() == Type::Destination::IN) { for (auto ®istered_destination : _destinations) { if (destination.hash() == registered_destination.hash()) { //raise KeyError("Attempt to register an already registered destination.") @@ -2092,7 +2092,7 @@ using namespace RNS::Utilities; _destinations.insert(destination); if (_owner.is_connected_to_shared_instance()) { - if (destination.type() == Destination::SINGLE) { + if (destination.type() == Type::Destination::SINGLE) { destination.announce({}, true); } } @@ -2122,12 +2122,12 @@ using namespace RNS::Utilities; /* extreme("Transport: Activating link " + link.toString()); if (_pending_links.find(link) != _pending_links.end()) { - if (link.status() != Link::ACTIVE) { + if (link.status() != Type::Link::ACTIVE) { throw std::runtime_error("Invalid link state for link activation: " + link.status_string()); } _pending_links.erase(link); _active_links.insert(link); - link.status(Link::ACTIVE); + link.status(Type::Link::ACTIVE); } else { error("Attempted to activate a link that was not in the pending table"); @@ -2166,7 +2166,7 @@ Deregisters an announce handler. } } - return {Interface::NONE}; + return {Type::NONE}; } /*static*/ bool Transport::should_cache(const Packet &packet) { @@ -2236,11 +2236,11 @@ Deregisters an announce handler. } */ // MOCK - return {Packet::NONE}; + return {Type::NONE}; } /*static*/ bool Transport::cache_request_packet(const Packet &packet) { - if (packet.data().size() == Identity::HASHLENGTH/8) { + if (packet.data().size() == Type::Identity::HASHLENGTH/8) { const Packet &cached_packet = get_cached_packet(packet.data()); if (cached_packet) { @@ -2270,7 +2270,7 @@ Deregisters an announce handler. else { // The packet is not in the local cache, // query the network. - Packet request(destination, packet_hash, Packet::DATA, Packet::CACHE_REQUEST); + Packet request(destination, packet_hash, Type::Packet::DATA, Type::Packet::CACHE_REQUEST); request.send(); } } @@ -2329,7 +2329,7 @@ Deregisters an announce handler. return destination_entry._receiving_interface; } else { - return {Interface::NONE}; + return {Type::NONE}; } } @@ -2354,7 +2354,7 @@ will announce it. :param destination_hash: A destination hash as *bytes*. :param on_interface: If specified, the path request will only be sent on this interface. In normal use, Reticulum handles this automatically, and this parameter should not be used. */ -/*static*/ void Transport::request_path(const Bytes &destination_hash, const Interface &on_interface /*= {Interface::NONE}*/, const Bytes &tag /*= {}*/, bool recursive /*= false*/) { +/*static*/ void Transport::request_path(const Bytes &destination_hash, const Interface &on_interface /*= {Type::NONE}*/, const Bytes &tag /*= {}*/, bool recursive /*= false*/) { /* if tag == None: request_tag = RNS.Identity.get_random_hash() @@ -2474,7 +2474,7 @@ will announce it. Transport.pending_local_path_requests[destination_hash] = attached_interface //local_destination = next((d for d in Transport.destinations if d.hash == destination_hash), None) - Destination local_destination(Destination::NONE); + Destination local_destination({Type::NONE}); for (auto &destination : _destinations) { if (destination.hash() == destination_hash) { local_destination = destination; diff --git a/src/Transport.h b/src/Transport.h index 8d697d3..3a78f5c 100644 --- a/src/Transport.h +++ b/src/Transport.h @@ -3,10 +3,10 @@ #include "Reticulum.h" #include "Link.h" // CBA TODO resolve circular dependency with following header file -//#include "Packet.h" +#include "Packet.h" #include "Bytes.h" -#include "None.h" #include "Interfaces/Interface.h" +#include "Type.h" #include #include @@ -133,6 +133,7 @@ namespace RNS { public: // Constants +/* enum types { BROADCAST = 0x00, TRANSPORT = 0x01, @@ -140,6 +141,7 @@ namespace RNS { TUNNEL = 0x03, NONE = 0xFF, }; +*/ enum reachabilities { REACHABILITY_UNREACHABLE = 0x00, @@ -168,7 +170,7 @@ namespace RNS { static const uint8_t PATH_REQUEST_RW = 2; // Path request random window static const uint8_t PATH_REQUEST_MI = 5; // Minimum interval in seconds for automated path requests - static constexpr const float LINK_TIMEOUT = Link::STALE_TIME * 1.25; + static constexpr const float LINK_TIMEOUT = Type::Link::STALE_TIME * 1.25; static const uint16_t REVERSE_TIMEOUT = 30*60; // Reverse table entries are removed after 30 minutes static const uint32_t DESTINATION_TIMEOUT = 60*60*24*7; // Destination table entries are removed if unused for one week static const uint16_t MAX_RECEIPTS = 1024; // Maximum number of receipts to keep track of @@ -181,7 +183,7 @@ namespace RNS { static void transmit(Interface &interface, const Bytes &raw); static bool outbound(Packet &packet); static bool packet_filter(const Packet &packet); - static void inbound(const Bytes &raw, const Interface &interface = Interface::NONE); + static void inbound(const Bytes &raw, const Interface &interface = {Type::NONE}); static void synthesize_tunnel(const Interface &interface); static void tunnel_synthesize_handler(const Bytes &data, const Packet &packet); static void handle_tunnel(const Bytes &tunnel_id, const Interface &interface); @@ -204,7 +206,7 @@ namespace RNS { static Bytes next_hop(const Bytes &destination_hash); static Interface next_hop_interface(const Bytes &destination_hash); static bool expire_path(const Bytes &destination_hash); - static void request_path(const Bytes &destination_hash, const Interface &on_interface = {Interface::NONE}, const Bytes &tag = {}, bool recursive = false); + static void request_path(const Bytes &destination_hash, const Interface &on_interface = {Type::NONE}, const Bytes &tag = {}, bool recursive = false); static void path_request_handler(const Bytes &data, const Packet &packet); static void path_request(const Bytes &destination_hash, bool is_from_local_client, const Interface &attached_interface, const Bytes &requestor_transport_id = {}, const Bytes &tag = {}); static bool from_local_client(const Packet &packet); diff --git a/src/Type.h b/src/Type.h new file mode 100644 index 0000000..4d12efe --- /dev/null +++ b/src/Type.h @@ -0,0 +1,321 @@ +#pragma once + +#include "Cryptography/Fernet.h" + +#include + +namespace RNS { namespace Type { + + // generic empty object constructor type + enum NoneConstructor { + NONE + }; + + namespace Reticulum { + + // Future minimum will probably be locked in at 251 bytes to support + // networks with segments of different MTUs. Absolute minimum is 219. + static const uint16_t MTU = 500; + /* + The MTU that Reticulum adheres to, and will expect other peers to + adhere to. By default, the MTU is 507 bytes. In custom RNS network + implementations, it is possible to change this value, but doing so will + completely break compatibility with all other RNS networks. An identical + MTU is a prerequisite for peers to communicate in the same network. + + Unless you really know what you are doing, the MTU should be left at + the default value. + */ + + static const uint16_t MAX_QUEUED_ANNOUNCES = 16384; + static const uint32_t QUEUED_ANNOUNCE_LIFE = 60*60*24; + + static const uint8_t ANNOUNCE_CAP = 2; + /* + The maximum percentage of interface bandwidth that, at any given time, + may be used to propagate announces. If an announce was scheduled for + broadcasting on an interface, but doing so would exceed the allowed + bandwidth allocation, the announce will be queued for transmission + when there is bandwidth available. + + Reticulum will always prioritise propagating announces with fewer + hops, ensuring that distant, large networks with many peers on fast + links don't overwhelm the capacity of smaller networks on slower + mediums. If an announce remains queued for an extended amount of time, + it will eventually be dropped. + + This value will be applied by default to all created interfaces, + but it can be configured individually on a per-interface basis. + */ + + static const uint16_t MINIMUM_BITRATE = 500; + + // TODO: To reach the 300bps level without unreasonably impacting + // performance on faster links, we need a mechanism for setting + // this value more intelligently. One option could be inferring it + // from interface speed, but a better general approach would most + // probably be to let Reticulum somehow continously build a map of + // per-hop latencies and use this map for the timeout calculation. + static const uint8_t DEFAULT_PER_HOP_TIMEOUT = 6; + + static const uint16_t HASHLENGTH = 256; // In bits + // Length of truncated hashes in bits. + static const uint16_t TRUNCATED_HASHLENGTH = 128; // In bits + + static const uint16_t HEADER_MINSIZE = 2+1+(TRUNCATED_HASHLENGTH/8)*1; // In bytes + static const uint16_t HEADER_MAXSIZE = 2+1+(TRUNCATED_HASHLENGTH/8)*2; // In bytes + static const uint16_t IFAC_MIN_SIZE = 1; + //zIFAC_SALT = bytes.fromhex("adf54d882c9a9b80771eb4995d702d4a3e733391b2a0f53f416d9f907e55cff8") + + static const uint16_t MDU = MTU - HEADER_MAXSIZE - IFAC_MIN_SIZE; + + static const uint32_t RESOURCE_CACHE = 24*60*60; + static const uint16_t JOB_INTERVAL = 5*60; + static const uint16_t CLEAN_INTERVAL = 15*60; + static const uint16_t PERSIST_INTERVAL = 60*60*12; + static const uint16_t GRACIOUS_PERSIST_INTERVAL = 60*5; + + static const uint8_t DESTINATION_LENGTH = TRUNCATED_HASHLENGTH/8; // In bytes + + } + + namespace Identity { + + //static const char CURVE[] = "Curve25519"; + static constexpr const char* CURVE = "Curve25519"; + // The curve used for Elliptic Curve DH key exchanges + + static const uint16_t KEYSIZE = 256*2; + // X25519 key size in bits. A complete key is the concatenation of a 256 bit encryption key, and a 256 bit signing key. + + // Non-configurable constants + static const uint8_t FERNET_OVERHEAD = Cryptography::Fernet::FERNET_OVERHEAD; + static const uint8_t AES128_BLOCKSIZE = 16; // In bytes + static const uint16_t HASHLENGTH = Reticulum::HASHLENGTH; // In bits + static const uint16_t SIGLENGTH = KEYSIZE; // In bits + + static const uint8_t NAME_HASH_LENGTH = 80; + static const uint16_t TRUNCATED_HASHLENGTH = Reticulum::TRUNCATED_HASHLENGTH; // In bits + // Constant specifying the truncated hash length (in bits) used by Reticulum + // for addressable hashes and other purposes. Non-configurable. + + } + + namespace Destination { + + enum types { + SINGLE = 0x00, + GROUP = 0x01, + PLAIN = 0x02, + LINK = 0x03, + }; + + enum proof_strategies { + PROVE_NONE = 0x21, + PROVE_APP = 0x22, + PROVE_ALL = 0x23, + }; + + enum request_policies { + ALLOW_NONE = 0x00, + ALLOW_ALL = 0x01, + ALLOW_LIST = 0x02, + }; + + enum directions { + IN = 0x11, + OUT = 0x12, + }; + + const uint8_t PR_TAG_WINDOW = 30; + + } + + namespace Link { + + static constexpr const char* CURVE = Identity::CURVE; + // The curve used for Elliptic Curve DH key exchanges + + static const uint16_t ECPUBSIZE = 32+32; + static const uint8_t KEYSIZE = 32; + + //static const uint16_t MDU = floor((Reticulum::MTU-Reticulum::IFAC_MIN_SIZE-Reticulum::HEADER_MINSIZE-Identity::FERNET_OVERHEAD)/Identity::AES128_BLOCKSIZE)*Identity::AES128_BLOCKSIZE - 1; + static const uint16_t MDU = ((Reticulum::MTU-Reticulum::IFAC_MIN_SIZE-Reticulum::HEADER_MINSIZE-Identity::FERNET_OVERHEAD)/Identity::AES128_BLOCKSIZE)*Identity::AES128_BLOCKSIZE - 1; + + static const uint8_t ESTABLISHMENT_TIMEOUT_PER_HOP = Reticulum::DEFAULT_PER_HOP_TIMEOUT; + // Timeout for link establishment in seconds per hop to destination. + + static const uint16_t TRAFFIC_TIMEOUT_FACTOR = 6; + static const uint16_t KEEPALIVE_TIMEOUT_FACTOR = 4; + // RTT timeout factor used in link timeout calculation. + static const uint8_t STALE_GRACE = 2; + // Grace period in seconds used in link timeout calculation. + static const uint16_t KEEPALIVE = 360; + // Interval for sending keep-alive packets on established links in seconds. + static const uint16_t STALE_TIME = 2*KEEPALIVE; + /* + If no traffic or keep-alive packets are received within this period, the + link will be marked as stale, and a final keep-alive packet will be sent. + If after this no traffic or keep-alive packets are received within ``RTT`` * + ``KEEPALIVE_TIMEOUT_FACTOR`` + ``STALE_GRACE``, the link is considered timed out, + and will be torn down. + */ + + enum status { + PENDING = 0x00, + HANDSHAKE = 0x01, + ACTIVE = 0x02, + STALE = 0x03, + CLOSED = 0x04 + }; + + enum teardown_reasons { + TIMEOUT = 0x01, + INITIATOR_CLOSED = 0x02, + DESTINATION_CLOSED = 0x03, + }; + + enum resource_strategies { + ACCEPT_NONE = 0x00, + ACCEPT_APP = 0x01, + ACCEPT_ALL = 0x02, + }; + + } + + namespace Interface { + + // Interface mode definitions + enum modes { + MODE_NONE = 0x00, + MODE_FULL = 0x01, + MODE_POINT_TO_POINT = 0x04, + MODE_ACCESS_POINT = 0x08, + MODE_ROAMING = 0x10, + MODE_BOUNDARY = 0x20, + MODE_GATEWAY = 0x40, + }; + + } + + namespace Packet { + + // Packet types + enum types { + DATA = 0x00, // Data packets + ANNOUNCE = 0x01, // Announces + LINKREQUEST = 0x02, // Link requests + PROOF = 0x03, // Proofs + }; + + // Header types + enum header_types { + HEADER_1 = 0x00, // Normal header format + HEADER_2 = 0x01, // Header format used for packets in transport + }; + + // Packet context types + enum context_types { + CONTEXT_NONE = 0x00, // Generic data packet + RESOURCE = 0x01, // Packet is part of a resource + RESOURCE_ADV = 0x02, // Packet is a resource advertisement + RESOURCE_REQ = 0x03, // Packet is a resource part request + RESOURCE_HMU = 0x04, // Packet is a resource hashmap update + RESOURCE_PRF = 0x05, // Packet is a resource proof + RESOURCE_ICL = 0x06, // Packet is a resource initiator cancel message + RESOURCE_RCL = 0x07, // Packet is a resource receiver cancel message + CACHE_REQUEST = 0x08, // Packet is a cache request + REQUEST = 0x09, // Packet is a request + RESPONSE = 0x0A, // Packet is a response to a request + PATH_RESPONSE = 0x0B, // Packet is a response to a path request + COMMAND = 0x0C, // Packet is a command + COMMAND_STATUS = 0x0D, // Packet is a status of an executed command + CHANNEL = 0x0E, // Packet contains link channel data + KEEPALIVE = 0xFA, // Packet is a keepalive packet + LINKIDENTIFY = 0xFB, // Packet is a link peer identification proof + LINKCLOSE = 0xFC, // Packet is a link close message + LINKPROOF = 0xFD, // Packet is a link packet proof + LRRTT = 0xFE, // Packet is a link request round-trip time measurement + LRPROOF = 0xFF, // Packet is a link request proof + }; + + // This is used to calculate allowable + // payload sizes + static const uint16_t HEADER_MAXSIZE = Reticulum::HEADER_MAXSIZE; + static const uint16_t MDU = Reticulum::MDU; + + // With an MTU of 500, the maximum of data we can + // send in a single encrypted packet is given by + // the below calculation; 383 bytes. + //static const uint16_t ENCRYPTED_MDU = floor((Reticulum::MDU-Identity::FERNET_OVERHEAD-Identity::KEYSIZE/16)/Identity::AES128_BLOCKSIZE)*Identity::AES128_BLOCKSIZE - 1; + //static const uint16_t ENCRYPTED_MDU; + static const uint16_t ENCRYPTED_MDU = ((Reticulum::MDU-Identity::FERNET_OVERHEAD-Identity::KEYSIZE/16)/Identity::AES128_BLOCKSIZE)*Identity::AES128_BLOCKSIZE - 1; + // The maximum size of the payload data in a single encrypted packet + static const uint16_t PLAIN_MDU = MDU; + // The maximum size of the payload data in a single unencrypted packet + + static const uint8_t TIMEOUT_PER_HOP = Reticulum::DEFAULT_PER_HOP_TIMEOUT; + + } + + namespace PacketReceipt { + + // Receipt status constants + enum Status { + FAILED = 0x00, + SENT = 0x01, + DELIVERED = 0x02, + CULLED = 0xFF + }; + + static const uint16_t EXPL_LENGTH = Identity::HASHLENGTH / 8 + Identity::SIGLENGTH / 8; + static const uint16_t IMPL_LENGTH = Identity::SIGLENGTH / 8; + + } + + namespace Transport { + + enum types { + BROADCAST = 0x00, + TRANSPORT = 0x01, + RELAY = 0x02, + TUNNEL = 0x03, + NONE = 0xFF, + }; + + enum reachabilities { + REACHABILITY_UNREACHABLE = 0x00, + REACHABILITY_DIRECT = 0x01, + REACHABILITY_TRANSPORT = 0x02, + }; + + static constexpr const char* APP_NAME = "rnstransport"; + + static const uint8_t PATHFINDER_M = 128; // Max hops + // Maximum amount of hops that Reticulum will transport a packet. + + static const uint8_t PATHFINDER_R = 1; // Retransmit retries + static const uint8_t PATHFINDER_G = 5; // Retry grace period + static constexpr const float PATHFINDER_RW = 0.5; // Random window for announce rebroadcast + static const uint32_t PATHFINDER_E = 60*60*24*7; // Path expiration of one week + static const uint32_t AP_PATH_TIME = 60*60*24; // Path expiration of one day for Access Point paths + static const uint32_t ROAMING_PATH_TIME = 60*60*6; // Path expiration of 6 hours for Roaming paths + + // TODO: Calculate an optimal number for this in + // various situations + static const uint8_t LOCAL_REBROADCASTS_MAX = 2; // How many local rebroadcasts of an announce is allowed + + static const uint8_t PATH_REQUEST_TIMEOUT = 15; // Default timuout for client path requests in seconds + static constexpr const float PATH_REQUEST_GRACE = 0.35; // Grace time before a path announcement is made, allows directly reachable peers to respond first + static const uint8_t PATH_REQUEST_RW = 2; // Path request random window + static const uint8_t PATH_REQUEST_MI = 5; // Minimum interval in seconds for automated path requests + + static constexpr const float LINK_TIMEOUT = Link::STALE_TIME * 1.25; + static const uint16_t REVERSE_TIMEOUT = 30*60; // Reverse table entries are removed after 30 minutes + static const uint32_t DESTINATION_TIMEOUT = 60*60*24*7; // Destination table entries are removed if unused for one week + static const uint16_t MAX_RECEIPTS = 1024; // Maximum number of receipts to keep track of + static const uint8_t MAX_RATE_TIMESTAMPS = 16; // Maximum number of announce timestamps to keep per destination + + } + +} } diff --git a/src/main.cpp b/src/main.cpp index 86d2c78..a7e0db4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -175,7 +175,7 @@ void setup() { // 22.6% (+0.7%) RNS::head("Creating Destination instance...", RNS::LOG_EXTREME); - RNS::Destination destination(identity, RNS::Destination::IN, RNS::Destination::SINGLE, "test", "context"); + RNS::Destination destination(identity, RNS::Type::Destination::IN, RNS::Type::Destination::SINGLE, "test", "context"); // 23.0% (+0.4%) /* @@ -197,7 +197,7 @@ void setup() { } */ - destination.set_proof_strategy(RNS::Destination::PROVE_ALL); + destination.set_proof_strategy(RNS::Type::Destination::PROVE_ALL); //zRNS::head("Registering announce handler with Transport...", RNS::LOG_EXTREME); //zannounce_handler = ExampleAnnounceHandler( @@ -213,7 +213,7 @@ void setup() { destination.announce(RNS::bytesFromString(fruits[rand() % 7])); // 23.9% (+0.8%) -/* +/**/ // test data send packet RNS::head("Creating send packet...", RNS::LOG_EXTREME); RNS::Packet send_packet(destination, "The quick brown fox jumps over the lazy dog"); @@ -227,13 +227,13 @@ void setup() { destination.set_packet_callback(onPacket); RNS::head("Creating recv packet...", RNS::LOG_EXTREME); - RNS::Packet recv_packet(RNS::Destination::NONE, send_packet.raw()); + RNS::Packet recv_packet({RNS::Type::NONE}, send_packet.raw()); recv_packet.unpack(); RNS::extreme("Test recv_packet: " + recv_packet.debugString()); RNS::head("Spoofing recv packet to destination...", RNS::LOG_EXTREME); destination.receive(recv_packet); -*/ +/**/ } catch (std::exception& e) {