WIP update

Minimal transport implementation.
This commit is contained in:
attermann 2023-11-19 08:51:10 -07:00
parent 18ed42b40f
commit a2e956eced
28 changed files with 4205 additions and 225 deletions

View File

@ -11,16 +11,10 @@
[platformio]
;default_envs = native
[env:avr-test]
platform = atmelavr
board = megaatmega2560
framework = arduino
debug_tool = simavr
[env:native]
platform = native
build_flags =
-std=c++11
-std=c++11
-Wall
-Wextra
-Wno-missing-field-initializers
@ -28,7 +22,7 @@ build_flags =
-Isrc
-DNATIVE
lib_deps =
; rweather/Crypto@^0.4.0
rweather/Crypto@^0.4.0
lib_compat_mode = off
[env:ttgo-t-beam]

View File

@ -29,30 +29,30 @@ namespace RNS {
public:
Bytes() {
//extreme("Bytes object created from default, this: " + std::to_string((ulong)this) + ", data: " + std::to_string((ulong)_data.get()));
//extreme("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((ulong)this) + ", data: " + std::to_string((ulong)_data.get()));
//extreme("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");
assign(bytes);
//extreme("Bytes object copy created from bytes \"" + toString() + "\", this: " + std::to_string((ulong)this) + ", data: " + std::to_string((ulong)_data.get()));
//extreme("Bytes object copy created from bytes \"" + toString() + "\", this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((unsigned long)_data.get()));
}
Bytes(const uint8_t *chunk, size_t size) {
assign(chunk, size);
//extreme(std::string("Bytes object created from chunk \"") + toString() + "\", this: " + std::to_string((ulong)this) + ", data: " + std::to_string((ulong)_data.get()));
//extreme(std::string("Bytes object created from chunk \"") + toString() + "\", this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((unsigned long)_data.get()));
}
Bytes(const char *string) {
assign(string);
//extreme(std::string("Bytes object created from string \"") + toString() + "\", this: " + std::to_string((ulong)this) + ", data: " + std::to_string((ulong)_data.get()));
//extreme(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((ulong)this) + ", data: " + std::to_string((ulong)_data.get()));
//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()));
}
~Bytes() {
//extreme(std::string("Bytes object destroyed \"") + toString() + "\", this: " + std::to_string((ulong)this) + ", data: " + std::to_string((ulong)_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()));
}
inline Bytes& operator = (const Bytes &bytes) {
@ -206,6 +206,28 @@ namespace RNS {
inline Bytes left(size_t len) const { if (!_data) return NONE; if (len > size()) len = size(); return {data(), len}; }
inline Bytes right(size_t len) const { if (!_data) return NONE; if (len > size()) len = size(); return {data() + (size() - len), len}; }
// Python array indexing
// [8:16]
// pos 8 to pos 16
// mid(8, 8)
// [:16]
// start to pos 16 (same as first 16)
// left(16)
// [16:]
// pos 16 to end
// mid(16)
// [-16:]
// last 16
// right(16)
// [:-16]
// all except the last 16
// left(size()-16)
// mid(0, size()-16)
// [-1]
// last element
// [-2]
// second to last element
private:
SharedData _data;
mutable bool _owner = true;

View File

@ -21,28 +21,6 @@ Fernet::Fernet(const Bytes &key) {
throw std::invalid_argument("Fernet key must be 32 bytes, not " + std::to_string(key.size()));
}
// Python array indexing
// [8:16]
// pos 8 to pos 16
// mid(8, 8)
// [:16]
// start to pos 16 (same as first 16)
// left(16)
// [16:]
// pos 16 to end
// mid(16)
// [-16:]
// last 16
// right(16)
// [:-16]
// all except the last 16
// left(size()-16)
// mid(0, size()-16)
// [-1]
// last element
// [-2]
// seocnd to last element
//self._signing_key = key[:16]
_signing_key = key.left(16);
//self._encryption_key = key[16:]

View File

@ -31,11 +31,15 @@ namespace RNS { namespace Cryptography {
//debug("PKCS7::pad: len: " + std::to_string(len));
size_t padlen = bs - (len % bs);
//debug("PKCS7::pad: pad len: " + std::to_string(padlen));
// create byte array of size n?
//v = bytes([padlen])
uint8_t pad[padlen] = {0};
// create zero-filled byte padding array of size padlen
//p v = bytes([padlen])
//uint8_t pad[padlen] = {0};
uint8_t pad[padlen];
memset(pad, 0, padlen);
// set last byte of padding array to size of padding
pad[padlen-1] = (uint8_t)padlen;
//return data+v*padlen
// concatenate data with padding
//p return data+v*padlen
data.append(pad, padlen);
//debug("PKCS7::pad: data size: " + std::to_string(data.size()));
}
@ -44,13 +48,14 @@ namespace RNS { namespace Cryptography {
static inline void inplace_unpad(Bytes &data, size_t bs = BLOCKSIZE) {
size_t len = data.size();
//debug("PKCS7::unpad: len: " + std::to_string(len));
// last byte is pad length
// read last byte which is pad length
//pad = data[-1]
size_t padlen = (size_t)data.data()[data.size()-1];
//debug("PKCS7::unpad: pad len: " + std::to_string(padlen));
if (padlen > bs) {
throw std::runtime_error("Cannot unpad, invalid padding length of " + std::to_string(padlen) + " bytes");
}
// truncate data to strip padding
//return data[:len-padlen]
data.resize(len - padlen);
//debug("PKCS7::unpad: data size: " + std::to_string(data.size()));

View File

@ -7,10 +7,32 @@
namespace RNS { namespace Cryptography {
// return vector specified length of random bytes
inline Bytes random(size_t length) {
Bytes rand;
RNG.rand(rand.writable(length), length);
return rand;
}
// return 32 bit random unigned int
inline uint32_t randomnum() {
Bytes rand;
RNG.rand(rand.writable(4), 4);
uint32_t randnum = uint32_t((unsigned char)(rand.data()[0]) << 24 |
(unsigned char)(rand.data()[0]) << 16 |
(unsigned char)(rand.data()[0]) << 8 |
(unsigned char)(rand.data()[0]));
return randnum;
}
// return 32 bit random unigned int between 0 and specified value
inline uint32_t randomnum(uint32_t max) {
return randomnum() % max;
}
// return random float value from 0 to 1
inline float random() {
return (float)(randomnum() / (float)0xffffffff);
}
} }

View File

@ -55,8 +55,8 @@ namespace RNS { namespace Cryptography {
class X25519PrivateKey {
public:
const float MIN_EXEC_TIME = 0.002;
const float MAX_EXEC_TIME = 0.5;
const float MIN_EXEC_TIME = 2; // in milliseconds
const float MAX_EXEC_TIME = 500; // in milliseconds
const uint8_t DELAY_WINDOW = 10;
//zT_CLEAR = None
@ -134,11 +134,11 @@ namespace RNS { namespace Cryptography {
if isinstance(peer_public_key, bytes):
peer_public_key = X25519PublicKey.from_public_bytes(peer_public_key)
start = time.time()
start = OS::time()
shared = _pack_number(_raw_curve25519(peer_public_key.x, _a))
end = time.time()
end = OS::time()
duration = end-start
if X25519PrivateKey.T_CLEAR == None:
@ -158,7 +158,7 @@ namespace RNS { namespace Cryptography {
target = start+X25519PrivateKey.MIN_EXEC_TIME
try:
time.sleep(target-time.time())
OS::sleep(target-OS::time())
except Exception as e:
pass

View File

@ -54,10 +54,6 @@ Destination::Destination(const Identity &identity, const directions direction, c
extreme("Destination object created");
}
Destination::~Destination() {
extreme("Destination object destroyed");
}
/*
:returns: A destination name in adressable hash form, for an app_name and a number of aspects.
*/
@ -124,7 +120,7 @@ Packet Destination::announce(const Bytes &app_data, bool path_response, Interfac
// vector
//Response &entry = *it;
// map
Response &entry = (*it).second;
PathResponse &entry = (*it).second;
if (now > (entry.first + Destination::PR_TAG_WINDOW)) {
it = _object->_path_responses.erase(it);
}
@ -218,6 +214,7 @@ Packet Destination::announce(const Bytes &app_data, bool path_response, Interfac
Packet announce_packet(*this, announce_data, Packet::ANNOUNCE, announce_context, Transport::BROADCAST, Packet::HEADER_1, nullptr, attached_interface);
if (send) {
debug("Destination::announce: sending announce packet...");
announce_packet.send();
return Packet::NONE;
}

View File

@ -1,15 +1,16 @@
#pragma once
#include "Reticulum.h"
#include "Link.h"
#include "Identity.h"
#include "Bytes.h"
#include "None.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <map>
#include <stdexcept>
#include <stdint.h>
namespace RNS {
@ -17,6 +18,7 @@ namespace RNS {
class Interface;
class Packet;
class Link;
class Identity;
/**
* @brief A class used to describe endpoints in a Reticulum Network. Destination
@ -40,7 +42,7 @@ namespace RNS {
using link_established = void(*)(const Link &link);
//using packet = void(*)(uint8_t *data, uint16_t data_len, Packet *packet);
using packet = void(*)(const Bytes &data, const Packet &packet);
using proof_requested = void(*)(const Packet &packet);
using proof_requested = bool(*)(const Packet &packet);
public:
link_established _link_established = nullptr;
packet _packet = nullptr;
@ -49,8 +51,8 @@ namespace RNS {
};
//typedef std::pair<time_t, std::string> Response;
using Response = std::pair<time_t, Bytes>;
//using Response = std::pair<time_t, std::vector<uint8_t>>;
using PathResponse = std::pair<time_t, Bytes>;
//using PathResponse = std::pair<time_t, std::vector<uint8_t>>;
enum NoneConstructor {
NONE
@ -87,20 +89,28 @@ namespace RNS {
Destination(NoneConstructor none) {
extreme("Destination NONE object created");
}
Destination(RNS::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();
virtual ~Destination() {
extreme("Destination object destroyed");
}
inline Destination& operator = (const Destination &destination) {
_object = destination._object;
extreme("Destination object copy created by assignment, this: " + std::to_string((ulong)this) + ", data: " + std::to_string((uint32_t)_object.get()));
extreme("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 {
return _object.get() != nullptr;
}
inline bool operator < (const Destination &destination) const {
return _object.get() < destination._object.get();
}
public:
static Bytes hash(const Identity &identity, const char *app_name, const char *aspects);
@ -172,12 +182,15 @@ namespace RNS {
// 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 directions direction() const { assert(_object); return _object->_direction; }
inline 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 const Callbacks &callbacks() const { assert(_object); return _object->_callbacks; }
inline const Identity &identity() const { assert(_object); return _object->_identity; }
inline std::string toString() const { assert(_object); return "{Destination:" + _object->_hash.toHex() + "}"; }
@ -185,6 +198,7 @@ namespace RNS {
class Object {
public:
Object(const Identity &identity) : _identity(identity) {}
virtual ~Object() {}
private:
bool _accept_link_requests = true;
Callbacks _callbacks;
@ -194,8 +208,8 @@ namespace RNS {
proof_strategies _proof_strategy = PROVE_NONE;
uint16_t _mtu = 0;
//std::vector<Response> _path_responses;
std::map<Bytes, Response> _path_responses;
//std::vector<PathResponse> _path_responses;
std::map<Bytes, PathResponse> _path_responses;
//z_links = []
Identity _identity;
@ -214,6 +228,9 @@ namespace RNS {
// CBA _link_id is expected by packet but only present in Link
// CBA TODO determine if Link needs to inherit from Destination or vice-versa
Bytes _link_id;
Link::status _status;
friend class Destination;
};
std::shared_ptr<Object> _object;

View File

@ -16,7 +16,7 @@ Identity::Identity(bool create_keys) : _object(new Object()) {
if (create_keys) {
createKeys();
}
extreme("Identity object created, this: " + std::to_string((ulong)this) + ", data: " + std::to_string((ulong)_object.get()));
extreme("Identity object created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
}
@ -49,6 +49,81 @@ void Identity::createKeys() {
}
/*static*/ bool Identity::validate_announce(const Packet &packet) {
/*
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:
signal_str += "RSSI "+str(packet.rssi)+"dBm"
if packet.snr != None:
signal_str += ", "
if packet.snr != None:
signal_str += "SNR "+str(packet.snr)+"dB"
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;
}
/*
Encrypts information for the identity.

View File

@ -5,6 +5,7 @@
//#include "Destination.h"
#include "Log.h"
#include "Bytes.h"
#include "None.h"
#include "Cryptography/Hashes.h"
#include "Cryptography/Ed25519.h"
#include "Cryptography/X25519.h"
@ -46,24 +47,30 @@ namespace RNS {
public:
Identity(NoneConstructor none) {
extreme("Identity NONE object created, this: " + std::to_string((ulong)this) + ", data: " + std::to_string((ulong)_object.get()));
extreme("Identity NONE object created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
}
Identity(RNS::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) {
extreme("Identity object copy created, this: " + std::to_string((ulong)this) + ", data: " + std::to_string((ulong)_object.get()));
extreme("Identity object copy created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
}
Identity(bool create_keys = true);
~Identity() {
extreme("Identity object destroyed, this: " + std::to_string((ulong)this) + ", data: " + std::to_string((ulong)_object.get()));
virtual ~Identity() {
extreme("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((ulong)this) + ", data: " + std::to_string((uint32_t)_object.get()));
extreme("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 {
return _object.get() != nullptr;
}
inline bool operator < (const Identity &identity) const {
return _object.get() < identity._object.get();
}
public:
void createKeys();
@ -110,6 +117,8 @@ namespace RNS {
return truncated_hash(Cryptography::random(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; }
@ -133,8 +142,8 @@ namespace RNS {
private:
class Object {
public:
Object() { extreme("Identity::Data object created, this: " + std::to_string((ulong)this)); }
~Object() { extreme("Identity::Data object destroyed, this: " + std::to_string((ulong)this)); }
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)); }
private:
RNS::Cryptography::X25519PrivateKey::Ptr _prv;

View File

@ -1,14 +1,65 @@
#include "Interface.h"
#include "Log.h"
#include "../Transport.h"
using namespace RNS;
Interface::Interface() {
extreme("Interface object created");
/*virtual*/ inline void Interface::processIncoming(const Bytes &data) {
extreme("Interface::processIncoming: data: " + data.toHex());
assert(_object);
_object->_rxb += data.size();
// CBA TODO implement concept of owner or a callback mechanism for incoming data
//_object->_owner.inbound(data, *this);
Transport::inbound(data, *this);
}
Interface::~Interface() {
extreme("Interface object destroyed");
/*virtual*/ inline void Interface::processOutgoing(const Bytes &data) {
extreme("Interface::processOutgoing: data: " + data.toHex());
assert(_object);
_object->_txb += data.size();
}
void Interface::process_announce_queue() {
/*
if not hasattr(self, "announce_cap"):
self.announce_cap = RNS.Reticulum.ANNOUNCE_CAP
if hasattr(self, "announce_queue"):
try:
now = time.time()
stale = []
for a in self.announce_queue:
if now > a["time"]+RNS.Reticulum.QUEUED_ANNOUNCE_LIFE:
stale.append(a)
for s in stale:
if s in self.announce_queue:
self.announce_queue.remove(s)
if len(self.announce_queue) > 0:
min_hops = min(entry["hops"] for entry in self.announce_queue)
entries = list(filter(lambda e: e["hops"] == min_hops, self.announce_queue))
entries.sort(key=lambda e: e["time"])
selected = entries[0]
now = time.time()
tx_time = (len(selected["raw"])*8) / self.bitrate
wait_time = (tx_time / self.announce_cap)
self.announce_allowed_at = now + wait_time
self.processOutgoing(selected["raw"])
if selected in self.announce_queue:
self.announce_queue.remove(selected)
if len(self.announce_queue) > 0:
timer = threading.Timer(wait_time, self.process_announce_queue)
timer.start()
except Exception as e:
self.announce_queue = []
RNS.log("Error while processing announce queue on "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR)
RNS.log("The announce queue for this interface has been cleared.", RNS.LOG_ERROR)
*/
}

View File

@ -1,13 +1,35 @@
#pragma once
#include "../Log.h"
#include "../Bytes.h"
#include "../None.h"
#include <list>
#include <memory>
#include <stdint.h>
namespace RNS {
class Interface {
public:
class AnnounceEntry {
public:
AnnounceEntry() {}
AnnounceEntry(const Bytes &destination, uint64_t time, uint8_t hops, uint64_t emitted, const Bytes &raw) :
_destination(destination),
_time(time),
_hops(hops),
_emitted(emitted),
_raw(raw) {}
public:
Bytes _destination;
uint64_t _time = 0;
uint8_t _hops = 0;
uint64_t _emitted = 0;
Bytes _raw;
};
public:
enum NoneConstructor {
NONE
@ -16,42 +38,106 @@ namespace RNS {
public:
// Interface mode definitions
enum modes {
MODE_FULL = 0x01,
MODE_POINT_TO_POINT = 0x02,
MODE_ACCESS_POINT = 0x03,
MODE_ROAMING = 0x04,
MODE_BOUNDARY = 0x05,
MODE_GATEWAY = 0x06,
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.
//zDISCOVER_PATHS_FOR = [MODE_ACCESS_POINT, MODE_GATEWAY]
uint8_t DISCOVER_PATHS_FOR = MODE_ACCESS_POINT | MODE_GATEWAY;
public:
public:
Interface(NoneConstructor none) {
extreme("Interface object NONE created");
}
Interface(RNS::NoneConstructor none) {
extreme("Interface object NONE created");
}
Interface(const Interface &interface) : _object(interface._object) {
extreme("Interface object copy created");
}
Interface();
~Interface();
Interface() : _object(new Object()) {
extreme("Interface object created");
}
Interface(const char *name) : _object(new Object(name)) {
extreme("Interface object created");
}
virtual ~Interface() {
extreme("Interface object destroyed");
}
inline Interface& operator = (const Interface &interface) {
_object = interface._object;
extreme("Interface object copy created by assignment, this: " + std::to_string((ulong)this) + ", data: " + std::to_string((uint32_t)_object.get()));
extreme("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 {
return _object.get() != nullptr;
}
inline bool operator < (const Interface &interface) const {
return _object.get() < interface._object.get();
}
public:
inline Bytes get_hash() const { /*return Identity::full_hash();*/ return {}; }
void process_announce_queue();
inline void detach() {}
virtual void processIncoming(const Bytes &data);
virtual void processOutgoing(const Bytes &data);
inline void add_announce(AnnounceEntry &entry) { assert(_object); _object->_announce_queue.push_back(entry); }
// getters/setters
protected:
inline void IN(bool IN) { assert(_object); _object->_IN = IN; }
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; }
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 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 uint32_t bitrate() const { assert(_object); return _object->_bitrate; }
inline uint64_t announce_allowed_at() const { assert(_object); return _object->_announce_allowed_at; }
inline void announce_allowed_at(uint64_t announce_allowed_at) { assert(_object); _object->_announce_allowed_at = announce_allowed_at; }
inline float announce_cap() const { assert(_object); return _object->_announce_cap; }
inline std::list<AnnounceEntry> announce_queue() const { assert(_object); return _object->_announce_queue; }
virtual inline std::string toString() const { assert(_object); return "Interface[" + _object->_name + "]"; }
private:
class Object {
public:
Object() {}
Object(const char *name) : _name(name) {}
virtual ~Object() {}
private:
bool _IN = false;
bool _OUT = false;
bool _FWD = false;
bool _RPT = false;
std::string _name;
size_t _rxb = 0;
size_t _txb = 0;
bool online = false;
Bytes _ifac_identity;
modes _mode = MODE_NONE;
uint32_t _bitrate = 0;
uint64_t _announce_allowed_at = 0;
float _announce_cap = 0.0;
std::list<AnnounceEntry> _announce_queue;
//Transport &_owner;
friend class Interface;
};
std::shared_ptr<Object> _object;

View File

@ -1,14 +1,22 @@
#include "Link.h"
#include "Packet.h"
#include "Log.h"
using namespace RNS;
Link::Link() {
log("Link object created", LOG_EXTREME);
Link::Link() : _object(new Object()) {
assert(_object);
extreme("Link object created");
}
Link::~Link() {
log("Link object destroyed", LOG_EXTREME);
void Link::set_link_id(const Packet &packet) {
assert(_object);
_object->_link_id = packet.getTruncatedHash();
_object->_hash = _object->_link_id;
}
void Link::receive(const Packet &packet) {
}

View File

@ -2,6 +2,12 @@
#include "Reticulum.h"
#include "Identity.h"
// CBA TODO resolve circular dependency with following header file
//#include "Packet.h"
#include "Bytes.h"
#include "None.h"
#include <memory>
namespace RNS {
@ -14,6 +20,10 @@ 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
@ -51,20 +61,64 @@ namespace RNS {
};
enum teardown_reasons {
TIMEOUT = 0x01,
INITIATOR_CLOSED = 0x02,
DESTINATION_CLOSED = 0x03,
TIMEOUT = 0x01,
INITIATOR_CLOSED = 0x02,
DESTINATION_CLOSED = 0x03,
};
enum resource_strategies {
ACCEPT_NONE = 0x00,
ACCEPT_APP = 0x01,
ACCEPT_ALL = 0x02,
ACCEPT_NONE = 0x00,
ACCEPT_APP = 0x01,
ACCEPT_ALL = 0x02,
};
public:
Link(NoneConstructor none) {
extreme("Link NONE object created");
}
Link(RNS::NoneConstructor none) {
extreme("Link NONE object created");
}
Link(const Link &link) : _object(link._object) {
extreme("Link object copy created");
}
Link();
~Link();
virtual ~Link(){
extreme("Link object destroyed");
}
inline Link& operator = (const Link &link) {
_object = link._object;
return *this;
}
inline operator bool() const {
return _object.get() != nullptr;
}
inline bool operator < (const Link &link) const {
return _object.get() < link._object.get();
}
public:
void set_link_id(const Packet &packet);
void receive(const Packet &packet);
// getters/setters
inline const Bytes &link_id() const { assert(_object); return _object->_link_id; }
inline const Bytes &hash() const { assert(_object); return _object->_hash; }
inline std::string toString() const { assert(_object); return "{Link: unknown}"; }
private:
class Object {
public:
Object() {}
virtual ~Object() {}
private:
Bytes _link_id;
Bytes _hash;
friend class Link;
};
std::shared_ptr<Object> _object;
};

View File

@ -37,7 +37,7 @@ 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;
}
@ -50,3 +50,15 @@ void RNS::doLog(const char* msg, LogLevel level) {
printf("%s: %s\n", getLevelName(level), msg);
#endif
}
void RNS::head(const char *msg, LogLevel level) {
if (level > _level) {
return;
}
#ifndef NATIVE
Serial.println("");
#else
printf("\n");
#endif
doLog(msg, level);
}

View File

@ -22,36 +22,39 @@ namespace RNS {
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); }
inline void log(const char *msg, LogLevel level = LOG_NOTICE) { doLog(msg, level); }
#ifndef NATIVE
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 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 std::string& msg) { doLog(msg.c_str(), 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 std::string& msg) { doLog(msg.c_str(), 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 std::string& msg) { doLog(msg.c_str(), 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 std::string& msg) { doLog(msg.c_str(), 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 std::string& msg) { doLog(msg.c_str(), 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 std::string& msg) { doLog(msg.c_str(), 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 std::string& msg) { doLog(msg.c_str(), 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 std::string& msg) { doLog(msg.c_str(), 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 head(const std::string &msg, LogLevel level = LOG_NOTICE) { head(msg.c_str(), level); }
}

10
src/None.h Normal file
View File

@ -0,0 +1,10 @@
#pragma once
namespace RNS {
// generic empty object constructor type
enum NoneConstructor {
NONE
};
}

View File

@ -11,7 +11,7 @@ using namespace RNS;
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)) {
if (_object->_destination) {
extreme("Creating packet with detination...");
extreme("Creating packet with destination...");
// CBA TODO handle NONE
if (transport_type == -1) {
transport_type = Transport::BROADCAST;
@ -32,7 +32,7 @@ Packet::Packet(const Destination &destination, const Interface &attached_interfa
_object->_create_receipt = create_receipt;
}
else {
extreme("Creating packet without detination...");
extreme("Creating packet without destination...");
_object->_raw = data;
_object->_packed = true;
_object->_fromPacked = true;
@ -399,8 +399,8 @@ bool Packet::send() {
}
if (RNS::Transport::outbound(*this)) {
//zreturn self.receipt
debug("Packet::send: successfully sent packet!!!");
//zreturn self.receipt
// MOCK
return true;
}
@ -428,8 +428,8 @@ bool Packet::resend() {
pack();
if (RNS::Transport::outbound(*this)) {
//zreturn self.receipt
debug("Packet::resend: successfully sent packet!!!");
//zreturn self.receipt
// MOCK
return true;
}
@ -441,24 +441,41 @@ bool Packet::resend() {
}
}
void Packet::prove(const Destination &destination /*= {Destination::NONE}*/) {
/*
assert(_object);
if (_object->_fromPacked && _object->_destination) {
if (_object->_destination.identity() && _object->_destination.identity().prv()) {
_object->_destination.identity().prove(*this, _object->_destination);
}
}
else if (_object->_fromPacked && _object->_link) {
_object->_link.prove_packet(*this);
}
else {
error("Could not prove packet associated with neither a destination nor a link");
}
*/
}
void Packet::update_hash() {
assert(_object);
_object->_packet_hash = get_hash();
}
Bytes Packet::get_hash() {
const Bytes Packet::get_hash() const {
assert(_object);
Bytes hashable_part = get_hashable_part();
return Identity::full_hash(hashable_part);
}
Bytes Packet::getTruncatedHash() {
const Bytes Packet::getTruncatedHash() const {
assert(_object);
Bytes hashable_part = get_hashable_part();
return Identity::truncated_hash(hashable_part);
}
Bytes Packet::get_hashable_part() {
const Bytes Packet::get_hashable_part() const {
assert(_object);
Bytes hashable_part;
hashable_part << (uint8_t)(_object->_raw.data()[0] & 0b00001111);
@ -480,7 +497,7 @@ Bytes Packet::get_hashable_part() {
//}
std::string Packet::debugString() {
std::string Packet::debugString() const {
if (_object->_packed) {
//unpack();
}
@ -495,15 +512,16 @@ std::string Packet::debugString() {
dump += "transport: " + _object->_transport_id.toHex() + "\n";
dump += "destination: " + _object->_destination_hash.toHex() + "\n";
dump += "context_type: " + std::to_string(_object->_header_type) + "\n";
dump += "data: " + _object->_data.toHex() + "\n";
dump += " length: " + std::to_string(_object->_data.size()) + "\n";
dump += "raw: " + _object->_raw.toHex() + "\n";
dump += " length: " + std::to_string(_object->_raw.size()) + "\n";
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;
if (_object->_header_type == HEADER_2) {
header_len = 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));
@ -517,3 +535,23 @@ std::string Packet::debugString() {
dump += "--------------------\n";
return dump;
}
void PacketReceipt::check_timeout() {
assert(_object);
if (_object->_status == SENT && is_timed_out()) {
if (_object->_timeout == -1) {
_object->_status = CULLED;
}
else {
_object->_status = FAILED;
}
_object->_concluded_at = Utilities::OS::time();
if (_object->_callbacks._timeout) {
//zthread = threading.Thread(target=self.callbacks.timeout, args=(self,))
//zthread.daemon = True
//zthread.start();
}
}
}

View File

@ -1,10 +1,13 @@
#pragma once
#include "Reticulum.h"
#include "Identity.h"
#include "Transport.h"
#include "Reticulum.h"
#include "Link.h"
#include "Identity.h"
#include "Destination.h"
#include "None.h"
#include "Interfaces/Interface.h"
#include "Utilities/OS.h"
#include <memory>
#include <stdint.h>
@ -12,11 +15,125 @@
namespace RNS {
class Packet;
class PacketProof;
class ProofDestination;
class PacketReceipt;
class PacketReceiptCallbacks;
class Packet;
class ProofDestination {
};
/*
The PacketReceipt class is used to receive notifications about
:ref:`RNS.Packet<api-packet>` instances sent over the network. Instances
of this class are never created manually, but always returned from
the *send()* method of a :ref:`RNS.Packet<api-packet>` instance.
*/
class PacketReceipt {
public:
class Callbacks {
public:
using delivery = void(*)(const PacketReceipt &packet_receipt);
using timeout = void(*)(const PacketReceipt &packet_receipt);
public:
delivery _delivery = nullptr;
timeout _timeout = nullptr;
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(const PacketReceipt &packet_receipt) : _object(packet_receipt._object) {}
PacketReceipt() : _object(new Object()) {}
PacketReceipt(const Packet &packet) {}
inline PacketReceipt& operator = (const PacketReceipt &packet_receipt) {
_object = packet_receipt._object;
return *this;
}
inline operator bool() const {
return _object.get() != nullptr;
}
inline bool operator < (const PacketReceipt &packet_receipt) const {
return _object.get() < packet_receipt._object.get();
}
public:
inline bool is_timed_out() {
assert(_object);
return ((_object->_sent_at + _object->_timeout) < Utilities::OS::time());
}
void check_timeout();
/*
Sets a timeout in seconds
:param timeout: The timeout in seconds.
*/
inline void set_timeout(int16_t timeout) {
assert(_object);
_object->_timeout = timeout;
}
/*
Sets a function that gets called if a successfull delivery has been proven.
:param callback: A *callable* with the signature *callback(packet_receipt)*
*/
inline void set_delivery_callback(Callbacks::delivery callback) {
assert(_object);
_object->_callbacks._delivery = callback;
}
/*
Sets a function that gets called if the delivery times out.
:param callback: A *callable* with the signature *callback(packet_receipt)*
*/
inline void set_timeout_callback(Callbacks::timeout callback) {
assert(_object);
_object->_callbacks._timeout = callback;
}
private:
class Object {
public:
Object() {}
virtual ~Object() {}
private:
bool _sent = true;
uint64_t _sent_at = Utilities::OS::time();
bool _proved = false;
Status _status = SENT;
Destination _destination = Destination::NONE;
Callbacks _callbacks;
uint64_t _concluded_at = 0;
//zPacket _proof_packet;
int16_t _timeout = 0;
friend class PacketReceipt;
};
std::shared_ptr<Object> _object;
};
class Packet {
@ -85,25 +202,30 @@ namespace RNS {
uint8_t EMPTY_DESTINATION[Reticulum::DESTINATION_LENGTH] = {0};
public:
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(NoneConstructor none) {
extreme("Packet NONE object created");
}
Packet(RNS::NoneConstructor none) {
extreme("Packet NONE object created");
}
Packet(const Packet &packet) : _object(packet._object) {
extreme("Packet object copy created");
}
~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);
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) {}
virtual ~Packet();
inline Packet& operator = (const Packet &packet) {
_object = packet._object;
extreme("Packet object copy created by assignment, this: " + std::to_string((ulong)this) + ", data: " + std::to_string((uint32_t)_object.get()));
extreme("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 {
return _object.get() != nullptr;
}
inline bool operator < (const Packet &packet) const {
return _object.get() < packet._object.get();
}
private:
/*
@ -120,37 +242,59 @@ namespace RNS {
bool unpack();
bool send();
bool resend();
void prove(const Destination &destination = Destination::NONE);
void update_hash();
Bytes get_hash();
Bytes getTruncatedHash();
Bytes get_hashable_part();
const Bytes get_hash() const;
const Bytes getTruncatedHash() const;
const Bytes get_hashable_part() const;
//zProofDestination &generate_proof_destination();
// getters/setters
inline const Destination &destination() const { assert(_object); return _object->_destination; }
inline void destination(const Destination &destination) { assert(_object); _object->_destination = destination; }
inline const Link &link() const { assert(_object); return _object->_link; }
inline void link(const Link &link) { assert(_object); _object->_link = link; }
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 const Bytes &data() const { assert(_object); return _object->_data; }
inline const Bytes &raw() const { assert(_object); return _object->_raw; }
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; }
inline void sent_at(time_t sent_at) { assert(_object); _object->_sent_at = sent_at; }
inline bool create_receipt() const { assert(_object); return _object->_create_receipt; }
inline const PacketReceipt &receipt() const { assert(_object); return _object->_receipt; }
inline void receipt(const PacketReceipt &receipt) { assert(_object); _object->_receipt = receipt; }
inline uint8_t flags() const { assert(_object); return _object->_flags; }
inline uint8_t hops() const { assert(_object); return _object->_hops; }
inline void hops(uint8_t hops) { assert(_object); _object->_hops = hops; }
inline Bytes packet_hash() const { assert(_object); return _object->_packet_hash; }
inline Bytes destination_hash() const { assert(_object); return _object->_destination_hash; }
inline Bytes transport_id() const { assert(_object); return _object->_transport_id; }
inline void transport_id(const Bytes &transport_id) { assert(_object); _object->_transport_id = transport_id; }
inline const Bytes &raw() const { assert(_object); return _object->_raw; }
inline const Bytes &data() const { assert(_object); return _object->_data; }
inline std::string toString() const { assert(_object); return "{Packet:" + _object->_packet_hash.toHex() + "}"; }
std::string debugString();
std::string debugString() const;
private:
class Object {
public:
Object(const Destination &destination, const Interface &attached_interface) : _destination(destination), _attached_interface(attached_interface) {}
virtual ~Object() {}
private:
Destination _destination;
Destination _destination = {Destination::NONE};
Link _link = {Link::NONE};
Interface _attached_interface = {Interface::NONE};
Interface _receiving_interface = {Interface::NONE};
Interface _attached_interface;
Interface _receiving_interface;
header_types _header_type = HEADER_1;
Transport::types _transport_type = Transport::BROADCAST;
Destination::types _destination_type = Destination::SINGLE;
@ -166,7 +310,7 @@ namespace RNS {
bool _fromPacked = false;
bool _truncated = false; // whether data was truncated
bool _encrypted = false; // whether data is encrytpted
//z_receipt = nullptr;
PacketReceipt _receipt;
uint16_t _mtu = Reticulum::MTU;
time_t _sent_at = 0;
@ -186,20 +330,4 @@ namespace RNS {
std::shared_ptr<Object> _object;
};
class ProofDestination {
};
class PacketReceipt {
public:
class Callbacks {
public:
typedef void (*delivery)(PacketReceipt *packet_receipt);
typedef void (*timeout)(PacketReceipt *packet_receipt);
};
};
}

View File

@ -1,31 +1,134 @@
#include "Reticulum.h"
#include "Transport.h"
#include "Log.h"
#include <RNG.h>
using namespace RNS;
/*
Initialises and starts a Reticulum instance. This must be
done before any other operations, and Reticulum will not
pass any traffic before being instantiated.
:param configdir: Full path to a Reticulum configuration directory.
*/
//def __init__(self,configdir=None, loglevel=None, logdest=None, verbosity=None):
Reticulum::Reticulum() : _object(new Object()) {
extreme("Reticulum object created");
// Initialkize random number generator
RNG.begin("Reticulum");
//RNG.stir(mac_address, sizeof(mac_address));
/*
RNS.vendor.platformutils.platform_checks()
if configdir != None:
Reticulum.configdir = configdir
else:
if os.path.isdir("/etc/reticulum") and os.path.isfile("/etc/reticulum/config"):
Reticulum.configdir = "/etc/reticulum"
elif os.path.isdir(Reticulum.userdir+"/.config/reticulum") and os.path.isfile(Reticulum.userdir+"/.config/reticulum/config"):
Reticulum.configdir = Reticulum.userdir+"/.config/reticulum"
else:
Reticulum.configdir = Reticulum.userdir+"/.reticulum"
if logdest == RNS.LOG_FILE:
RNS.logdest = RNS.LOG_FILE
RNS.logfile = Reticulum.configdir+"/logfile"
Reticulum.configpath = Reticulum.configdir+"/config"
Reticulum.storagepath = Reticulum.configdir+"/storage"
Reticulum.cachepath = Reticulum.configdir+"/storage/cache"
Reticulum.resourcepath = Reticulum.configdir+"/storage/resources"
Reticulum.identitypath = Reticulum.configdir+"/storage/identities"
Reticulum.__transport_enabled = False
Reticulum.__use_implicit_proof = True
Reticulum.__allow_probes = False
Reticulum.panic_on_interface_error = False
self.local_interface_port = 37428
self.local_control_port = 37429
self.share_instance = True
self.rpc_listener = None
self.ifac_salt = Reticulum.IFAC_SALT
self.requested_loglevel = loglevel
self.requested_verbosity = verbosity
if self.requested_loglevel != None:
if self.requested_loglevel > RNS.LOG_EXTREME:
self.requested_loglevel = RNS.LOG_EXTREME
if self.requested_loglevel < RNS.LOG_CRITICAL:
self.requested_loglevel = RNS.LOG_CRITICAL
RNS.loglevel = self.requested_loglevel
self.is_shared_instance = False
self.is_connected_to_shared_instance = False
self.is_standalone_instance = False
self.jobs_thread = None
self.last_data_persist = time.time()
self.last_cache_clean = 0
if not os.path.isdir(Reticulum.storagepath):
os.makedirs(Reticulum.storagepath)
if not os.path.isdir(Reticulum.cachepath):
os.makedirs(Reticulum.cachepath)
if not os.path.isdir(Reticulum.resourcepath):
os.makedirs(Reticulum.resourcepath)
if not os.path.isdir(Reticulum.identitypath):
os.makedirs(Reticulum.identitypath)
if os.path.isfile(self.configpath):
try:
self.config = ConfigObj(self.configpath)
except Exception as e:
RNS.log("Could not parse the configuration at "+self.configpath, RNS.LOG_ERROR)
RNS.log("Check your configuration file for errors!", RNS.LOG_ERROR)
RNS.panic()
else:
RNS.log("Could not load config file, creating default configuration file...")
self.__create_default_config()
RNS.log("Default config file created. Make any necessary changes in "+Reticulum.configdir+"/config and restart Reticulum if needed.")
time.sleep(1.5)
self.__apply_config()
RNS.log("Configuration loaded from "+self.configpath, RNS.LOG_VERBOSE)
RNS.Identity.load_known_destinations()
*/
Transport::start(*this);
/*
self.rpc_addr = ("127.0.0.1", self.local_control_port)
self.rpc_key = RNS.Identity.full_hash(RNS.Transport.identity.get_private_key())
if self.is_shared_instance:
self.rpc_listener = multiprocessing.connection.Listener(self.rpc_addr, authkey=self.rpc_key)
thread = threading.Thread(target=self.rpc_loop)
thread.daemon = True
thread.start()
atexit.register(Reticulum.exit_handler)
signal.signal(signal.SIGINT, Reticulum.sigint_handler)
signal.signal(signal.SIGTERM, Reticulum.sigterm_handler)
*/
extreme("Reticulum object created");
}
Reticulum::~Reticulum() {
extreme("Reticulum object destroyed");
}
/*
Returns whether proofs sent are explicit or implicit.
:returns: True if the current running configuration specifies to use implicit proofs. False if not.
*/
/*static*/ bool Reticulum::should_use_implicit_proof() {
return __use_implicit_proof;
}
void Reticulum::loop() {
// Perform random number gnerator housekeeping

View File

@ -1,10 +1,11 @@
#pragma once
#include "Log.h"
#include "None.h"
#include <vector>
#include <memory>
#include <stdint.h>
#include <vector>
namespace RNS {
@ -86,31 +87,64 @@ namespace RNS {
static const bool panic_on_interface_error = false;
public:
Reticulum();
Reticulum(NoneConstructor none) {
extreme("Reticulum NONE object created");
}
Reticulum(RNS::NoneConstructor none) {
extreme("Reticulum NONE object created");
}
Reticulum(const Reticulum &reticulum) : _object(reticulum._object) {
extreme("Reticulum object copy created");
}
~Reticulum();
Reticulum();
virtual ~Reticulum();
inline Reticulum& operator = (const Reticulum &reticulum) {
_object = reticulum._object;
extreme("Reticulum object copy created by assignment, this: " + std::to_string((ulong)this) + ", data: " + std::to_string((uint32_t)_object.get()));
extreme("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 {
return _object.get() != nullptr;
}
inline bool operator < (const Reticulum &reticulum) const {
return _object.get() < reticulum._object.get();
}
public:
static bool should_use_implicit_proof();
void loop();
/*
Returns whether proofs sent are explicit or implicit.
:returns: True if the current running configuration specifies to use implicit proofs. False if not.
*/
inline static bool should_use_implicit_proof() { return __use_implicit_proof; }
/*
Returns whether Transport is enabled for the running
instance.
When Transport is enabled, Reticulum will
route traffic for other peers, respond to path requests
and pass announces over the network.
:returns: True if Transport is enabled, False if not.
*/
inline static bool transport_enabled() { return __transport_enabled; }
inline static bool probe_destination_enabled() { return __allow_probes; }
// getters/setters
inline bool is_connected_to_shared_instance() const { assert(_object); return _object->_is_connected_to_shared_instance; }
private:
class Object {
public:
Object() {}
virtual ~Object() {}
private:
bool _is_connected_to_shared_instance = false;
friend class Reticulum;
};
std::shared_ptr<Object> _object;

View File

@ -1,4 +1,4 @@
#include <unity.h>
//#include <unity.h>
#include "Bytes.h"
#include "Log.h"
@ -209,9 +209,9 @@ void testCowBytes() {
assert(memcmp(bytes3.data(), "1", bytes3.size()) == 0);
assert(bytes3.data() == bytes2.data());
RNS::extreme("pre bytes1 ptr: " + std::to_string((uint32_t)bytes1.data()) + " data: " + bytes1.toString());
RNS::extreme("pre bytes2 ptr: " + std::to_string((uint32_t)bytes2.data()) + " data: " + bytes2.toString());
RNS::extreme("pre bytes3 ptr: " + std::to_string((uint32_t)bytes3.data()) + " data: " + bytes3.toString());
RNS::extreme("pre bytes1 ptr: " + std::to_string((uintptr_t)bytes1.data()) + " data: " + bytes1.toString());
RNS::extreme("pre bytes2 ptr: " + std::to_string((uintptr_t)bytes2.data()) + " data: " + bytes2.toString());
RNS::extreme("pre bytes3 ptr: " + std::to_string((uintptr_t)bytes3.data()) + " data: " + bytes3.toString());
//bytes1.append("mississippi");
//assert(bytes1.size() == 12);
@ -228,9 +228,9 @@ void testCowBytes() {
assert(memcmp(bytes3.data(), "mississippi", bytes3.size()) == 0);
assert(bytes3.data() != bytes2.data());
RNS::extreme("post bytes1 ptr: " + std::to_string((uint32_t)bytes1.data()) + " data: " + bytes1.toString());
RNS::extreme("post bytes2 ptr: " + std::to_string((uint32_t)bytes2.data()) + " data: " + bytes2.toString());
RNS::extreme("post bytes3 ptr: " + std::to_string((uint32_t)bytes3.data()) + " data: " + bytes3.toString());
RNS::extreme("post bytes1 ptr: " + std::to_string((uintptr_t)bytes1.data()) + " data: " + bytes1.toString());
RNS::extreme("post bytes2 ptr: " + std::to_string((uintptr_t)bytes2.data()) + " data: " + bytes2.toString());
RNS::extreme("post bytes3 ptr: " + std::to_string((uintptr_t)bytes3.data()) + " data: " + bytes3.toString());
}
void testBytesConversion() {
@ -331,8 +331,15 @@ void testMap()
}
/*
int main(void)
{
void setUp(void) {
// set stuff up here
}
void tearDown(void) {
// clean stuff up here
}
int runUnityTests(void) {
UNITY_BEGIN();
RUN_TEST(testBytes);
RUN_TEST(testCowBytes);
@ -340,4 +347,24 @@ int main(void)
RUN_TEST(testMap);
return UNITY_END();
}
// For native dev-platform or for some embedded frameworks
int main(void) {
return runUnityTests();
}
// For Arduino framework
void setup() {
// Wait ~2 seconds before the Unity test runner
// establishes connection with a board Serial interface
delay(2000);
runUnityTests();
}
void loop() {}
// For ESP-IDF framework
void app_main() {
runUnityTests();
}
*/

View File

@ -1,4 +1,4 @@
#include <unity.h>
//#include <unity.h>
#include "Reticulum.h"
#include "Identity.h"

View File

@ -1,4 +1,4 @@
#include <unity.h>
//#include <unity.h>
#include "Reticulum.h"
#include "Bytes.h"

File diff suppressed because it is too large Load Diff

View File

@ -1,29 +1,150 @@
#pragma once
#include "Reticulum.h"
#include "Link.h"
// CBA TODO resolve circular dependency with following header file
//#include "Packet.h"
#include "Bytes.h"
#include "None.h"
#include "Interfaces/Interface.h"
#include <memory>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <functional>
#include <stdint.h>
namespace RNS {
class Packet;
class PacketReceipt;
class Destination;
class Interface;
class Link;
class Identity;
class AnnounceHandler {
public:
AnnounceHandler(const std::string &aspect_filter) {
_aspect_filter = aspect_filter;
}
virtual void received_announce(const Bytes &destination_hash, const Identity &announced_identity, const Bytes &app_data) = 0;
private:
std::string _aspect_filter;
};
using HAnnounceHandler = std::shared_ptr<AnnounceHandler>;
/*
Through static methods of this class you can interact with the
Transport system of Reticulum.
*/
class Transport {
private:
class DestinationEntry {
public:
DestinationEntry(uint64_t time, Bytes received_from, uint8_t announce_hops, uint64_t expires, std::set<Bytes> random_blobs, Interface &receiving_interface, const Packet &packet) :
_timestamp(time),
_received_from(received_from),
_hops(announce_hops),
_expires(expires),
_random_blobs(random_blobs),
_receiving_interface(receiving_interface),
_packet(packet)
{
}
public:
uint64_t _timestamp = 0;
Bytes _received_from;
uint8_t _hops = 0;
uint64_t _expires = 0;
std::set<Bytes> _random_blobs;
Interface &_receiving_interface;
const Packet &_packet;
};
class AnnounceEntry {
public:
AnnounceEntry(uint64_t timestamp, uint16_t retransmit_timeout, uint8_t retries, Bytes received_from, uint8_t hops, const Packet &packet, uint8_t local_rebroadcasts, bool block_rebroadcasts, const Interface &attached_interface) :
_timestamp(timestamp),
_retransmit_timeout(retransmit_timeout),
_retries(retries),
_received_from(received_from),
_hops(hops),
_packet(packet),
_local_rebroadcasts(local_rebroadcasts),
_block_rebroadcasts(block_rebroadcasts),
_attached_interface(attached_interface)
{
}
public:
uint64_t _timestamp = 0;
uint16_t _retransmit_timeout = 0;
uint8_t _retries = 0;
Bytes _received_from;
uint8_t _hops = 0;
const Packet &_packet;
uint8_t _local_rebroadcasts = 0;
bool _block_rebroadcasts = false;
const Interface &_attached_interface;
};
class LinkEntry {
public:
LinkEntry(uint64_t timestamp, const Bytes &next_hop, const Interface &outbound_interface, uint8_t remaining_hops, const Interface &receiving_interface, uint8_t hops, const Bytes &destination_hash, bool validated, uint64_t proof_timeout) :
_timestamp(timestamp),
_next_hop(next_hop),
_outbound_interface(outbound_interface),
_remaining_hops(remaining_hops),
_receiving_interface(receiving_interface),
_hops(hops),
_destination_hash(destination_hash),
_validated(validated),
_proof_timeout(proof_timeout)
{
}
public:
uint64_t _timestamp = 0;
Bytes _next_hop;
const Interface &_outbound_interface;
uint8_t _remaining_hops = 0;
const Interface &_receiving_interface;
uint8_t _hops = 0;
Bytes _destination_hash;
bool _validated = false;
uint64_t _proof_timeout = 0;
};
class ReverseEntry {
public:
ReverseEntry(const Interface &receiving_interface, const Interface &outbound_interface, uint64_t timestamp) :
_receiving_interface(receiving_interface),
_outbound_interface(outbound_interface),
_timestamp(timestamp)
{
}
public:
const Interface &_receiving_interface;
const Interface &_outbound_interface;
uint64_t _timestamp = 0;
};
public:
// Constants
enum types {
BROADCAST = 0x00,
TRANSPORT = 0x01,
RELAY = 0x02,
TUNNEL = 0x03,
NONE = 0xFF,
BROADCAST = 0x00,
TRANSPORT = 0x01,
RELAY = 0x02,
TUNNEL = 0x03,
NONE = 0xFF,
};
enum reachabilities {
REACHABILITY_UNREACHABLE = 0x00,
REACHABILITY_DIRECT = 0x01,
REACHABILITY_TRANSPORT = 0x02,
REACHABILITY_UNREACHABLE = 0x00,
REACHABILITY_DIRECT = 0x01,
REACHABILITY_TRANSPORT = 0x02,
};
static constexpr const char* APP_NAME = "rnstransport";
@ -54,13 +175,112 @@ namespace RNS {
static const uint8_t MAX_RATE_TIMESTAMPS = 16; // Maximum number of announce timestamps to keep per destination
public:
Transport();
~Transport();
public:
static void start(const Reticulum &reticulum_instance);
static void jobloop();
static void jobs();
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 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);
static void register_interface(Interface &interface);
static void deregister_interface(const Interface &interface);
static void register_destination(Destination &destination);
static bool outbound(const Packet &packet);
static void deregister_destination(const Destination &destination);
static void register_link(const Link &link);
static void activate_link(Link &link);
static void register_announce_handler(HAnnounceHandler handler);
static void deregister_announce_handler(HAnnounceHandler handler);
static Interface find_interface_from_hash(const Bytes &interface_hash);
static bool should_cache(const Packet &packet);
static void cache(const Packet &packet, bool force_cache = false);
static Packet get_cached_packet(const Bytes &packet_hash);
static bool cache_request_packet(const Packet &packet);
static void cache_request(const Bytes &packet_hash, const Destination &destination);
static bool has_path(const Bytes &destination_hash);
static uint8_t hops_to(const Bytes &destination_hash);
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 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);
static bool is_local_client_interface(const Interface &interface);
static bool interface_to_shared_instance(const Interface &interface);
static void detach_interfaces();
static void shared_connection_disappeared();
static void shared_connection_reappeared();
static void drop_announce_queues();
static bool announce_emitted(const Packet &packet);
static void save_packet_hashlist();
static void save_path_table();
static void save_tunnel_table();
static void persist_data();
static void exit_handler();
private:
//static std::set<std::reference_wrapper<const Interface>, std::less<const Interface>> _interfaces; // All active interfaces
static std::list<std::reference_wrapper<Interface>> _interfaces; // All active interfaces
static std::set<Destination> _destinations; // All active destinations
//static std::map<Bytes, Destination> _destinations; // All active destinations
static std::set<Link> _pending_links; // Links that are being established
static std::set<Link> _active_links; // Links that are active
static std::set<Bytes> _packet_hashlist; // A list of packet hashes for duplicate detection
static std::set<PacketReceipt> _receipts; // Receipts of all outgoing packets for proof processing
// TODO: "destination_table" should really be renamed to "path_table"
// Notes on memory usage: 1 megabyte of memory can store approximately
// 55.100 path table entries or approximately 22.300 link table entries.
static std::map<Bytes, AnnounceEntry> _announce_table; // A table for storing announces currently waiting to be retransmitted
static std::map<Bytes, DestinationEntry> _destination_table; // A lookup table containing the next hop to a given destination
static std::map<Bytes, ReverseEntry> _reverse_table; // A lookup table for storing packet hashes used to return proofs and replies
static std::map<Bytes, LinkEntry> _link_table; // A lookup table containing hops for links
static std::map<Bytes, AnnounceEntry> _held_announces; // A table containing temporarily held announce-table entries
static std::set<HAnnounceHandler> _announce_handlers; // A table storing externally registered announce handlers
//z_tunnels = {} // A table storing tunnels to other transport instances
//z_announce_rate_table = {} // A table for keeping track of announce rates
static std::set<Bytes> _path_requests; // A table for storing path request timestamps
//z_discovery_path_requests = {} // A table for keeping track of path requests on behalf of other nodes
//z_discovery_pr_tags = [] // A table for keeping track of tagged path requests
static uint16_t _max_pr_taXgxs; // Maximum amount of unique path request tags to remember
// Transport control destinations are used
// for control purposes like path requests
static std::set<Destination> _control_destinations;
static std::set<Bytes> _control_hashes;
// Interfaces for communicating with
// local clients connected to a shared
// Reticulum instance
static std::set<Interface> _local_client_interfaces;
//z_local_client_rssi_cache = []
//z_local_client_snr_cache = []
static uint16_t _LOCAL_CLIENT_CACHE_MAXSIZE;
std::map<Bytes, Interface> _pending_local_path_requests;
static uint64_t _start_time;
static bool _jobs_locked;
static bool _jobs_running;
static uint32_t _job_interval;
static uint64_t _links_last_checked;
static uint32_t _links_check_interval;
static uint64_t _receipts_last_checked;
static uint32_t _receipts_check_interval;
static uint64_t _announces_last_checked;
static uint32_t _announces_check_interval;
static uint32_t _hashlist_maxsize;
static uint64_t _tables_last_culled;
static uint32_t _tables_cull_interval;
static Reticulum _owner;
static Identity _identity;
};
}

23
src/Utilities/OS.h Normal file
View File

@ -0,0 +1,23 @@
#pragma once
#include <cmath>
#include <unistd.h>
#include <time.h>
#include <stdint.h>
#include <sys/time.h>
namespace RNS { namespace Utilities {
class OS {
public:
// 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; }
};
} }

View File

@ -6,6 +6,7 @@
#include "Identity.h"
#include "Destination.h"
#include "Packet.h"
#include "Interfaces/Interface.h"
#include "Bytes.h"
#ifndef NATIVE
@ -17,6 +18,7 @@
#include <string>
#include <vector>
#include <map>
#include <functional>
//#include <sstream>
// Let's define an app name. We'll use this for all
@ -29,9 +31,98 @@ const char* APP_NAME = "example_utilities";
const char* fruits[] = {"Peach", "Quince", "Date", "Tangerine", "Pomelo", "Carambola", "Grape"};
const char* noble_gases[] = {"Helium", "Neon", "Argon", "Krypton", "Xenon", "Radon", "Oganesson"};
class TestInterface : public RNS::Interface {
public:
TestInterface() : RNS::Interface("TestInterface") {
IN(true);
OUT(true);
}
TestInterface(const char *name) : RNS::Interface(name) {
IN(true);
OUT(true);
}
virtual ~TestInterface() {
name("deleted");
}
virtual void processIncoming(const RNS::Bytes &data) {
RNS::extreme("TestInterface.processIncoming: data: " + data.toHex());
}
virtual void processOutgoing(const RNS::Bytes &data) {
RNS::extreme("TestInterface.processOutgoing: data: " + data.toHex());
}
virtual inline std::string toString() const { return "TestInterface[" + name() + "]"; }
};
class TestLoopbackInterface : public RNS::Interface {
public:
TestLoopbackInterface(RNS::Interface &loopback_interface) : RNS::Interface("TestLoopbackInterface"), _loopback_interface(loopback_interface) {
IN(true);
OUT(true);
}
TestLoopbackInterface(RNS::Interface &loopback_interface, const char *name) : RNS::Interface(name), _loopback_interface(loopback_interface) {
IN(true);
OUT(true);
}
virtual ~TestLoopbackInterface() {
name("deleted");
}
virtual void processIncoming(const RNS::Bytes &data) {
RNS::extreme("TestLoopbackInterface.processIncoming: data: " + data.toHex());
_loopback_interface.processOutgoing(data);
}
virtual void processOutgoing(const RNS::Bytes &data) {
RNS::extreme("TestLoopbackInterface.processOutgoing: data: " + data.toHex());
_loopback_interface.processIncoming(data);
}
virtual inline std::string toString() const { return "TestLoopbackInterface[" + name() + "]"; }
private:
RNS::Interface &_loopback_interface;
};
class TestOutInterface : public RNS::Interface {
public:
TestOutInterface() : RNS::Interface("TestOutInterface") {
OUT(true);
IN(false);
}
TestOutInterface(const char *name) : RNS::Interface(name) {
OUT(true);
IN(false);
}
virtual ~TestOutInterface() {
name("(deleted)");
}
virtual void processOutgoing(const RNS::Bytes &data) {
RNS::head("TestOutInterface.processOutgoing: data: " + data.toHex(), RNS::LOG_EXTREME);
RNS::Interface::processOutgoing(data);
}
virtual inline std::string toString() const { return "TestOutInterface[" + name() + "]"; }
};
class TestInInterface : public RNS::Interface {
public:
TestInInterface() : RNS::Interface("TestInInterface") {
OUT(false);
IN(true);
}
TestInInterface(const char *name) : RNS::Interface(name) {
OUT(false);
IN(true);
}
virtual ~TestInInterface() {
name("(deleted)");
}
virtual void processIncoming(const RNS::Bytes &data) {
RNS::head("TestInInterface.processIncoming: data: " + data.toHex(), RNS::LOG_EXTREME);
RNS::Interface::processIncoming(data);
}
virtual inline std::string toString() const { return "TestInInterface[" + name() + "]"; }
};
void onPacket(const RNS::Bytes &data, const RNS::Packet &packet) {
RNS::extreme("onPacket: data: " + data.toHex());
RNS::extreme("onPacket: data string: \"" + data.toString() + "\"");
RNS::head("onPacket: data: " + data.toHex(), RNS::LOG_EXTREME);
RNS::head("onPacket: data string: \"" + data.toString() + "\"", RNS::LOG_EXTREME);
//RNS::head("onPacket: " + packet.debugString(), RNS::LOG_EXTREME);
}
void setup() {
@ -46,7 +137,11 @@ void setup() {
#ifndef NDEBUG
RNS::loglevel(RNS::LOG_WARNING);
//RNS::loglevel(RNS::LOG_EXTREME);
RNS::extreme("Running tests...");
test();
//testReference();
//testCrypto();
RNS::extreme("Finished running tests");
#endif
//std::stringstream test;
@ -59,22 +154,58 @@ void setup() {
// 21.8% baseline here with serial
RNS::head("Creating Reticulum instance...", RNS::LOG_EXTREME);
RNS::Reticulum reticulum;
// 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::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::Destination::IN, RNS::Destination::SINGLE, "test", "context");
// 23.0% (+0.4%)
/*
RNS::head("Testing map...", RNS::LOG_EXTREME);
{
std::map<RNS::Bytes, RNS::Destination&> destinations;
destinations.insert({destination.hash(), destination});
//for (RNS::Destination &destination : destinations) {
for (auto &[hash, destination] : destinations) {
RNS::extreme("Iterated destination: " + destination.toString());
}
RNS::Bytes hash = destination.hash();
auto iter = destinations.find(hash);
if (iter != destinations.end()) {
RNS::Destination &destination = (*iter).second;
RNS::extreme("Found destination: " + destination.toString());
}
return;
}
*/
destination.set_proof_strategy(RNS::Destination::PROVE_ALL);
//zRNS::head("Registering announce handler with Transport...", RNS::LOG_EXTREME);
//zannounce_handler = ExampleAnnounceHandler(
//z aspect_filter="example_utilities.announcesample.fruits";
//z)
//zRNS::Transport.register_announce_handler(announce_handler);
RNS::head("Announcing destination...", RNS::LOG_EXTREME);
//destination.announce(RNS::bytesFromString(fruits[rand() % 7]));
// test path
//destination.announce(RNS::bytesFromString(fruits[rand() % 7]), true, nullptr, RNS::bytesFromString("test_tag"));
@ -82,17 +213,27 @@ 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");
RNS::head("Sending send packet...", RNS::LOG_EXTREME);
send_packet.pack();
RNS::extreme("Test send_packet packet: " + send_packet.debugString());
RNS::extreme("Test send_packet: " + send_packet.debugString());
// test data receive packet
RNS::head("Registering packet callback with Destination...", RNS::LOG_EXTREME);
destination.set_packet_callback(onPacket);
RNS::head("Creating recv packet...", RNS::LOG_EXTREME);
RNS::Packet recv_packet(RNS::Destination::NONE, send_packet.raw());
recv_packet.unpack();
RNS::extreme("Test recv_packet packet: " + recv_packet.debugString());
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) {
@ -110,6 +251,83 @@ void loop() {
int main(void) {
printf("Hello from Native on PlatformIO!\n");
/*
RNS::loglevel(RNS::LOG_EXTREME);
TestInterface testinterface;
std::set<std::reference_wrapper<RNS::Interface>, std::less<RNS::Interface>> interfaces;
interfaces.insert(testinterface);
for (auto iter = interfaces.begin(); iter != interfaces.end(); ++iter) {
RNS::Interface &interface = (*iter);
RNS::extreme("Found interface: " + interface.toString());
RNS::Bytes data;
const_cast<RNS::Interface&>(interface).processOutgoing(data);
}
return 0;
*/
/*
RNS::loglevel(RNS::LOG_EXTREME);
TestInterface testinterface;
std::set<std::reference_wrapper<RNS::Interface>, std::less<RNS::Interface>> interfaces;
interfaces.insert(testinterface);
for (auto &interface : interfaces) {
RNS::extreme("Found interface: " + interface.toString());
RNS::Bytes data;
const_cast<RNS::Interface&>(interface).processOutgoing(data);
}
return 0;
*/
/*
RNS::loglevel(RNS::LOG_EXTREME);
TestInterface testinterface;
std::list<std::reference_wrapper<RNS::Interface>> interfaces;
interfaces.push_back(testinterface);
for (auto iter = interfaces.begin(); iter != interfaces.end(); ++iter) {
RNS::Interface &interface = (*iter);
RNS::extreme("Found interface: " + interface.toString());
RNS::Bytes data;
const_cast<RNS::Interface&>(interface).processOutgoing(data);
}
return 0;
*/
/*
RNS::loglevel(RNS::LOG_EXTREME);
TestInterface testinterface;
std::list<std::reference_wrapper<RNS::Interface>> interfaces;
interfaces.push_back(testinterface);
//for (auto &interface : interfaces) {
for (RNS::Interface &interface : interfaces) {
RNS::extreme("Found interface: " + interface.toString());
RNS::Bytes data;
const_cast<RNS::Interface&>(interface).processOutgoing(data);
}
return 0;
*/
/*
std::list<std::reference_wrapper<RNS::Interface>> interfaces;
{
RNS::loglevel(RNS::LOG_EXTREME);
TestInterface testinterface;
interfaces.push_back(testinterface);
for (auto iter = interfaces.begin(); iter != interfaces.end(); ++iter) {
RNS::Interface &interface = (*iter);
RNS::extreme("1 Found interface: " + interface.toString());
RNS::Bytes data;
const_cast<RNS::Interface&>(interface).processOutgoing(data);
}
}
for (auto iter = interfaces.begin(); iter != interfaces.end(); ++iter) {
RNS::Interface &interface = (*iter);
RNS::extreme("2 Found interface: " + interface.toString());
RNS::Bytes data;
const_cast<RNS::Interface&>(interface).processOutgoing(data);
}
return 0;
*/
setup();
//while (true) {