diff --git a/platformio.ini b/platformio.ini index ccbab57..792e58a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -55,3 +55,5 @@ build_flags = -Isrc lib_deps = rweather/Crypto@^0.4.0 + sandeepmistry/LoRa@^0.8.0 + WiFi@^2.0.0 diff --git a/src/Cryptography/Fernet.cpp b/src/Cryptography/Fernet.cpp index 089bca7..36e6ff5 100644 --- a/src/Cryptography/Fernet.cpp +++ b/src/Cryptography/Fernet.cpp @@ -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()); diff --git a/src/Destination.cpp b/src/Destination.cpp index 07aa4d6..289a068 100644 --- a/src/Destination.cpp +++ b/src/Destination.cpp @@ -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()); diff --git a/src/Destination.h b/src/Destination.h index 0103d77..f097ff4 100644 --- a/src/Destination.h +++ b/src/Destination.h @@ -50,9 +50,7 @@ namespace RNS { friend class Detination; }; - //typedef std::pair Response; - using PathResponse = std::pair; - //using PathResponse = std::pair>; + using PathResponse = std::pair; 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 _path_responses; std::map _path_responses; //z _links = [] diff --git a/src/Identity.cpp b/src/Identity.cpp index 8be1656..c55aae0 100644 --- a/src/Identity.cpp +++ b/src/Identity.cpp @@ -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 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; diff --git a/src/Identity.h b/src/Identity.h index 19abbe4..97ec6eb 100644 --- a/src/Identity.h +++ b/src/Identity.h @@ -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; diff --git a/src/Interface.cpp b/src/Interface.cpp index 7f00eda..85a9fe1 100644 --- a/src/Interface.cpp +++ b/src/Interface.cpp @@ -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"]) diff --git a/src/Interface.h b/src/Interface.h index 6aaad80..a50d304 100644 --- a/src/Interface.h +++ b/src/Interface.h @@ -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& 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 _announce_queue; bool _is_connected_to_shared_instance = false; diff --git a/src/Interfaces/LoRaInterface.cpp b/src/Interfaces/LoRaInterface.cpp new file mode 100644 index 0000000..23d2350 --- /dev/null +++ b/src/Interfaces/LoRaInterface.cpp @@ -0,0 +1,132 @@ +#include "LoRaInterface.h" + +#include "../Log.h" +#include "../Utilities/OS.h" + +#include + +using namespace RNS; +using namespace RNS::Interfaces; + +/* +@staticmethod +def get_address_for_if(name): + import RNS.vendor.ifaddr.niwrapper as netinfo + ifaddr = netinfo.ifaddresses(name) + return ifaddr[netinfo.AF_INET][0]["addr"] + +@staticmethod +def get_broadcast_for_if(name): + import RNS.vendor.ifaddr.niwrapper as netinfo + ifaddr = netinfo.ifaddresses(name) + return ifaddr[netinfo.AF_INET][0]["broadcast"] +*/ + +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()); + } +} diff --git a/src/Interfaces/LoRaInterface.h b/src/Interfaces/LoRaInterface.h new file mode 100644 index 0000000..02a2ad3 --- /dev/null +++ b/src/Interfaces/LoRaInterface.h @@ -0,0 +1,62 @@ +#pragma once + +#include "../Interface.h" +#include "../Bytes.h" +#include "../Type.h" + +#ifdef ARDUINO +#include +#include +#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 + +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; + + }; + +} } diff --git a/src/Interfaces/UDPInterface.cpp b/src/Interfaces/UDPInterface.cpp index 693aee4..e9877c1 100644 --- a/src/Interfaces/UDPInterface.cpp +++ b/src/Interfaces/UDPInterface.cpp @@ -4,6 +4,15 @@ #include +#ifndef ARDUINO +#include +#include +#include +#include +#include +#include +#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 } diff --git a/src/Interfaces/UDPInterface.h b/src/Interfaces/UDPInterface.h index 0c3a05a..817c543 100644 --- a/src/Interfaces/UDPInterface.h +++ b/src/Interfaces/UDPInterface.h @@ -8,6 +8,8 @@ #include #include //#include +#else +#include #endif #include @@ -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 }; diff --git a/src/Link.cpp b/src/Link.cpp index ff4e8b0..6dd042a 100644 --- a/src/Link.cpp +++ b/src/Link.cpp @@ -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"); diff --git a/src/Link.h b/src/Link.h index 521c8d5..d7bbbcc 100644 --- a/src/Link.h +++ b/src/Link.h @@ -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; diff --git a/src/Log.cpp b/src/Log.cpp index 6478b42..ac4562a 100644 --- a/src/Log.cpp +++ b/src/Log.cpp @@ -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; diff --git a/src/Packet.cpp b/src/Packet.cpp index f6d7031..d0706f9 100644 --- a/src/Packet.cpp +++ b/src/Packet.cpp @@ -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())); } diff --git a/src/Packet.h b/src/Packet.h index 7f2dc27..c42c504 100644 --- a/src/Packet.h +++ b/src/Packet.h @@ -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; diff --git a/src/Reticulum.cpp b/src/Reticulum.cpp index a2c001e..71ef477 100644 --- a/src/Reticulum.cpp +++ b/src/Reticulum.cpp @@ -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(); } diff --git a/src/Reticulum.h b/src/Reticulum.h index dbcbe43..0ff95df 100644 --- a/src/Reticulum.h +++ b/src/Reticulum.h @@ -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; } diff --git a/src/Test/Test.cpp b/src/Test/Test.cpp index d7c6767..3b21b84 100644 --- a/src/Test/Test.cpp +++ b/src/Test/Test.cpp @@ -4,6 +4,7 @@ void test() { + testOS(); testBytes(); testCollections(); testReference(); diff --git a/src/Test/Test.h b/src/Test/Test.h index 88df2d4..f7095b6 100644 --- a/src/Test/Test.h +++ b/src/Test/Test.h @@ -1,6 +1,7 @@ void test(); +void testOS(); void testBytes(); void testCollections(); void testReference(); diff --git a/src/Test/TestCollections.cpp b/src/Test/TestCollections.cpp index c6322b9..4a241ef 100644 --- a/src/Test/TestCollections.cpp +++ b/src/Test/TestCollections.cpp @@ -65,6 +65,34 @@ class Entry { RNS::Bytes _hash; }; +void testOldMap() { + + std::map entries; + std::map other_entries; + + { + Entry some_entry("some hash"); + entries.insert({some_entry._hash, some_entry}); + Entry some_other_entry("some other hash"); + other_entries.insert({some_entry._hash, some_entry}); + other_entries.insert({some_other_entry._hash, some_other_entry}); + } + + assert(entries.size() == 1); + assert(other_entries.size() == 2); + for (auto& 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 entries; @@ -96,6 +124,7 @@ void testNewMap() { void testCollections() { RNS::head("Running testCollections...", RNS::LOG_EXTREME); testBytesMap(); + testOldMap(); testNewMap(); } diff --git a/src/Test/TestOS.cpp b/src/Test/TestOS.cpp new file mode 100644 index 0000000..5dfb7d7 --- /dev/null +++ b/src/Test/TestOS.cpp @@ -0,0 +1,76 @@ +//#include + +#include "Log.h" +#include "Utilities/OS.h" + +#include + +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(); +} +*/ + diff --git a/src/Transport.cpp b/src/Transport.cpp index 393fa68..c105ee3 100644 --- a/src/Transport.cpp +++ b/src/Transport.cpp @@ -33,7 +33,7 @@ using namespace RNS::Utilities; /*static*/ std::set Transport::_pending_links; /*static*/ std::set Transport::_active_links; /*static*/ std::set Transport::_packet_hashlist; -/*static*/ std::set Transport::_receipts; +/*static*/ std::list Transport::_receipts; /*static*/ std::map Transport::_announce_table; /*static*/ std::map Transport::_destination_table; @@ -41,11 +41,11 @@ using namespace RNS::Utilities; /*static*/ std::map Transport::_link_table; /*static*/ std::map Transport::_held_announces; /*static*/ std::set Transport::_announce_handlers; -/*static*/ std::map Transport::_path_requests; +/*static*/ std::map Transport::_path_requests; /*static*/ std::map Transport::_discovery_path_requests; /*static*/ std::set Transport::_discovery_pr_tags; -/*static*/ uint16_t Transport::_max_pr_taXgxs = 32000; +/*static*/ uint16_t Transport::_max_pr_tags = 32000; /*static*/ std::set Transport::_control_destinations; /*static*/ std::set 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 outgoing; - std::vector path_requests; + std::set 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).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(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) { diff --git a/src/Transport.h b/src/Transport.h index 08b4417..0a2c98f 100644 --- a/src/Transport.h +++ b/src/Transport.h @@ -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& random_blobs, Interface& receiving_interface, const Packet& packet) : + DestinationEntry(double time, const Bytes& received_from, uint8_t announce_hops, double expires, const std::set& 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 _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 _pending_links; // Links that are being established static std::set _active_links; // Links that are active static std::set _packet_hashlist; // A list of packet hashes for duplicate detection - static std::set _receipts; // Receipts of all outgoing packets for proof processing + static std::list _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 _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 _path_requests; // A table for storing path request timestamps + static std::map _path_requests; // A table for storing path request timestamps static std::map _discovery_path_requests; // A table for keeping track of path requests on behalf of other nodes static std::set _discovery_pr_tags; // A table for keeping track of tagged path requests - static uint16_t _max_pr_taXgxs; // Maximum amount of unique path request tags to remember + 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; diff --git a/src/Type.h b/src/Type.h index 2e17a3a..225be05 100644 --- a/src/Type.h +++ b/src/Type.h @@ -1,5 +1,6 @@ #pragma once +#include "Log.h" #include "Cryptography/Fernet.h" #include diff --git a/src/Utilities/OS.h b/src/Utilities/OS.h index c86e109..f2405e0 100644 --- a/src/Utilities/OS.h +++ b/src/Utilities/OS.h @@ -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; } diff --git a/src/main.cpp b/src/main.cpp index 96f31ea..5cdf41d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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"); }