Vendor microReticulum library with boundary mode transport fixes: - Two-whitelist system gates backbone traffic (local addresses + mentioned addresses from local devices) - Allow control_hashes and local destinations through boundary filter (fixes backbone→LoRa path discovery) - Fix get_cached_packet() to call unpack() instead of update_hash() (fixes empty destination_hash in path responses) - LRPROOF Identity::recall null guard - remaining_hops HEADER_1/BROADCAST fix for final-hop delivery - PROOF packets excluded from boundary wrapping - Iterator invalidation fix in transport table cleanup - is_backbone flag replaces string matching for interface identification Firmware changes: - Set is_backbone(true) on backbone TCP interface - Rename default TcpInterface name to BackboneInterface - Update comments for dual-use TcpInterface (backbone + local AP) - Use vendored lib/microReticulum instead of PlatformIO registry
202 lines
5.9 KiB
C++
Executable File
202 lines
5.9 KiB
C++
Executable File
#include "Bytes.h"
|
|
|
|
using namespace RNS;
|
|
|
|
// Creates new shared data for instance
|
|
// - If capacity is specified (>0) then create empty shared data with initial reserved capacity
|
|
// - If capacity is not specified (<=0) then create empty shared data with no initial capacity
|
|
void Bytes::newData(size_t capacity /*= 0*/) {
|
|
//MEMF("Bytes is creating own data with capacity %u", capacity);
|
|
//MEM("newData: Creating new data...");
|
|
Data* data = new Data();
|
|
if (data == nullptr) {
|
|
ERROR("Bytes failed to allocate empty data buffer");
|
|
throw std::runtime_error("Failed to allocate empty data buffer");
|
|
}
|
|
//MEM("newData: Created new data");
|
|
if (capacity > 0) {
|
|
//MEMF("newData: Reserving data capacity of %u...", capacity);
|
|
data->reserve(capacity);
|
|
//MEM("newData: Reserved data capacity");
|
|
}
|
|
//MEM("newData: Assigning data to shared data pointer...");
|
|
_data = SharedData(data);
|
|
//MEM("newData: Assigned data to shared data pointer");
|
|
_exclusive = true;
|
|
}
|
|
|
|
// Ensures that instance has exclusive shared data
|
|
// - If instance has no shared data then create new shared data
|
|
// - If instance does not have exclusive on shared data that is not empty then make a copy of shared data (if requests) and reserve capacity (if requested)
|
|
// - If instance does not have exclusive on shared data that is empty then create new shared data
|
|
// - If instance already has exclusive on shared data then do nothing except reserve capacity (if requested)
|
|
void Bytes::exclusiveData(bool copy /*= true*/, size_t capacity /*= 0*/) {
|
|
if (!_data) {
|
|
newData(capacity);
|
|
}
|
|
else if (!_exclusive) {
|
|
if (copy && !_data->empty()) {
|
|
//TRACE("Bytes is creating a writable copy of its shared data");
|
|
//Data* data = new Data(*_data.get());
|
|
//MEM("exclusiveData: Creating new data...");
|
|
Data* data = new Data();
|
|
if (data == nullptr) {
|
|
ERROR("Bytes failed to duplicate data buffer");
|
|
throw std::runtime_error("Failed to duplicate data buffer");
|
|
}
|
|
//MEM("exclusiveData: Created new data");
|
|
if (capacity > 0) {
|
|
//MEMF("exclusiveData: Reserving data capacity of %u...", capacity);
|
|
// if requested capacity < existing size then reserve capacity for existing size instead
|
|
data->reserve((capacity > _data->size()) ? capacity : _data->size());
|
|
//MEM("exclusiveData: Reserved data capacity");
|
|
}
|
|
else {
|
|
data->reserve(_data->size());
|
|
}
|
|
//MEM("exclusiveData: Copying existing data...");
|
|
data->insert(data->begin(), _data->begin(), _data->end());
|
|
//MEM("exclusiveData: Copied existing data");
|
|
//MEM("exclusiveData: Assigning data to shared data pointer...");
|
|
_data = SharedData(data);
|
|
//MEM("exclusiveData: Assigned data to shared data pointer");
|
|
_exclusive = true;
|
|
}
|
|
else {
|
|
//MEM("Bytes is creating its own data because shared is empty");
|
|
//data = new Data();
|
|
//if (data == nullptr) {
|
|
// ERROR("Bytes failed to allocate empty data buffer");
|
|
// throw std::runtime_error("Failed to allocate empty data buffer");
|
|
//}
|
|
//_data = SharedData(data);
|
|
//_exclusive = true;
|
|
//MEM("exclusiveData: Creating new empty data...");
|
|
newData(capacity);
|
|
//MEM("exclusiveData: Created new empty data");
|
|
}
|
|
}
|
|
else if (capacity > 0 && capacity > size()) {
|
|
reserve(capacity);
|
|
}
|
|
}
|
|
|
|
int Bytes::compare(const Bytes& bytes) const {
|
|
if (_data == bytes._data) {
|
|
return 0;
|
|
}
|
|
else if (!_data) {
|
|
return -1;
|
|
}
|
|
else if (!bytes._data) {
|
|
return 1;
|
|
}
|
|
else if (*_data < *(bytes._data)) {
|
|
return -1;
|
|
}
|
|
else if (*_data > *(bytes._data)) {
|
|
return 1;
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int Bytes::compare(const uint8_t* buf, size_t size) const {
|
|
if (!_data && size == 0) {
|
|
return 0;
|
|
}
|
|
else if (!_data) {
|
|
return -1;
|
|
}
|
|
int cmp = memcmp(_data->data(), buf, (_data->size() < size) ? _data->size() : size);
|
|
if (cmp == 0 && _data->size() < size) {
|
|
return -1;
|
|
}
|
|
else if (cmp == 0 && _data->size() > size) {
|
|
return 1;
|
|
}
|
|
return cmp;
|
|
}
|
|
|
|
void Bytes::assignHex(const uint8_t* hex, size_t hex_size) {
|
|
// if assignment is empty then clear data and don't bother creating new
|
|
if (hex == nullptr || hex_size <= 0) {
|
|
_data = nullptr;
|
|
_exclusive = true;
|
|
return;
|
|
}
|
|
exclusiveData(false, hex_size / 2);
|
|
// need to clear data since we're appending below
|
|
_data->clear();
|
|
for (size_t i = 0; i < hex_size; i += 2) {
|
|
uint8_t byte = (hex[i] % 32 + 9) % 25 * 16 + (hex[i+1] % 32 + 9) % 25;
|
|
_data->push_back(byte);
|
|
}
|
|
}
|
|
|
|
void Bytes::appendHex(const uint8_t* hex, size_t hex_size) {
|
|
// if append is empty then do nothing
|
|
if (hex == nullptr || hex_size <= 0) {
|
|
return;
|
|
}
|
|
exclusiveData(true, size() + (hex_size / 2));
|
|
for (size_t i = 0; i < hex_size; i += 2) {
|
|
uint8_t byte = (hex[i] % 32 + 9) % 25 * 16 + (hex[i+1] % 32 + 9) % 25;
|
|
_data->push_back(byte);
|
|
}
|
|
}
|
|
|
|
const char hex_upper_chars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
|
const char hex_lower_chars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
|
|
|
|
std::string RNS::hexFromByte(uint8_t byte, bool upper /*= true*/) {
|
|
std::string hex;
|
|
if (upper) {
|
|
hex += hex_upper_chars[ (byte& 0xF0) >> 4];
|
|
hex += hex_upper_chars[ (byte& 0x0F) >> 0];
|
|
}
|
|
else {
|
|
hex += hex_lower_chars[ (byte& 0xF0) >> 4];
|
|
hex += hex_lower_chars[ (byte& 0x0F) >> 0];
|
|
}
|
|
return hex;
|
|
}
|
|
|
|
std::string Bytes::toHex(bool upper /*= false*/) const {
|
|
if (!_data) {
|
|
return "";
|
|
}
|
|
std::string hex;
|
|
for (uint8_t byte : *_data) {
|
|
if (upper) {
|
|
hex += hex_upper_chars[ (byte& 0xF0) >> 4];
|
|
hex += hex_upper_chars[ (byte& 0x0F) >> 0];
|
|
}
|
|
else {
|
|
hex += hex_lower_chars[ (byte& 0xF0) >> 4];
|
|
hex += hex_lower_chars[ (byte& 0x0F) >> 0];
|
|
}
|
|
}
|
|
return hex;
|
|
}
|
|
|
|
// mid
|
|
Bytes Bytes::mid(size_t beginpos, size_t len) const {
|
|
if (!_data || beginpos >= size()) {
|
|
return NONE;
|
|
}
|
|
if ((beginpos + len) >= size()) {
|
|
len = (size() - beginpos);
|
|
}
|
|
return {data() + beginpos, len};
|
|
}
|
|
|
|
// to end
|
|
Bytes Bytes::mid(size_t beginpos) const {
|
|
if (!_data || beginpos >= size()) {
|
|
return NONE;
|
|
}
|
|
return {data() + beginpos, size() - beginpos};
|
|
}
|