WIP: Fixes, optimizations, and more Transport

Changed all time references to use decimal seconds to match Python
reference implementation.
Fixed memory issues caused by storing references to objects instead of
copies.
More implementation of Transport logic.
This is the first build that fully implements end-to-end path finding
and routing.
This commit is contained in:
attermann 2023-12-02 08:52:45 -07:00
parent ea7b4603ed
commit 642486ac7e
28 changed files with 958 additions and 261 deletions

View File

@ -55,3 +55,5 @@ build_flags =
-Isrc
lib_deps =
rweather/Crypto@^0.4.0
sandeepmistry/LoRa@^0.8.0
WiFi@^2.0.0

View File

@ -53,7 +53,7 @@ const Bytes Fernet::encrypt(const Bytes& data) {
debug("Fernet::encrypt: plaintext length: " + std::to_string(data.size()));
Bytes iv = random(16);
//time_t current_time = time(nullptr);
//double current_time = OS::time();
extreme("Fernet::encrypt: iv: " + iv.toHex());
extreme("Fernet::encrypt: plaintext: " + data.toHex());

View File

@ -11,6 +11,7 @@
using namespace RNS;
using namespace RNS::Type::Destination;
using namespace RNS::Utilities;
Destination::Destination(const Identity& identity, const directions direction, const types type, const char* app_name, const char* aspects) : _object(new Object(identity)) {
assert(_object);
@ -20,6 +21,7 @@ Destination::Destination(const Identity& identity, const directions direction, c
if (strchr(app_name, '.') != nullptr) {
throw std::invalid_argument("Dots can't be used in app names");
}
debug("Destination::Destination: app name: " + std::string(app_name));
_object->_type = type;
_object->_direction = direction;
@ -156,7 +158,7 @@ Packet Destination::announce(const Bytes& app_data, bool path_response, const In
throw std::invalid_argument("Only IN destination types can be announced");
}
time_t now = time(nullptr);
double now = OS::time();
auto it = _object->_path_responses.begin();
while (it != _object->_path_responses.end()) {
// vector
@ -228,7 +230,8 @@ Packet Destination::announce(const Bytes& app_data, bool path_response, const In
debug("Destination::announce: public key: " + _object->_identity.get_public_key().toHex());
debug("Destination::announce: name hash: " + _object->_name_hash.toHex());
debug("Destination::announce: random hash: " + random_hash.toHex());
debug("Destination::announce: new app data: " + new_app_data.toHex());
debug("Destination::announce: app data: " + new_app_data.toHex());
debug("Destination::announce: app data text:" + new_app_data.toString());
signed_data << _object->_hash << _object->_identity.get_public_key() << _object->_name_hash << random_hash;
if (new_app_data) {
signed_data << new_app_data;
@ -244,7 +247,7 @@ Packet Destination::announce(const Bytes& app_data, bool path_response, const In
announce_data << new_app_data;
}
_object->_path_responses.insert({tag, {time(nullptr), announce_data}});
_object->_path_responses.insert({tag, {OS::time(), announce_data}});
}
debug("Destination::announce: announce_data:" + announce_data.toHex());

View File

@ -50,9 +50,7 @@ namespace RNS {
friend class Detination;
};
//typedef std::pair<time_t, std::string> Response;
using PathResponse = std::pair<time_t, Bytes>;
//using PathResponse = std::pair<time_t, std::vector<uint8_t>>;
using PathResponse = std::pair<double, Bytes>;
public:
Destination(Type::NoneConstructor none) {
@ -184,7 +182,6 @@ namespace RNS {
Type::Destination::proof_strategies _proof_strategy = Type::Destination::PROVE_NONE;
uint16_t _mtu = 0;
//std::vector<PathResponse> _path_responses;
std::map<Bytes, PathResponse> _path_responses;
//z _links = []

View File

@ -64,19 +64,26 @@ Load a private key into the instance.
*/
bool Identity::load_private_key(const Bytes& prv_bytes) {
assert(_object);
try {
//p self.prv_bytes = prv_bytes[:Identity.KEYSIZE//8//2]
_object->_prv_bytes = prv_bytes.left(Type::Identity::KEYSIZE/8/2);
_object->_prv = X25519PrivateKey::from_private_bytes(_object->_prv_bytes);
debug("Identity::load_private_key: prv bytes: " + _object->_prv_bytes.toHex());
//p self.sig_prv_bytes = prv_bytes[Identity.KEYSIZE//8//2:]
_object->_sig_prv_bytes = prv_bytes.mid(Type::Identity::KEYSIZE/8/2);
_object->_sig_prv = Ed25519PrivateKey::from_private_bytes(_object->_sig_prv_bytes);
debug("Identity::load_private_key: sig prv bytes: " + _object->_sig_prv_bytes.toHex());
_object->_pub = _object->_prv->public_key();
_object->_pub_bytes = _object->_pub->public_bytes();
debug("Identity::load_private_key: pub bytes: " + _object->_pub_bytes.toHex());
_object->_sig_pub = _object->_sig_prv->public_key();
_object->_sig_pub_bytes = _object->_sig_pub->public_bytes();
debug("Identity::load_private_key: sig pub bytes: " + _object->_sig_pub_bytes.toHex());
update_hashes();
@ -98,11 +105,16 @@ Load a public key into the instance.
*/
void Identity::load_public_key(const Bytes& pub_bytes) {
assert(_object);
try {
//_pub_bytes = pub_bytes[:Identity.KEYSIZE//8//2]
_object->_pub_bytes = pub_bytes.left(Type::Identity::KEYSIZE/8/2);
debug("Identity::load_public_key: pub bytes: " + _object->_pub_bytes.toHex());
//_sig_pub_bytes = pub_bytes[Identity.KEYSIZE//8//2:]
_object->_sig_pub_bytes = pub_bytes.mid(Type::Identity::KEYSIZE/8/2);
debug("Identity::load_public_key: sig pub bytes: " + _object->_sig_pub_bytes.toHex());
_object->_pub = X25519PublicKey::from_public_bytes(_object->_pub_bytes);
_object->_sig_pub = Ed25519PublicKey::from_public_bytes(_object->_sig_pub_bytes);
@ -203,10 +215,10 @@ Recall last heard app_data for a destination hash.
if (_saving_known_destinations) {
double wait_interval = 0.2;
double wait_timeout = 5;
double wait_start = OS::dtime();
double wait_start = OS::time();
while (_saving_known_destinations) {
OS::sleep(wait_interval);
if (OS::dtime() > (wait_start + wait_timeout)) {
if (OS::time() > (wait_start + wait_timeout)) {
error("Could not save known destinations to storage, waiting for previous save operation timed out.");
return false;
}
@ -214,7 +226,7 @@ Recall last heard app_data for a destination hash.
}
_saving_known_destinations = true;
double save_start = OS::dtime();
double save_start = OS::time();
std::map<Bytes, IdentityEntry> storage_known_destinations;
// TODO
@ -245,7 +257,7 @@ Recall last heard app_data for a destination hash.
*/
std::string time_str;
double save_time = OS::dtime() - save_start;
double save_time = OS::time() - save_start;
if (save_time < 1) {
time_str = std::to_string(OS::round(save_time*1000, 2)) + "ms";
}
@ -302,6 +314,7 @@ Recall last heard app_data for a destination hash.
app_data = packet.data().mid(KEYSIZE/8 + NAME_HASH_LENGTH/8 + RANDOM_HASH_LENGTH/8 + SIGLENGTH/8);
}
extreme("Identity::validate_announce: app_data: " + app_data.toHex());
extreme("Identity::validate_announce: app_data text: " + app_data.toString());
Bytes signed_data;
signed_data << packet.destination_hash() << public_key << name_hash << random_hash+app_data;

View File

@ -22,7 +22,7 @@ namespace RNS {
private:
class IdentityEntry {
public:
IdentityEntry(uint64_t timestamp, const Bytes& packet_hash, const Bytes& public_key, const Bytes& app_data) :
IdentityEntry(double timestamp, const Bytes& packet_hash, const Bytes& public_key, const Bytes& app_data) :
_timestamp(timestamp),
_packet_hash(packet_hash),
_public_key(public_key),
@ -30,7 +30,7 @@ namespace RNS {
{
}
public:
uint64_t _timestamp = 0;
double _timestamp = 0;
Bytes _packet_hash;
Bytes _public_key;
Bytes _app_data;

View File

@ -50,10 +50,13 @@ void Interface::process_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
double now = OS::time();
uint32_t wait_time = 0;
if (_object->_bitrate > 0 && _object->_announce_cap > 0) {
uint32_t tx_time = (len(selected["raw"])*8) / _object->_bitrate;
wait_time = (tx_time / _object->_announce_cap);
}
_object->_announce_allowed_at = now + wait_time;
self.processOutgoing(selected["raw"])

View File

@ -16,7 +16,7 @@ namespace RNS {
class AnnounceEntry {
public:
AnnounceEntry() {}
AnnounceEntry(const Bytes& destination, uint64_t time, uint8_t hops, uint64_t emitted, const Bytes& raw) :
AnnounceEntry(const Bytes& destination, double time, uint8_t hops, double emitted, const Bytes& raw) :
_destination(destination),
_time(time),
_hops(hops),
@ -24,9 +24,9 @@ namespace RNS {
_raw(raw) {}
public:
Bytes _destination;
uint64_t _time = 0;
double _time = 0;
uint8_t _hops = 0;
uint64_t _emitted = 0;
double _emitted = 0;
Bytes _raw;
};
@ -40,19 +40,19 @@ namespace RNS {
public:
Interface(Type::NoneConstructor none) {
mem("Interface object NONE created");
mem("Interface object NONE created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
}
Interface(const Interface& interface) : _object(interface._object) {
mem("Interface object copy created");
mem("Interface object copy created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
}
Interface() : _object(new Object()) {
mem("Interface object created");
mem("Interface object created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
}
Interface(const char* name) : _object(new Object(name)) {
mem("Interface object created");
mem("Interface object created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
}
virtual ~Interface() {
mem("Interface object destroyed");
mem("Interface object destroyed, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
}
inline Interface& operator = (const Interface& interface) {
@ -86,7 +86,7 @@ namespace RNS {
inline void name(const char* name) { assert(_object); _object->_name = name; }
inline void bitrate(uint32_t bitrate) { assert(_object); _object->_bitrate = bitrate; }
inline void online(bool online) { assert(_object); _object->_online = online; }
inline void announce_allowed_at(uint64_t announce_allowed_at) { assert(_object); _object->_announce_allowed_at = announce_allowed_at; }
inline void announce_allowed_at(double announce_allowed_at) { assert(_object); _object->_announce_allowed_at = announce_allowed_at; }
public:
inline bool IN() const { assert(_object); return _object->_IN; }
inline bool OUT() const { assert(_object); return _object->_OUT; }
@ -97,7 +97,7 @@ namespace RNS {
inline const Bytes& ifac_identity() const { assert(_object); return _object->_ifac_identity; }
inline Type::Interface::modes mode() const { assert(_object); return _object->_mode; }
inline uint32_t bitrate() const { assert(_object); return _object->_bitrate; }
inline uint64_t announce_allowed_at() const { assert(_object); return _object->_announce_allowed_at; }
inline double announce_allowed_at() const { assert(_object); return _object->_announce_allowed_at; }
inline float announce_cap() const { assert(_object); return _object->_announce_cap; }
inline std::list<AnnounceEntry>& announce_queue() const { assert(_object); return _object->_announce_queue; }
inline bool is_connected_to_shared_instance() const { assert(_object); return _object->_is_connected_to_shared_instance; }
@ -106,12 +106,18 @@ namespace RNS {
virtual inline std::string toString() const { assert(_object); return "Interface[" + _object->_name + "]"; }
inline std::string debugString() const {
std::string dump;
dump = "Interface object, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get());
return dump;
}
private:
class Object {
public:
Object() {}
Object(const char* name) : _name(name) {}
virtual ~Object() {}
Object() { mem("Interface::Data object created, this: " + std::to_string((uintptr_t)this)); }
Object(const char* name) : _name(name) { mem("Interface::Data object created, this: " + std::to_string((uintptr_t)this)); }
virtual ~Object() { mem("Interface::Data object destroyed, this: " + std::to_string((uintptr_t)this)); }
private:
bool _IN = false;
bool _OUT = false;
@ -124,7 +130,7 @@ namespace RNS {
Bytes _ifac_identity;
Type::Interface::modes _mode = Type::Interface::MODE_NONE;
uint32_t _bitrate = 0;
uint64_t _announce_allowed_at = 0;
double _announce_allowed_at = 0;
float _announce_cap = 0.0;
std::list<AnnounceEntry> _announce_queue;
bool _is_connected_to_shared_instance = false;

View File

@ -0,0 +1,132 @@
#include "LoRaInterface.h"
#include "../Log.h"
#include "../Utilities/OS.h"
#include <memory>
using namespace RNS;
using namespace RNS::Interfaces;
/*
@staticmethod
def get_address_for_if(name):
import RNS.vendor.ifaddr.niwrapper as netinfo
ifaddr = netinfo.ifaddresses(name)
return ifaddr[netinfo.AF_INET][0]["addr"]
@staticmethod
def get_broadcast_for_if(name):
import RNS.vendor.ifaddr.niwrapper as netinfo
ifaddr = netinfo.ifaddresses(name)
return ifaddr[netinfo.AF_INET][0]["broadcast"]
*/
LoRaInterface::LoRaInterface(const char* name /*= "LoRaInterface"*/) : Interface(name) {
IN(true);
OUT(true);
//p self.bitrate = self.r_sf * ( (4.0/self.r_cr) / (math.pow(2,self.r_sf)/(self.r_bandwidth/1000)) ) * 1000
bitrate((double)spreading * ( (4.0/coding) / (pow(2, spreading)/(bandwidth/1000.0)) ) * 1000.0);
}
/*virtual*/ LoRaInterface::~LoRaInterface() {
stop();
}
bool LoRaInterface::start() {
online(false);
info("LoRa initializing...");
#ifdef ARDUINO
SPI.begin(RADIO_SCLK_PIN, RADIO_MISO_PIN, RADIO_MOSI_PIN);
delay(1500);
LoRa.setPins(RADIO_CS_PIN, RADIO_RST_PIN, RADIO_DIO0_PIN);
// initialize radio
if (!LoRa.begin(frequency)) {
error("LoRa init failed. Check your connections.");
return false;
}
LoRa.setSignalBandwidth(bandwidth);
LoRa.setSpreadingFactor(spreading);
LoRa.setCodingRate4(coding);
LoRa.setPreambleLength(20);
LoRa.setTxPower(power);
info("LoRa init succeeded.");
extreme("LoRa bandwidth is " + std::to_string(Utilities::OS::round(bitrate()/1000.0, 2)) + " Kbps");
#endif
online(true);
return true;
}
void LoRaInterface::stop() {
#ifdef ARDUINO
#endif
online(false);
}
void LoRaInterface::loop() {
if (online()) {
// Check for incoming packet
#ifdef ARDUINO
int available = LoRa.parsePacket();
if (available > 0) {
Serial.println(available);
extreme("LoRaInterface: receiving bytes...");
// read packet
buffer.clear();
while (LoRa.available()) {
buffer << (uint8_t)LoRa.read();
}
Serial.println("RSSI: " + String(LoRa.packetRssi()));
Serial.println("Snr: " + String(LoRa.packetSnr()));
processIncoming(buffer);
}
#endif
}
}
/*virtual*/ void LoRaInterface::processIncoming(const Bytes& data) {
debug("LoRaInterface.processIncoming: data: " + data.toHex());
Interface::processIncoming(data);
}
/*virtual*/ void LoRaInterface::processOutgoing(const Bytes& data) {
debug("LoRaInterface.processOutgoing: data: " + data.toHex());
try {
if (online()) {
extreme("LoRaInterface: sending " + std::to_string(data.size()) + " bytes...");
// Send packet
#ifdef ARDUINO
LoRa.beginPacket(); // start packet
// add payload
//LoRa.print((const char*)data.data());
for (size_t i = 0; i < data.size(); ++i) {
LoRa.write(data.data()[i]);
}
LoRa.endPacket(); // finish packet and send it
#endif
extreme("LoRaInterface: sent bytes");
}
Interface::processOutgoing(data);
}
catch (std::exception& e) {
error("Could not transmit on " + toString() + ". The contained exception was: " + e.what());
}
}

View File

@ -0,0 +1,62 @@
#pragma once
#include "../Interface.h"
#include "../Bytes.h"
#include "../Type.h"
#ifdef ARDUINO
#include <SPI.h>
#include <LoRa.h>
#endif
// LILYGO T-Beam V1.X
#define RADIO_SCLK_PIN 5
#define RADIO_MISO_PIN 19
#define RADIO_MOSI_PIN 27
#define RADIO_CS_PIN 18
#define RADIO_DIO0_PIN 26
#define RADIO_RST_PIN 23
#define RADIO_DIO1_PIN 33
#define RADIO_BUSY_PIN 32
#include <stdint.h>
namespace RNS { namespace Interfaces {
class LoRaInterface : public Interface {
public:
//z def get_address_for_if(name):
//z def get_broadcast_for_if(name):
public:
//p def __init__(self, owner, name, device=None, bindip=None, bindport=None, forwardip=None, forwardport=None):
LoRaInterface(const char* name = "LoRaInterface");
virtual ~LoRaInterface();
bool start();
void stop();
void loop();
virtual void processIncoming(const Bytes& data);
virtual void processOutgoing(const Bytes& data);
virtual inline std::string toString() const { return "LoRaInterface[" + name() + "]"; }
private:
const uint16_t HW_MTU = 508;
//uint8_t buffer[Type::Reticulum::MTU] = {0};
const uint8_t message_count = 0;
Bytes buffer;
const long frequency = 915E6;
// Reticulum default
const long bandwidth = 125E3;
const int spreading = 8;
const int coding = 5;
const int power = 17;
};
} }

View File

@ -4,6 +4,15 @@
#include <memory>
#ifndef ARDUINO
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#endif
using namespace RNS;
using namespace RNS::Interfaces;
@ -25,29 +34,53 @@ def get_broadcast_for_if(name):
UDPInterface::UDPInterface(const char* name /*= "UDPInterface"*/) : Interface(name) {
IN(true);
//OUT(false);
OUT(true);
bitrate(BITRATE_GUESS);
}
void UDPInterface::start() {
UDPInterface::UDPInterface(const char* wifi_ssid, const char* wifi_password, int local_port, const char* local_host /*=nullptr*/, const char* name /*= "UDPInterface"*/) : Interface(name),
_local_port(local_port)
{
IN(true);
OUT(true);
bitrate(BITRATE_GUESS);
if (wifi_ssid != nullptr) {
_wifi_ssid = wifi_ssid;
}
if (wifi_password != nullptr) {
_wifi_password = wifi_password;
}
if (local_host != nullptr) {
_local_host = local_host;
}
}
/*virtual*/ UDPInterface::~UDPInterface() {
stop();
}
bool UDPInterface::start() {
online(false);
#ifdef ARDUINO
// Connect to the WiFi network
WiFi.begin(ssid, pwd);
WiFi.begin(_wifi_ssid.c_str(), _wifi_password.c_str());
Serial.println("");
// Wait for WiFi network connection to complete
Serial.print("Connecting to ");
Serial.print(ssid);
Serial.print(_wifi_ssid.c_str());
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.println(_wifi_ssid.c_str());
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
@ -86,10 +119,78 @@ void UDPInterface::start() {
*/
// This initializes udp and transfer buffer
udp.begin(udpPort);
udp.begin(_local_port);
#else
// resolve local host
struct in_addr local_addr;
if (inet_aton(_local_host.c_str(), &local_addr) == 0) {
struct hostent* host_ent = gethostbyname(_local_host.c_str());
if (host_ent == nullptr || host_ent->h_addr_list[0] == nullptr) {
error("Unable to resolve local host " + std::string(_local_host));
return false;
}
_local_address = *((in_addr_t*)(host_ent->h_addr_list[0]));
}
else {
_local_address = local_addr.s_addr;
}
// resolve remote host
struct in_addr remote_addr;
if (inet_aton(_remote_host.c_str(), &remote_addr) == 0) {
struct hostent* host_ent = gethostbyname(_remote_host.c_str());
if (host_ent == nullptr || host_ent->h_addr_list[0] == nullptr) {
error("Unable to resolve remote host " + std::string(_remote_host));
return false;
}
_remote_address = *((in_addr_t*)(host_ent->h_addr_list[0]));
}
else {
_remote_address = remote_addr.s_addr;
}
// open udp socket
extreme("Opening UDP socket");
_socket = socket( PF_INET, SOCK_DGRAM, 0 );
if (_socket < 0) {
error("Unable to create socket with error " + std::to_string(errno));
return false;
}
// enable broadcast
int broadcast = 1;
setsockopt(_socket, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast));
// bind to udp socket for listening
info("Binding UDP socket " + std::to_string(_socket) + " to " + std::string(_local_host) + ":" + std::to_string(_local_port));
sockaddr_in bind_addr;
bind_addr.sin_family = AF_INET;
bind_addr.sin_addr.s_addr = _local_address;
bind_addr.sin_port = htons(_local_port);
if (bind(_socket, (struct sockaddr*)&bind_addr, sizeof(bind_addr)) == -1) {
close(_socket);
_socket = -1;
error("Unable to bind socket with error " + std::to_string(errno));
return false;
}
#endif
online(true);
return true;
}
void UDPInterface::stop() {
#ifdef ARDUINO
#else
if (_socket > -1) {
close(_socket);
_socket = -1;
}
#endif
online(false);
}
void UDPInterface::loop() {
@ -98,10 +199,22 @@ void UDPInterface::loop() {
// Check for incoming packet
#ifdef ARDUINO
udp.parsePacket();
size_t len = udp.read(buffer.writable(Type::Reticulum::MTU), Type::Reticulum::MTU);
size_t len = udp.read(_buffer.writable(Type::Reticulum::MTU), Type::Reticulum::MTU);
if (len > 0) {
buffer.resize(len);
processIncoming(buffer);
_buffer.resize(len);
processIncoming(_buffer);
}
#else
size_t available = 0;
ioctl(_socket, FIONREAD, &available);
if (available > 0) {
size_t len = read(_socket, _buffer.writable(available), available);
if (len > 0) {
if (len < available) {
_buffer.resize(len);
}
processIncoming(_buffer);
}
}
#endif
}
@ -109,20 +222,26 @@ void UDPInterface::loop() {
/*virtual*/ void UDPInterface::processIncoming(const Bytes& data) {
debug("UDPInterface.processIncoming: data: " + data.toHex());
//debug("UDPInterface.processIncoming: text: " + data.toString());
Interface::processIncoming(data);
}
/*virtual*/ void UDPInterface::processOutgoing(const Bytes& data) {
debug("UDPInterface.processOutgoing: data: " + data.toHex());
debug("UDPInterface.processOutgoing: text: " + data.toString());
try {
if (online()) {
// Send packet
#ifdef ARDUINO
udp.beginPacket(udpAddress, udpPort);
udp.beginPacket(_remote_host.c_str(), _remote_port);
udp.write(data.data(), data.size());
udp.endPacket();
#else
extreme("Sending UDP packet to " + std::string(_remote_host) + ":" + std::to_string(_remote_port));
sockaddr_in sock_addr;
sock_addr.sin_family = AF_INET;
sock_addr.sin_addr.s_addr = _remote_address;
sock_addr.sin_port = htons(_remote_port);
int sent = sendto(_socket, data.data(), data.size(), 0, (struct sockaddr*)&sock_addr, sizeof(sock_addr));
extreme("Sent " + std::to_string(sent) + " bytes to " + std::string(_remote_host) + ":" + std::to_string(_remote_port));
#endif
}

View File

@ -8,6 +8,8 @@
#include <WiFi.h>
#include <WiFiUdp.h>
//#include <AsyncUDP.h>
#else
#include <netinet/in.h>
#endif
#include <stdint.h>
@ -25,8 +27,11 @@ namespace RNS { namespace Interfaces {
public:
//p def __init__(self, owner, name, device=None, bindip=None, bindport=None, forwardip=None, forwardport=None):
UDPInterface(const char* name = "UDPInterface");
UDPInterface(const char* wifi_ssid, const char* wifi_password, int local_port, const char* local_host = nullptr, const char* name = "UDPInterface");
virtual ~UDPInterface();
void start();
bool start();
void stop();
void loop();
virtual void processIncoming(const Bytes& data);
@ -38,22 +43,28 @@ namespace RNS { namespace Interfaces {
private:
const uint16_t HW_MTU = 1064;
//uint8_t buffer[Type::Reticulum::MTU] = {0};
Bytes buffer;
Bytes _buffer;
// WiFi network name and password
const char* ssid = "some-ssid";
const char* pwd = "some-pass";
std::string _wifi_ssid = "";
std::string _wifi_password = "";
// IP address to send UDP data to.
// it can be ip address of the server or
// broadcast
const char* udpAddress = "255.255.255.255";
const int udpPort = 4242;
std::string _local_host = "0.0.0.0";
int _local_port = 4242;
std::string _remote_host = "255.255.255.255";
int _remote_port = 4242;
// create UDP instance
#ifdef ARDUINO
WiFiUDP udp;
//AsyncUDP udp;
#else
int _socket = -1;
in_addr_t _local_address = INADDR_ANY;
in_addr_t _remote_address = INADDR_NONE;
#endif
};

View File

@ -6,7 +6,7 @@
using namespace RNS;
using namespace RNS::Type::Link;
Link::Link() : _object(new Object()) {
Link::Link(const Destination& destination) : _object(new Object(destination)) {
assert(_object);
mem("Link object created");

View File

@ -1,5 +1,6 @@
#pragma once
#include "Destination.h"
#include "Bytes.h"
#include "Type.h"
@ -25,7 +26,7 @@ namespace RNS {
Link(const Link& link) : _object(link._object) {
mem("Link object copy created");
}
Link();
Link(const Destination& destination);
virtual ~Link(){
mem("Link object destroyed");
}
@ -46,19 +47,23 @@ namespace RNS {
void receive(const Packet& packet);
// getters/setters
inline const Destination& destination() const { assert(_object); return _object->_destination; }
inline const Bytes& link_id() const { assert(_object); return _object->_link_id; }
inline const Bytes& hash() const { assert(_object); return _object->_hash; }
inline Type::Link::status status() const { assert(_object); return _object->_status; }
inline std::string toString() const { assert(_object); return "{Link: unknown}"; }
private:
class Object {
public:
Object() {}
Object(const Destination& destination) : _destination(destination) {}
virtual ~Object() {}
private:
Destination _destination = {Type::NONE};
Bytes _link_id;
Bytes _hash;
Type::Link::status _status = Type::Link::PENDING;
friend class Link;
};
std::shared_ptr<Object> _object;

View File

@ -31,6 +31,7 @@ const char* getLevelName(LogLevel level) {
//LogLevel _level = LOG_VERBOSE;
LogLevel _level = LOG_EXTREME;
//LogLevel _level = LOG_MEM;
void RNS::loglevel(LogLevel level) {
_level = level;

View File

@ -41,11 +41,7 @@ Packet::Packet(const Destination& destination, const Interface& attached_interfa
_object->_fromPacked = true;
_object->_create_receipt = false;
}
mem("Packet object created");
}
Packet::~Packet() {
mem("Packet object destroyed");
mem("Packet object created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
}

View File

@ -95,6 +95,9 @@ namespace RNS {
_object->_callbacks._timeout = callback;
}
// getters/setters
inline Type::PacketReceipt::Status status() const { assert(_object); return _object->_status; }
private:
class Object {
public:
@ -102,12 +105,12 @@ namespace RNS {
virtual ~Object() {}
private:
bool _sent = true;
uint64_t _sent_at = Utilities::OS::time();
double _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;
double _concluded_at = 0;
//z Packet _proof_packet;
int16_t _timeout = 0;
friend class PacketReceipt;
@ -125,10 +128,10 @@ namespace RNS {
public:
Packet(Type::NoneConstructor none) {
mem("Packet NONE object created");
mem("Packet NONE object created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
}
Packet(const Packet& packet) : _object(packet._object) {
mem("Packet object copy created");
mem("Packet object copy created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
}
Packet(
const Destination& destination,
@ -151,7 +154,9 @@ namespace RNS {
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();
virtual ~Packet() {
mem("Packet object destroyed, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
}
inline Packet& operator = (const Packet& packet) {
_object = packet._object;
@ -202,8 +207,8 @@ namespace RNS {
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; }
inline void sent_at(time_t sent_at) { assert(_object); _object->_sent_at = sent_at; }
inline double sent_at() const { assert(_object); return _object->_sent_at; }
inline void sent_at(double 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; }
@ -224,8 +229,8 @@ namespace RNS {
private:
class Object {
public:
Object(const Destination& destination, const Interface& attached_interface) : _destination(destination), _attached_interface(attached_interface) {}
virtual ~Object() {}
Object(const Destination& destination, const Interface& attached_interface) : _destination(destination), _attached_interface(attached_interface) { mem("Packet::Data object created, this: " + std::to_string((uintptr_t)this)); }
virtual ~Object() { mem("Identity::Data object destroyed, this: " + std::to_string((uintptr_t)this)); }
private:
Destination _destination = {Type::NONE};
Link _link = {Type::NONE};
@ -251,7 +256,7 @@ namespace RNS {
PacketReceipt _receipt;
uint16_t _mtu = Type::Reticulum::MTU;
time_t _sent_at = 0;
double _sent_at = 0;
float _rssi = 0.0;
float _snr = 0.0;

View File

@ -37,6 +37,9 @@ Reticulum::Reticulum() : _object(new Object()) {
// Initialkize random number generator
RNG.begin("Reticulum");
// CBA TEST Transport
__transport_enabled = true;
#ifdef ARDUINO
// Stir in the Ethernet MAC address.
//byte mac[6];
@ -154,6 +157,10 @@ Reticulum::Reticulum() : _object(new Object()) {
void Reticulum::loop() {
assert(_object);
if (!_object->_is_connected_to_shared_instance) {
RNS::Transport::loop();
}
// Perform random number gnerator housekeeping
RNG.loop();
}

View File

@ -62,6 +62,7 @@ namespace RNS {
:returns: True if Transport is enabled, False if not.
*/
inline static bool transport_enabled() { return __transport_enabled; }
inline static void transport_enabled(bool transport_enabled) { __transport_enabled = transport_enabled; }
inline static bool probe_destination_enabled() { return __allow_probes; }

View File

@ -4,6 +4,7 @@
void test() {
testOS();
testBytes();
testCollections();
testReference();

View File

@ -1,6 +1,7 @@
void test();
void testOS();
void testBytes();
void testCollections();
void testReference();

View File

@ -65,6 +65,34 @@ class Entry {
RNS::Bytes _hash;
};
void testOldMap() {
std::map<RNS::Bytes, Entry> entries;
std::map<RNS::Bytes, Entry> other_entries;
{
Entry some_entry("some hash");
entries.insert({some_entry._hash, some_entry});
Entry some_other_entry("some other hash");
other_entries.insert({some_entry._hash, some_entry});
other_entries.insert({some_other_entry._hash, some_other_entry});
}
assert(entries.size() == 1);
assert(other_entries.size() == 2);
for (auto& pair : other_entries) {
if (entries.find(pair.first) == entries.end()) {
entries[pair.first] = other_entries[pair.first];
}
}
for (auto& pair : entries) {
RNS::extreme("entries: " + pair.second._hash.toString());
}
assert(entries.size() == 2);
assert(other_entries.size() == 2);
}
void testNewMap() {
std::map<RNS::Bytes, Entry> entries;
@ -96,6 +124,7 @@ void testNewMap() {
void testCollections() {
RNS::head("Running testCollections...", RNS::LOG_EXTREME);
testBytesMap();
testOldMap();
testNewMap();
}

76
src/Test/TestOS.cpp Normal file
View File

@ -0,0 +1,76 @@
//#include <unity.h>
#include "Log.h"
#include "Utilities/OS.h"
#include <assert.h>
using namespace RNS::Utilities;
void testTime()
{
uint64_t start_ltime = OS::ltime();
double start_dtime = OS::time();
double sleep_time = 1.23456;
OS::sleep(sleep_time);
uint64_t end_ltime = OS::ltime();
double end_dtime = OS::time();
double diff_time;
diff_time = (double)(end_ltime - start_ltime) / 1000.0;
RNS::extreme(std::string("ltime diff: ") + std::to_string(diff_time));
assert(diff_time > sleep_time * 0.99);
assert(diff_time < sleep_time * 1.01);
diff_time = end_dtime - start_dtime;
RNS::extreme(std::string("dtime diff: ") + std::to_string(diff_time));
assert(diff_time > sleep_time * 0.99);
assert(diff_time < sleep_time * 1.01);
}
void testOS() {
RNS::head("Running testOS...", RNS::LOG_EXTREME);
testTime();
}
/*
void setUp(void) {
// set stuff up here
}
void tearDown(void) {
// clean stuff up here
}
int runUnityTests(void) {
UNITY_BEGIN();
RUN_TEST(testCollections);
return UNITY_END();
}
// For native dev-platform or for some embedded frameworks
int main(void) {
return runUnityTests();
}
// For Arduino framework
void setup() {
// Wait ~2 seconds before the Unity test runner
// establishes connection with a board Serial interface
delay(2000);
runUnityTests();
}
void loop() {}
// For ESP-IDF framework
void app_main() {
runUnityTests();
}
*/

View File

@ -33,7 +33,7 @@ using namespace RNS::Utilities;
/*static*/ std::set<Link> Transport::_pending_links;
/*static*/ std::set<Link> Transport::_active_links;
/*static*/ std::set<Bytes> Transport::_packet_hashlist;
/*static*/ std::set<PacketReceipt> Transport::_receipts;
/*static*/ std::list<PacketReceipt> Transport::_receipts;
/*static*/ std::map<Bytes, Transport::AnnounceEntry> Transport::_announce_table;
/*static*/ std::map<Bytes, Transport::DestinationEntry> Transport::_destination_table;
@ -41,11 +41,11 @@ using namespace RNS::Utilities;
/*static*/ std::map<Bytes, Transport::LinkEntry> Transport::_link_table;
/*static*/ std::map<Bytes, Transport::AnnounceEntry> Transport::_held_announces;
/*static*/ std::set<HAnnounceHandler> Transport::_announce_handlers;
/*static*/ std::map<Bytes, uint64_t> Transport::_path_requests;
/*static*/ std::map<Bytes, double> Transport::_path_requests;
/*static*/ std::map<Bytes, Transport::PathRequestEntry> Transport::_discovery_path_requests;
/*static*/ std::set<Bytes> Transport::_discovery_pr_tags;
/*static*/ uint16_t Transport::_max_pr_taXgxs = 32000;
/*static*/ uint16_t Transport::_max_pr_tags = 32000;
/*static*/ std::set<Destination> Transport::_control_destinations;
/*static*/ std::set<Bytes> Transport::_control_hashes;
@ -57,19 +57,20 @@ using namespace RNS::Utilities;
/*static*/ uint16_t Transport::_LOCAL_CLIENT_CACHE_MAXSIZE = 512;
/*static*/ uint64_t Transport::_start_time = 0;
/*static*/ double Transport::_start_time = 0;
/*static*/ bool Transport::_jobs_locked = false;
/*static*/ bool Transport::_jobs_running = false;
/*static*/ uint32_t Transport::_job_interval = 250;
/*static*/ uint64_t Transport::_links_last_checked = 0;
/*static*/ uint32_t Transport::_links_check_interval = 1000;
/*static*/ uint64_t Transport::_receipts_last_checked = 0;
/*static*/ uint32_t Transport::_receipts_check_interval = 1000;
/*static*/ uint64_t Transport::_announces_last_checked = 0;
/*static*/ uint32_t Transport::_announces_check_interval= 1000;
/*static*/ uint32_t Transport::_job_interval = 0.250;
/*static*/ double Transport::_jobs_last_run = 0;
/*static*/ double Transport::_links_last_checked = 0;
/*static*/ uint32_t Transport::_links_check_interval = 1.0;
/*static*/ double Transport::_receipts_last_checked = 0;
/*static*/ uint32_t Transport::_receipts_check_interval = 1.0;
/*static*/ double Transport::_announces_last_checked = 0;
/*static*/ uint32_t Transport::_announces_check_interval= 1.0;
/*static*/ uint32_t Transport::_hashlist_maxsize = 1000000;
/*static*/ uint64_t Transport::_tables_last_culled = 0;
/*static*/ uint32_t Transport::_tables_cull_interval = 5000;
/*static*/ double Transport::_tables_last_culled = 0;
/*static*/ uint32_t Transport::_tables_cull_interval = 5.0;
/*static*/ Reticulum Transport::_owner({Type::NONE});
/*static*/ Identity Transport::_identity({Type::NONE});
@ -127,11 +128,12 @@ using namespace RNS::Utilities;
_jobs_running = false;
// CBA Threading
//p thread = threading.Thread(target=Transport.jobloop, daemon=True)
//p thread.start()
// TODO
/*
thread = threading.Thread(target=Transport.jobloop, daemon=True)
thread.start()
if RNS.Reticulum.transport_enabled():
destination_table_path = RNS.Reticulum.storagepath+"/destination_table"
tunnel_table_path = RNS.Reticulum.storagepath+"/tunnels"
@ -249,6 +251,13 @@ using namespace RNS::Utilities;
*/
}
/*static*/ void Transport::loop() {
if (OS::time() > (_jobs_last_run + _job_interval)) {
jobs();
_jobs_last_run = OS::time();
}
}
/*static*/ void Transport::jobloop() {
while (true) {
jobs();
@ -259,104 +268,137 @@ using namespace RNS::Utilities;
/*static*/ void Transport::jobs() {
std::vector<Packet> outgoing;
std::vector<Bytes> path_requests;
std::set<Bytes> path_requests;
_jobs_running = true;
try {
// TODO
/*
if (!Transport.jobs_locked) {
if (!_jobs_locked) {
// Process active and pending link lists
if (time(nullptr) > _links_last_checked + Transport.links_check_interval) {
if (OS::time() > (_links_last_checked + _links_check_interval)) {
for (auto& link : _pending_links) {
if link.status() == RNS.Link.CLOSED:
if (link.status() == Type::Link::CLOSED) {
// If we are not a Transport Instance, finding a pending link
// that was never activated will trigger an expiry of the path
// to the destination, and an attempt to rediscover the path.
if not RNS.Reticulum.transport_enabled():
Transport.expire_path(link.destination.hash)
if (!Reticulum::transport_enabled()) {
expire_path(link.destination().hash());
// If we are connected to a shared instance, it will take
// care of sending out a new path request. If not, we will
// send one directly.
if not Transport.owner.is_connected_to_shared_instance:
last_path_request = 0
if link.destination.hash in Transport.path_requests:
last_path_request = Transport.path_requests[link.destination.hash]
if (!_owner.is_connected_to_shared_instance()) {
double last_path_request = 0;
auto iter = _path_requests.find(link.destination().hash());
if (iter != _path_requests.end()) {
last_path_request = (*iter).second;
}
if time.time() - last_path_request > Transport.PATH_REQUEST_MI:
RNS.log("Trying to rediscover path for "+RNS.prettyhexrep(link.destination.hash)+" since an attempted link was never established", RNS.LOG_DEBUG)
if not link.destination.hash in path_requests:
path_requests.append(link.destination.hash)
if ((OS::time() - last_path_request) > Type::Transport::PATH_REQUEST_MI) {
debug("Trying to rediscover path for " + link.destination().hash().toHex() + " since an attempted link was never established");
if (path_requests.find(link.destination().hash()) == path_requests.end()) {
path_requests.insert(link.destination().hash());
}
}
}
}
Transport.pending_links.remove(link)
_pending_links.erase(link);
}
}
for (auto& link : _active_links) {
if link.status == RNS.Link.CLOSED:
Transport.active_links.remove(link)
if (link.status() == Type::Link::CLOSED) {
_active_links.erase(link);
}
}
_links_last_checked = time(NULL)
_links_last_checked = OS::time();
}
// Process receipts list for timed-out packets
if time.time() > Transport.receipts_last_checked+Transport.receipts_check_interval:
while len(Transport.receipts) > Transport.MAX_RECEIPTS:
culled_receipt = Transport.receipts.pop(0)
culled_receipt.timeout = -1
culled_receipt.check_timeout()
if (OS::time() > (_receipts_last_checked + _receipts_check_interval)) {
while (_receipts.size() > Type::Transport::MAX_RECEIPTS) {
//p culled_receipt = Transport.receipts.pop(0)
PacketReceipt culled_receipt = _receipts.front();
_receipts.pop_front();
culled_receipt.set_timeout(-1);
culled_receipt.check_timeout();
}
for receipt in Transport.receipts:
receipt.check_timeout()
if receipt.status != RNS.PacketReceipt.SENT:
if receipt in Transport.receipts:
Transport.receipts.remove(receipt)
// TODO (erase while iterating)
/*
for (auto& receipt : _receipts) {
receipt.check_timeout();
if (receipt.status() != Type::PacketReceipt::SENT) {
// CBA Can NOT modify collection while iterating!
//z if receipt in Transport.receipts:
//z Transport.receipts.remove(receipt)
}
}
*/
Transport.receipts_last_checked = time.time()
_receipts_last_checked = OS::time();
}
// Process announces needing retransmission
if time.time() > Transport.announces_last_checked+Transport.announces_check_interval:
for destination_hash in Transport.announce_table:
announce_entry = Transport.announce_table[destination_hash]
if announce_entry[2] > Transport.PATHFINDER_R:
RNS.log("Completed announce processing for "+RNS.prettyhexrep(destination_hash)+", retry limit reached", RNS.LOG_EXTREME)
Transport.announce_table.pop(destination_hash)
break
else:
if time.time() > announce_entry[1]:
announce_entry[1] = time.time() + Transport.PATHFINDER_G + Transport.PATHFINDER_RW
announce_entry[2] += 1
packet = announce_entry[5]
block_rebroadcasts = announce_entry[7]
attached_interface = announce_entry[8]
announce_context = RNS.Packet.NONE
if block_rebroadcasts:
announce_context = RNS.Packet.PATH_RESPONSE
announce_data = packet.data
announce_identity = RNS.Identity.recall(packet.destination_hash)
announce_destination = RNS.Destination(announce_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, "unknown", "unknown");
announce_destination.hash = packet.destination_hash
announce_destination.hexhash = announce_destination.hash.hex()
new_packet = RNS.Packet(
announce_destination,
announce_data,
RNS.Packet.ANNOUNCE,
context = announce_context,
header_type = RNS.Packet.HEADER_2,
transport_type = Transport.TRANSPORT,
transport_id = Transport.identity.hash,
attached_interface = attached_interface
)
if (OS::time() > (_announces_last_checked + _announces_check_interval)) {
//p for destination_hash in Transport.announce_table:
for (auto& [destination_hash, announce_entry] : _announce_table) {
//for (auto& pair : _announce_table) {
// const auto& destination_hash = pair.first;
// auto& announce_entry = pair.second;
//extreme("[0] announce entry data size: " + std::to_string(announce_entry._packet.data().size()));
//p announce_entry = Transport.announce_table[destination_hash]
if (announce_entry._retries > Type::Transport::PATHFINDER_R) {
extreme("Completed announce processing for " + destination_hash.toHex() + ", retry limit reached");
// CBA OK to modify collection here since we're immediately exiting iteration
_announce_table.erase(destination_hash);
break;
}
else {
if (OS::time() > announce_entry._retransmit_timeout) {
announce_entry._retransmit_timeout = OS::time() + Type::Transport::PATHFINDER_G + Type::Transport::PATHFINDER_RW;
announce_entry._retries += 1;
//p packet = announce_entry[5]
//p block_rebroadcasts = announce_entry[7]
//p attached_interface = announce_entry[8]
Type::Packet::context_types announce_context = Type::Packet::CONTEXT_NONE;
if (announce_entry._block_rebroadcasts) {
announce_context = Type::Packet::PATH_RESPONSE;
}
//p announce_data = packet.data
Identity announce_identity(Identity::recall(announce_entry._packet.destination_hash()));
Destination announce_destination(announce_identity, Type::Destination::OUT, Type::Destination::SINGLE, "unknown", "unknown");
announce_destination.hash(announce_entry._packet.destination_hash());
//P announce_destination.hexhash = announce_destination.hash.hex()
new_packet.hops = announce_entry[4]
if block_rebroadcasts:
RNS.log("Rebroadcasting announce as path response for "+RNS.prettyhexrep(announce_destination.hash)+" with hop count "+str(new_packet.hops), RNS.LOG_DEBUG)
else:
RNS.log("Rebroadcasting announce for "+RNS.prettyhexrep(announce_destination.hash)+" with hop count "+str(new_packet.hops), RNS.LOG_DEBUG)
//if (announce_entry._attached_interface) {
//extreme("[1] interface is valid");
//extreme("[1] interface: " + announce_entry._attached_interface.debugString());
//extreme("[1] interface: " + announce_entry._attached_interface.toString());
//}
Packet new_packet(
announce_destination,
//{Type::NONE},
announce_entry._attached_interface,
//{Type::NONE},
announce_entry._packet.data(),
Type::Packet::ANNOUNCE,
announce_context,
Type::Transport::TRANSPORT,
Type::Packet::HEADER_2,
Transport::_identity.hash()
);
new_packet.hops(announce_entry._hops);
if (announce_entry._block_rebroadcasts) {
debug("Rebroadcasting announce as path response for " + announce_destination.hash().toHex() + " with hop count " + std::to_string(new_packet.hops()));
}
else {
debug("Rebroadcasting announce for " + announce_destination.hash().toHex() + " with hop count " + std::to_string(new_packet.hops()));
}
outgoing.append(new_packet)
outgoing.push_back(new_packet);
// This handles an edge case where a peer sends a past
// request for a destination just after an announce for
@ -364,14 +406,28 @@ using namespace RNS::Utilities;
// rebroadcast locally. In such a case the actual announce
// is temporarily held, and then reinserted when the path
// request has been served to the peer.
if destination_hash in Transport.held_announces:
held_entry = Transport.held_announces.pop(destination_hash)
Transport.announce_table[destination_hash] = held_entry
RNS.log("Reinserting held announce into table", RNS.LOG_DEBUG)
Transport.announces_last_checked = time.time()
//p if destination_hash in Transport.held_announces:
auto iter =_held_announces.find(destination_hash);
if (iter != _held_announces.end()) {
//p held_entry = Transport.held_announces.pop(destination_hash)
auto held_entry = (*iter).second;
_held_announces.erase(iter);
//p Transport.announce_table[destination_hash] = held_entry
//_announce_table[destination_hash] = held_entry;
//_announce_table.insert_or_assign({destination_hash, held_entry});
_announce_table.erase(destination_hash);
_announce_table.insert({destination_hash, held_entry});
debug("Reinserting held announce into table");
}
}
}
}
_announces_last_checked = OS::time();
}
// TODO
/*
// Cull the packet hashlist if it has reached its max size
if len(Transport.packet_hashlist) > Transport.hashlist_maxsize:
Transport.packet_hashlist = Transport.packet_hashlist[len(Transport.packet_hashlist)-Transport.hashlist_maxsize:len(Transport.packet_hashlist)-1]
@ -568,11 +624,12 @@ using namespace RNS::Utilities;
RNS.log("Removed "+str(i)+" tunnels", RNS.LOG_EXTREME)
Transport.tables_last_culled = time.time()
else:
// Transport jobs were locked, do nothing
pass
*/
}
else {
// Transport jobs were locked, do nothing
//p pass
}
}
catch (std::exception& e) {
error("An exception occurred while running Transport jobs.");
@ -644,17 +701,23 @@ using namespace RNS::Utilities;
/*static*/ bool Transport::outbound(Packet& packet) {
extreme("Transport::outbound()");
if (!packet.destination()) {
//throw std::invalid_argument("Can not send packet with no destination.");
error("Can not send packet with no destination");
return false;
}
extreme("Transport::outbound: destination=" + packet.destination_hash().toHex() + " hops=" + std::to_string(packet.hops()));
while (_jobs_running) {
extreme("Transport::outbound: sleeping...");
OS::sleep(5);
OS::sleep(0.0005);
}
_jobs_locked = true;
bool sent = false;
uint64_t outbound_time = OS::time();
double outbound_time = OS::time();
// 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:
@ -792,7 +855,7 @@ using namespace RNS::Utilities;
//}
if (iter != _destinations.end()) {
#endif
//extreme("Allowing announce broadcast on roaming-mode interface from instance-local destination");
extreme("Allowing announce broadcast on roaming-mode interface from instance-local destination");
}
else {
const Interface& from_interface = next_hop_interface(packet.destination_hash());
@ -841,7 +904,7 @@ using namespace RNS::Utilities;
auto iter = _destinations.find(packet.destination_hash());
if (iter != _destinations.end()) {
#endif
//extreme("Allowing announce broadcast on boundary-mode interface from instance-local destination");
extreme("Allowing announce broadcast on boundary-mode interface from instance-local destination");
}
else {
const Interface& from_interface = next_hop_interface(packet.destination_hash());
@ -882,8 +945,11 @@ using namespace RNS::Utilities;
bool queued_announces = (interface.announce_queue().size() > 0);
if (!queued_announces && outbound_time > interface.announce_allowed_at()) {
uint16_t tx_time = (packet.raw().size() * 8) / interface.bitrate();
uint16_t wait_time = (tx_time / interface.announce_cap());
uint16_t wait_time = 0;
if (interface.bitrate() > 0 && interface.announce_cap() > 0) {
uint16_t tx_time = (packet.raw().size() * 8) / interface.bitrate();
wait_time = (tx_time / interface.announce_cap());
}
#if defined(INTERFACES_SET)
const_cast<Interface&>(interface).announce_allowed_at(outbound_time + wait_time);
#else
@ -896,7 +962,7 @@ using namespace RNS::Utilities;
bool should_queue = true;
for (auto& entry : interface.announce_queue()) {
if (entry._destination == packet.destination_hash()) {
uint64_t emission_timestamp = announce_emitted(packet);
double emission_timestamp = announce_emitted(packet);
should_queue = false;
if (emission_timestamp > entry._emitted) {
entry._time = outbound_time;
@ -924,7 +990,7 @@ using namespace RNS::Utilities;
#endif
if (!queued_announces) {
uint64_t wait_time = std::max(interface.announce_allowed_at() - OS::time(), (uint64_t)0);
double wait_time = std::max(interface.announce_allowed_at() - OS::time(), (double)0);
// CBA TODO THREAD?
//z timer = threading.Timer(wait_time, interface.process_announce_queue)
//z timer.start()
@ -941,7 +1007,7 @@ using namespace RNS::Utilities;
extreme("Added announce to queue (height " + ql_str + ") on " + interface.toString() + " for processing in " + wait_time_str);
}
else {
uint64_t wait_time = std::max(interface.announce_allowed_at() - OS::time(), (uint64_t)0);
double wait_time = std::max(interface.announce_allowed_at() - OS::time(), (double)0);
std::string wait_time_str;
if (wait_time < 1000) {
@ -957,12 +1023,12 @@ using namespace RNS::Utilities;
}
}
else {
// future
//p pass
}
}
}
else {
// future
//p pass
}
}
}
@ -998,7 +1064,7 @@ using namespace RNS::Utilities;
if (sent) {
packet.sent(true);
packet.sent_at(time(nullptr));
packet.sent_at(OS::time());
// Don't generate receipt if it has been explicitly disabled
if (packet.create_receipt() &&
@ -1013,7 +1079,7 @@ using namespace RNS::Utilities;
PacketReceipt receipt(packet);
packet.receipt(receipt);
_receipts.insert(receipt);
_receipts.push_back(receipt);
}
cache(packet);
@ -1169,7 +1235,7 @@ using namespace RNS::Utilities;
while (_jobs_running) {
extreme("Transport::inbound: sleeping...");
OS::sleep(5);
OS::sleep(0.0005);
}
if (!_identity) {
@ -1181,7 +1247,7 @@ using namespace RNS::Utilities;
Packet packet({Type::NONE}, raw);
if (!packet.unpack()) {
warning("Transport::inbound: Pscket unpack failed!");
warning("Transport::inbound: Packet unpack failed!");
return;
}
@ -1229,11 +1295,11 @@ using namespace RNS::Utilities;
// Check special conditions for local clients connected
// through a shared Reticulum instance
//from_local_client = (packet.receiving_interface in Transport.local_client_interfaces)
//p from_local_client = (packet.receiving_interface in Transport.local_client_interfaces)
bool from_local_client = (_local_client_interfaces.find(packet.receiving_interface()) != _local_client_interfaces.end());
//for_local_client = (packet.packet_type != RNS.Packet.ANNOUNCE) and (packet.destination_hash in Transport.destination_table and Transport.destination_table[packet.destination_hash][2] == 0)
//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][4] in Transport.local_client_interfaces)
//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)
//p for_local_client = (packet.packet_type != RNS.Packet.ANNOUNCE) and (packet.destination_hash in Transport.destination_table and Transport.destination_table[packet.destination_hash][2] == 0)
//p 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][4] in Transport.local_client_interfaces)
//p 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() != Type::Packet::ANNOUNCE) {
@ -1374,8 +1440,8 @@ using namespace RNS::Utilities;
Interface& outbound_interface = destination_entry._receiving_interface;
if (packet.packet_type() == Type::Packet::LINKREQUEST) {
uint64_t now = OS::time();
uint64_t proof_timeout = now + Type::Link::ESTABLISHMENT_TIMEOUT_PER_HOP*1000 * std::max((uint8_t)1, remaining_hops);
double now = OS::time();
double proof_timeout = now + Type::Link::ESTABLISHMENT_TIMEOUT_PER_HOP*1000 * std::max((uint8_t)1, remaining_hops);
LinkEntry link_entry(
now,
next_hop,
@ -1460,7 +1526,7 @@ using namespace RNS::Utilities;
link_entry._timestamp = OS::time();
}
else {
// future
//p pass
}
}
}
@ -1511,7 +1577,7 @@ using namespace RNS::Utilities;
}
if ((packet.hops() - 1) == (announce_entry._hops + 1) && announce_entry._retries > 0) {
uint64_t now = OS::time();
double now = OS::time();
if (now < announce_entry._timestamp) {
debug("Rebroadcasted announce for " + packet.destination_hash().toHex() + " has been passed on to another node, no further tries needed");
_announce_table.erase(packet.destination_hash());
@ -1544,7 +1610,7 @@ using namespace RNS::Utilities;
auto iter = _destinations.find(packet.destination_hash());
if (iter == _destinations.end() && packet.hops() < (PATHFINDER_M+1)) {
#endif
uint64_t announce_emitted = Transport::announce_emitted(packet);
double announce_emitted = Transport::announce_emitted(packet);
//p random_blob = packet.data[RNS.Identity.KEYSIZE//8+RNS.Identity.NAME_HASH_LENGTH//8:RNS.Identity.KEYSIZE//8+RNS.Identity.NAME_HASH_LENGTH//8+10]
Bytes random_blob = packet.data().mid(Type::Identity::KEYSIZE/8 + Type::Identity::NAME_HASH_LENGTH/8, Type::Identity::RANDOM_HASH_LENGTH/8);
@ -1579,10 +1645,10 @@ using namespace RNS::Utilities;
// count than we already have in the table,
// ignore it, unless the path is expired, or
// the emission timestamp is more recent.
uint64_t now = OS::time();
uint64_t path_expires = destination_entry._expires;
double now = OS::time();
double path_expires = destination_entry._expires;
uint64_t path_announce_emitted = 0;
double path_announce_emitted = 0;
for (const Bytes& path_random_blob : random_blobs) {
//p path_announce_emitted = max(path_announce_emitted, int.from_bytes(path_random_blob[5:10], "big"))
// CBA TODO
@ -1626,7 +1692,7 @@ using namespace RNS::Utilities;
}
if (should_add) {
uint64_t now = OS::time();
double now = OS::time();
bool rate_blocked = false;
@ -1672,9 +1738,9 @@ using namespace RNS::Utilities;
bool block_rebroadcasts = false;
Interface attached_interface = {Type::NONE};
uint64_t retransmit_timeout = now + (Cryptography::random() * PATHFINDER_RW);
double retransmit_timeout = now + (Cryptography::random() * PATHFINDER_RW);
uint64_t expires;
double expires;
if (packet.receiving_interface().mode() == Type::Interface::MODE_ACCESS_POINT) {
expires = now + AP_PATH_TIME;
}
@ -1877,6 +1943,7 @@ using namespace RNS::Utilities;
}
}
if (execute_callback) {
// CBA TODO Why does app data come from recall instead of from this annuonce packet?
handler->received_announce(
packet.destination_hash(),
announce_identity,
@ -2230,7 +2297,7 @@ using namespace RNS::Utilities;
}
/*static*/ void Transport::register_destination(Destination& destination) {
extreme("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
//extreme("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
extreme("Transport: Registering destination " + destination.toString());
destination.mtu(Type::Reticulum::MTU);
if (destination.direction() == Type::Destination::IN) {
@ -2261,6 +2328,7 @@ using namespace RNS::Utilities;
}
}
/*
#if defined(DESTINATIONS_SET)
for (const Destination& destination : _destinations) {
#elif defined(DESTINATIONS_MAP)
@ -2268,7 +2336,8 @@ using namespace RNS::Utilities;
#endif
extreme("Transport::register_destination: Listed destination " + destination.toString());
}
extreme("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
*/
//extreme("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
}
/*static*/ void Transport::deregister_destination(const Destination& destination) {
@ -2594,15 +2663,18 @@ will announce it.
return;
}
else {
uint64_t now = OS::time();
double now = OS::time();
if (now < on_interface.announce_allowed_at()) {
extreme("Blocking recursive path request on " + on_interface.toString() + " due to active announce cap");
return;
}
else {
//p tx_time = ((len(path_request_data)+RNS.Reticulum.HEADER_MINSIZE)*8) / on_interface.bitrate
uint32_t tx_time = ((path_request_data.size() + Type::Reticulum::HEADER_MINSIZE)*8) / on_interface.bitrate();
uint32_t wait_time = (tx_time / on_interface.announce_cap());
uint32_t wait_time = 0;
if ( on_interface.bitrate() > 0 && on_interface.announce_cap() > 0) {
uint32_t tx_time = ((path_request_data.size() + Type::Reticulum::HEADER_MINSIZE)*8) / on_interface.bitrate();
wait_time = (tx_time / on_interface.announce_cap());
}
const_cast<Interface&>(on_interface).announce_allowed_at(now + wait_time);
}
}
@ -2751,13 +2823,13 @@ will announce it.
else {
debug("Answering path request for destination " + destination_hash.toHex() + interface_str + ", path is known");
uint64_t now = OS::time();
double now = OS::time();
uint8_t retries = Type::Transport::PATHFINDER_R;
uint8_t local_rebroadcasts = 0;
bool block_rebroadcasts = true;
uint8_t announce_hops = destination_entry._announce_packet.hops();
uint64_t retransmit_timeout = 0;
double retransmit_timeout = 0;
if (is_from_local_client) {
retransmit_timeout = now;
}
@ -2777,7 +2849,8 @@ will announce it.
AnnounceEntry& held_entry = (*announce_iter).second;
_held_announces.insert({destination_entry._announce_packet.destination_hash(), held_entry});
}
/*
_announce_table.insert({destination_entry._announce_packet.destination_hash(), {
now,
retransmit_timeout,
@ -2791,6 +2864,21 @@ will announce it.
block_rebroadcasts,
attached_interface
}});
*/
AnnounceEntry announce_entry(
now,
retransmit_timeout,
retries,
// BUG?
//destination_entry.receiving_interface,
destination_entry._received_from,
announce_hops,
destination_entry._announce_packet,
local_rebroadcasts,
block_rebroadcasts,
attached_interface
);
_announce_table.insert({destination_entry._announce_packet.destination_hash(), announce_entry});
}
}
}
@ -3180,7 +3268,7 @@ will announce it.
}
/*static*/ Destination Transport::find_destination_from_hash(const Bytes& destination_hash) {
extreme("Transport: Searching for destination " + destination_hash.toHex());
extreme("Transport::find_destination_from_hash: Searching for destination " + destination_hash.toHex());
#if defined(DESTINATIONS_SET)
for (const Destination& destination : _destinations) {
if (destination.get_hash() == destination_hash) {

View File

@ -1,5 +1,6 @@
#pragma once
#include "Packet.h"
#include "Bytes.h"
#include "Type.h"
@ -58,7 +59,7 @@ namespace RNS {
// CBA TODO Analyze safety of using Packet references here
class DestinationEntry {
public:
DestinationEntry(uint64_t time, const Bytes& received_from, uint8_t announce_hops, uint64_t expires, const std::set<Bytes>& random_blobs, Interface& receiving_interface, const Packet& packet) :
DestinationEntry(double time, const Bytes& received_from, uint8_t announce_hops, double expires, const std::set<Bytes>& random_blobs, Interface& receiving_interface, const Packet& packet) :
_timestamp(time),
_received_from(received_from),
_hops(announce_hops),
@ -69,20 +70,22 @@ namespace RNS {
{
}
public:
uint64_t _timestamp = 0;
double _timestamp = 0;
Bytes _received_from;
uint8_t _hops = 0;
uint64_t _expires = 0;
double _expires = 0;
std::set<Bytes> _random_blobs;
// CBA TODO does this need to be a reference in order for virtual method callbacks to work?
Interface& _receiving_interface;
const Packet& _announce_packet;
//const Packet& _announce_packet;
Packet _announce_packet;
};
// CBA TODO Analyze safety of using Inrerface references here
// CBA TODO Analyze safety of using Packet references here
class AnnounceEntry {
public:
AnnounceEntry(uint64_t timestamp, uint64_t retransmit_timeout, uint8_t retries, const Bytes& received_from, uint8_t hops, const Packet& packet, uint8_t local_rebroadcasts, bool block_rebroadcasts, const Interface& attached_interface) :
AnnounceEntry(double timestamp, double retransmit_timeout, uint8_t retries, const Bytes& received_from, uint8_t hops, const Packet& packet, uint8_t local_rebroadcasts, bool block_rebroadcasts, const Interface& attached_interface) :
_timestamp(timestamp),
_retransmit_timeout(retransmit_timeout),
_retries(retries),
@ -95,21 +98,26 @@ namespace RNS {
{
}
public:
uint64_t _timestamp = 0;
uint64_t _retransmit_timeout = 0;
double _timestamp = 0;
double _retransmit_timeout = 0;
uint8_t _retries = 0;
Bytes _received_from;
uint8_t _hops = 0;
const Packet& _packet;
// CBA Storing packet reference causes memory issues, presumably because orignal packet is being destroyed
// MUST use instance instad of reference!!!
//const Packet& _packet;
Packet _packet;
uint8_t _local_rebroadcasts = 0;
bool _block_rebroadcasts = false;
const Interface& _attached_interface;
// CBA TODO does this need to be a reference in order for virtual method callbacks to work?
//const Interface& _attached_interface;
Interface _attached_interface;
};
// CBA TODO Analyze safety of using Inrerface references here
class LinkEntry {
public:
LinkEntry(uint64_t timestamp, const Bytes& next_hop, const Interface& outbound_interface, uint8_t remaining_hops, const Interface& receiving_interface, uint8_t hops, const Bytes& destination_hash, bool validated, uint64_t proof_timeout) :
LinkEntry(double 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, double proof_timeout) :
_timestamp(timestamp),
_next_hop(next_hop),
_outbound_interface(outbound_interface),
@ -122,36 +130,44 @@ namespace RNS {
{
}
public:
uint64_t _timestamp = 0;
double _timestamp = 0;
Bytes _next_hop;
const Interface& _outbound_interface;
// CBA TODO does this need to be a reference in order for virtual method callbacks to work?
//const Interface& _outbound_interface;
Interface _outbound_interface;
uint8_t _remaining_hops = 0;
const Interface& _receiving_interface;
// CBA TODO does this need to be a reference in order for virtual method callbacks to work?
//const Interface& _receiving_interface;
Interface _receiving_interface;
uint8_t _hops = 0;
Bytes _destination_hash;
bool _validated = false;
uint64_t _proof_timeout = 0;
double _proof_timeout = 0;
};
// CBA TODO Analyze safety of using Inrerface references here
class ReverseEntry {
public:
ReverseEntry(const Interface& receiving_interface, const Interface& outbound_interface, uint64_t timestamp) :
ReverseEntry(const Interface& receiving_interface, const Interface& outbound_interface, double timestamp) :
_receiving_interface(receiving_interface),
_outbound_interface(outbound_interface),
_timestamp(timestamp)
{
}
public:
const Interface& _receiving_interface;
const Interface& _outbound_interface;
uint64_t _timestamp = 0;
// CBA TODO does this need to be a reference in order for virtual method callbacks to work?
//const Interface& _receiving_interface;
Interface _receiving_interface;
// CBA TODO does this need to be a reference in order for virtual method callbacks to work?
//const Interface& _outbound_interface;
Interface _outbound_interface;
double _timestamp = 0;
};
// CBA TODO Analyze safety of using Inrerface references here
class PathRequestEntry {
public:
PathRequestEntry(const Bytes& destination_hash, uint64_t timeout, const Interface& requesting_interface) :
PathRequestEntry(const Bytes& destination_hash, double timeout, const Interface& requesting_interface) :
_destination_hash(destination_hash),
_timeout(timeout),
_requesting_interface(requesting_interface)
@ -159,12 +175,15 @@ namespace RNS {
}
public:
Bytes _destination_hash;
uint64_t _timeout = 0;
const Interface& _requesting_interface;
double _timeout = 0;
// CBA TODO does this need to be a reference in order for virtual method callbacks to work?
//const Interface& _requesting_interface;
Interface _requesting_interface;
};
public:
static void start(const Reticulum& reticulum_instance);
static void loop();
static void jobloop();
static void jobs();
static void transmit(Interface& interface, const Bytes& raw);
@ -237,7 +256,7 @@ namespace RNS {
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
static std::list<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
@ -251,11 +270,11 @@ namespace RNS {
static std::set<HAnnounceHandler> _announce_handlers; // A table storing externally registered announce handlers
//z _tunnels = {} // A table storing tunnels to other transport instances
//z _announce_rate_table = {} // A table for keeping track of announce rates
static std::map<Bytes, uint64_t> _path_requests; // A table for storing path request timestamps
static std::map<Bytes, double> _path_requests; // A table for storing path request timestamps
static std::map<Bytes, PathRequestEntry> _discovery_path_requests; // A table for keeping track of path requests on behalf of other nodes
static std::set<Bytes> _discovery_pr_tags; // A table for keeping track of tagged path requests
static uint16_t _max_pr_taXgxs; // Maximum amount of unique path request tags to remember
static uint16_t _max_pr_tags; // Maximum amount of unique path request tags to remember
// Transport control destinations are used
// for control purposes like path requests
@ -274,18 +293,19 @@ namespace RNS {
//z _local_client_snr_cache = []
static uint16_t _LOCAL_CLIENT_CACHE_MAXSIZE;
static uint64_t _start_time;
static double _start_time;
static bool _jobs_locked;
static bool _jobs_running;
static uint32_t _job_interval;
static uint64_t _links_last_checked;
static double _jobs_last_run;
static double _links_last_checked;
static uint32_t _links_check_interval;
static uint64_t _receipts_last_checked;
static double _receipts_last_checked;
static uint32_t _receipts_check_interval;
static uint64_t _announces_last_checked;
static double _announces_last_checked;
static uint32_t _announces_check_interval;
static uint32_t _hashlist_maxsize;
static uint64_t _tables_last_culled;
static double _tables_last_culled;
static uint32_t _tables_cull_interval;
static Reticulum _owner;

View File

@ -1,5 +1,6 @@
#pragma once
#include "Log.h"
#include "Cryptography/Fernet.h"
#include <stdint.h>

View File

@ -12,14 +12,19 @@ namespace RNS { namespace Utilities {
public:
// sleep for specified milliseconds
static inline void sleep(float seconds) { ::sleep(seconds); }
//static inline void sleep(float seconds) { ::sleep(seconds); }
#ifdef ARDUINO
static inline void sleep(float seconds) { delay((uint32_t)(seconds * 1000)); }
#else
static inline void sleep(float seconds) { timespec time; time.tv_sec = (time_t)(seconds); time.tv_nsec = (seconds - (float)time.tv_sec) * 1000000000; ::nanosleep(&time, nullptr); }
#endif
//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 uint64_t ltime() { timeval time; ::gettimeofday(&time, NULL); return (uint64_t)(time.tv_sec * 1000) + (uint64_t)(time.tv_usec / 1000); }
// return current time in float seconds since 00:00:00, January 1, 1970 (Unix Epoch)
static double dtime() { timeval time; ::gettimeofday(&time, NULL); return (double)time.tv_sec + ((double)time.tv_usec / 1000000); }
static inline double time() { timeval time; ::gettimeofday(&time, NULL); return (double)time.tv_sec + ((double)time.tv_usec / 1000000); }
// round decimal number to specified precision
//static inline float round(float value, uint8_t precision) { return std::round(value / precision) * precision; }

View File

@ -12,6 +12,7 @@
#include "Bytes.h"
#include "Type.h"
#include "Interfaces/UDPInterface.h"
#include "Interfaces/LoRaInterface.h"
#include "Utilities/OS.h"
#ifdef ARDUINO
@ -30,9 +31,14 @@
#ifndef NDEBUG
//#define RUN_TESTS
#endif
#define RUN_RETICULUM
#define UDP_INTERFACE
#define LORA_INTERFACE
//#define RETICULUM_PACKET_TEST
#define USER_BUTTON_PIN 38
// Let's define an app name. We'll use this for all
// destinations we create. Since this basic example
// is part of a range of example utilities, we'll put
@ -43,6 +49,9 @@ 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"};
double last_announce = 0.0;
bool send_announce = false;
class TestInterface : public RNS::Interface {
public:
TestInterface() : RNS::Interface("TestInterface") {
@ -137,7 +146,7 @@ public:
ExampleAnnounceHandler(const char* aspect_filter = nullptr) : AnnounceHandler(aspect_filter) {}
virtual ~ExampleAnnounceHandler() {}
virtual void received_announce(const RNS::Bytes& destination_hash, const RNS::Identity& announced_identity, const RNS::Bytes& app_data) {
RNS::info("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
RNS::info("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
RNS::info("ExampleAnnounceHandler: destination hash: " + destination_hash.toHex());
if (announced_identity) {
RNS::info("ExampleAnnounceHandler: announced identity hash: " + announced_identity.hash().toHex());
@ -146,28 +155,44 @@ public:
if (app_data) {
RNS::info("ExampleAnnounceHandler: app data text: \"" + app_data.toString() + "\"");
}
RNS::info("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
RNS::info("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
}
};
// Test packet receive callback
void onPacket(const RNS::Bytes& data, const RNS::Packet& packet) {
RNS::info("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
RNS::head("onPacket: data: " + data.toHex(), RNS::LOG_INFO);
RNS::head("onPacket: data string: \"" + data.toString() + "\"", RNS::LOG_INFO);
//RNS::head("onPacket: " + packet.debugString(), RNS::LOG_EXTREME);
RNS::info("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
RNS::info("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
RNS::info("onPacket: data: " + data.toHex());
RNS::info("onPacket: text: \"" + data.toString() + "\"");
//RNS::extreme("onPacket: " + packet.debugString());
RNS::info("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
}
// Ping packet receive callback
void onPingPacket(const RNS::Bytes& data, const RNS::Packet& packet) {
RNS::info("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
RNS::info("onPingPacket: data: " + data.toHex());
RNS::info("onPingPacket: text: \"" + data.toString() + "\"");
//RNS::extreme("onPingPacket: " + packet.debugString());
RNS::info("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
}
#if defined(RUN_RETICULUM)
RNS::Reticulum reticulum({RNS::Type::NONE});
RNS::Identity identity({RNS::Type::NONE});
RNS::Destination destination({RNS::Type::NONE});
//TestInterface interface;
TestOutInterface outinterface;
TestInInterface ininterface;
TestLoopbackInterface loopinterface(ininterface);
RNS::Interfaces::UDPInterface udpinterface;
#ifdef UDP_INTERFACE
RNS::Interfaces::UDPInterface udp_interface;
#endif
#ifdef LORA_INTERFACE
RNS::Interfaces::LoRaInterface lora_interface;
#endif
//ExampleAnnounceHandler announce_handler((const char*)"example_utilities.announcesample.fruits");
//RNS::HAnnounceHandler announce_handler(new ExampleAnnounceHandler("example_utilities.announcesample.fruits"));
@ -197,6 +222,17 @@ void run_tests() {
}
#endif
void reticulum_announce() {
if (destination) {
RNS::head("Announcing destination...", RNS::LOG_EXTREME);
//destination.announce(RNS::bytesFromString(fruits[RNS::Cryptography::randomnum() % 7]));
// test path
//destination.announce(RNS::bytesFromString(fruits[RNS::Cryptography::randomnum() % 7]), true, nullptr, RNS::bytesFromString("test_tag"));
// test packet send
destination.announce(RNS::bytesFromString(fruits[RNS::Cryptography::randomnum() % 7]));
}
}
#if defined(RUN_RETICULUM)
void setup_reticulum() {
RNS::info("Setting up Reticulum...");
@ -222,32 +258,71 @@ void setup_reticulum() {
RNS::Transport::register_interface(outinterface);
RNS::Transport::register_interface(ininterface);
RNS::Transport::register_interface(loopinterface);
RNS::Transport::register_interface(udpinterface);
#ifdef UDP_INTERFACE
RNS::Transport::register_interface(udp_interface);
#endif
#ifdef LORA_INTERFACE
RNS::Transport::register_interface(lora_interface);
#endif
#ifdef UDP_INTERFACE
RNS::head("Starting UDPInterface...", RNS::LOG_EXTREME);
udpinterface.start();
udp_interface.start();
#endif
#ifdef LORA_INTERFACE
RNS::head("Starting LoRaInterface...", RNS::LOG_EXTREME);
lora_interface.start();
#endif
RNS::head("Creating Identity instance...", RNS::LOG_EXTREME);
RNS::Identity identity;
// new identity
//RNS::Identity identity;
//identity = RNS::Identity();
// predefined identity
//RNS::Identity identity(false);
identity = RNS::Identity(false);
RNS::Bytes prv_bytes;
#ifdef ARDUINO
prv_bytes.assignHex("78E7D93E28D55871608FF13329A226CABC3903A357388A035B360162FF6321570B092E0583772AB80BC425F99791DF5CA2CA0A985FF0415DAB419BBC64DDFAE8");
#else
prv_bytes.assignHex("E0D43398EDC974EBA9F4A83463691A08F4D306D4E56BA6B275B8690A2FBD9852E9EBE7C03BC45CAEC9EF8E78C830037210BFB9986F6CA2DEE2B5C28D7B4DE6B0");
#endif
identity.load_private_key(prv_bytes);
// 22.6% (+0.7%)
RNS::head("Creating Destination instance...", RNS::LOG_EXTREME);
RNS::Destination destination(identity, RNS::Type::Destination::IN, RNS::Type::Destination::SINGLE, "app", "aspects");
//RNS::Destination destination(identity, RNS::Type::Destination::IN, RNS::Type::Destination::SINGLE, "app", "aspects");
destination = RNS::Destination(identity, RNS::Type::Destination::IN, RNS::Type::Destination::SINGLE, "app", "aspects");
// 23.0% (+0.4%)
// test data receive packet
RNS::head("Registering packet callback with Destination...", RNS::LOG_EXTREME);
destination.set_packet_callback(onPacket);
destination.set_proof_strategy(RNS::Type::Destination::PROVE_ALL);
{
RNS::head("Creating PING Destination instance...", RNS::LOG_EXTREME);
RNS::Destination ping_destination(identity, RNS::Type::Destination::IN, RNS::Type::Destination::SINGLE, "example_utilities", "echo.request");
RNS::head("Registering packet callback with PING Destination...", RNS::LOG_EXTREME);
ping_destination.set_packet_callback(onPingPacket);
ping_destination.set_proof_strategy(RNS::Type::Destination::PROVE_ALL);
}
RNS::head("Registering announce handler with Transport...", RNS::LOG_EXTREME);
RNS::Transport::register_announce_handler(announce_handler);
/*
RNS::head("Announcing destination...", RNS::LOG_EXTREME);
//destination.announce(RNS::bytesFromString(fruits[rand() % 7]));
//destination.announce(RNS::bytesFromString(fruits[RNS::Cryptography::randomnum() % 7]));
// test path
//destination.announce(RNS::bytesFromString(fruits[rand() % 7]), true, nullptr, RNS::bytesFromString("test_tag"));
//destination.announce(RNS::bytesFromString(fruits[RNS::Cryptography::randomnum() % 7]), true, nullptr, RNS::bytesFromString("test_tag"));
// test packet send
destination.announce(RNS::bytesFromString(fruits[rand() % 7]));
destination.announce(RNS::bytesFromString(fruits[RNS::Cryptography::randomnum() % 7]));
// 23.9% (+0.8%)
*/
reticulum_announce();
#if defined (RETICULUM_PACKET_TEST)
// test data send packet
@ -258,10 +333,6 @@ void setup_reticulum() {
send_packet.pack();
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::Type::NONE}, send_packet.raw());
recv_packet.unpack();
@ -286,7 +357,12 @@ void teardown_reticulum() {
RNS::Transport::deregister_announce_handler(announce_handler);
RNS::head("Deregistering Interface instances with Transport...", RNS::LOG_EXTREME);
RNS::Transport::deregister_interface(udpinterface);
#ifdef UDP_INTERFACE
RNS::Transport::deregister_interface(udp_interface);
#endif
#ifdef LORA_INTERFACE
RNS::Transport::deregister_interface(lora_interface);
#endif
RNS::Transport::deregister_interface(loopinterface);
RNS::Transport::deregister_interface(ininterface);
RNS::Transport::deregister_interface(outinterface);
@ -299,14 +375,30 @@ void teardown_reticulum() {
}
#endif
#ifdef ARDUINO
void userKey(void)
{
//delay(10);
if (digitalRead(USER_BUTTON_PIN) == LOW) {
//Serial.print("T-Beam USER button press\n");
send_announce = true;
}
}
#endif
void setup() {
#ifdef ARDUINO
Serial.begin(115200);
Serial.print("Hello from T-Beam on PlatformIO!\n");
// Setup user button
pinMode(USER_BUTTON_PIN, INPUT);
attachInterrupt(USER_BUTTON_PIN, userKey, FALLING);
#endif
RNS::loglevel(RNS::LOG_EXTREME);
//RNS::loglevel(RNS::LOG_MEM);
/*
{
@ -331,8 +423,28 @@ void setup() {
void loop() {
#if defined(RUN_RETICULUM)
reticulum.loop();
udpinterface.loop();
#ifdef UDP_INTERFACE
udp_interface.loop();
#endif
#ifdef LORA_INTERFACE
lora_interface.loop();
#endif
#ifdef ARDUINO
/*
if ((RNS::Utilities::OS::time() - last_announce) > 10) {
reticulum_announce();
last_announce = RNS::Utilities::OS::time();
}
*/
#endif
if (send_announce) {
reticulum_announce();
send_announce = false;
}
#endif
}
@ -342,9 +454,10 @@ int main(void) {
setup();
//while (true) {
// loop();
//}
while (true) {
loop();
RNS::Utilities::OS::sleep(0.01);
}
printf("Goodbye from Native on PlatformIO!\n");
}