Let room users manage their own return routes
This commit is contained in:
1 parent
5cb8367d12
commit
0eb1d03a16
15 files changed
+1098
-54
No files matched your search
Vendored
+196
@@ -0,0 +1,196 @@
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "filesystem.h"
|
||||
#include <Packet.h>
|
||||
#include <helpers/RoomAccessPolicy.h>
|
||||
#include <helpers/RoomClientPathCommand.h>
|
||||
#include <helpers/ClientPathObservation.h>
|
||||
#include <helpers/ClientPathPersistence.h>
|
||||
#include <helpers/RemoteCliReplyCache.h>
|
||||
#include <helpers/RemoteCliRequest.h>
|
||||
#include <helpers/ClientACLResponse.h>
|
||||
#include <helpers/LazyPersistence.h>
|
||||
#include <helpers/LogicalMessageCache.h>
|
||||
#include <helpers/TxtDataHelpers.h>
|
||||
|
||||
@CONSTANTS@
|
||||
@STR_HELPER@
|
||||
#define MESH_CLIENT_REPEATER_ONLY 0
|
||||
namespace mesh {
|
||||
struct Identity { uint8_t pub_key[PUB_KEY_SIZE]; };
|
||||
struct Utils {
|
||||
static void sha256(uint8_t* out, size_t n, const uint8_t* left, size_t ln,
|
||||
const uint8_t* right, size_t rn) {
|
||||
memset(out, 0, n);
|
||||
for (size_t i = 0; i < ln; ++i) out[i % n] ^= left[i];
|
||||
for (size_t i = 0; i < rn; ++i) out[i % n] ^= right[i];
|
||||
}
|
||||
};
|
||||
@PACKET_METHODS@
|
||||
}
|
||||
@CLIENT_INFO@;
|
||||
|
||||
struct FakeACL {
|
||||
ClientInfo clients[2]{};
|
||||
ClientInfo durable[2]{};
|
||||
bool retained[2]{};
|
||||
bool save_ok = true;
|
||||
unsigned saves = 0;
|
||||
int getNumClients() const { return 2; }
|
||||
ClientInfo* getClientByIdx(int i) { assert(i >= 0 && i < 2); return &clients[i]; }
|
||||
bool save(MemoryFS* fs, bool (*filter)(ClientInfo*)) {
|
||||
++saves;
|
||||
assert(fs != nullptr && filter != nullptr);
|
||||
if (!save_ok) return false;
|
||||
for (unsigned i = 0; i < 2; ++i) {
|
||||
retained[i] = filter(&clients[i]);
|
||||
if (retained[i]) durable[i] = clients[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
struct FakeClock {
|
||||
uint32_t now = 1000;
|
||||
uint32_t serial = 0;
|
||||
uint32_t getCurrentTime() const { return now; }
|
||||
uint32_t getCurrentTimeUnique() { return now + ++serial; }
|
||||
};
|
||||
struct FakeRng {
|
||||
void random(uint8_t* data, size_t n) { memset(data, 0xB5, n); }
|
||||
};
|
||||
static uint32_t ticks = 100;
|
||||
static uint32_t millis() { return ticks; }
|
||||
struct Sent {
|
||||
mesh::Packet packet;
|
||||
uint8_t path[MAX_PATH_SIZE]{};
|
||||
uint8_t path_len = 0;
|
||||
unsigned long delay = 0;
|
||||
bool direct = true;
|
||||
bool retry_enabled = false;
|
||||
};
|
||||
struct MyMesh {
|
||||
FakeACL acl;
|
||||
MemoryFS policy_fs;
|
||||
MemoryFS* _fs = &policy_fs;
|
||||
mesh::RoomAccessPolicy room_access;
|
||||
mesh::RemoteCliReplyCache remote_cli_reply_cache;
|
||||
mesh::LogicalMessageCache<ROOM_MESSAGE_CACHE_SIZE> recent_room_posts;
|
||||
mesh::LogicalMessageCache<ROOM_MESSAGE_CACHE_SIZE> recent_room_polls;
|
||||
int matching_peer_indexes[2] = {0, 1};
|
||||
unsigned long dirty_contacts_expiry = 0;
|
||||
uint8_t contacts_save_failures = 0;
|
||||
FakeClock clock;
|
||||
FakeRng rng;
|
||||
uint8_t reply_data[MAX_PACKET_PAYLOAD]{};
|
||||
mesh::Packet pool[64];
|
||||
unsigned used = 0, allocations = 0, releases = 0, fail_allocation = UINT32_MAX;
|
||||
bool send_ok = true;
|
||||
unsigned general_commands = 0, posts = 0, retry_replacements = 0, _num_post_pushes = 0;
|
||||
uint32_t retry_timestamp = 0;
|
||||
mesh::Packet retry_packet;
|
||||
std::vector<Sent> sent;
|
||||
uint16_t default_scope = 0;
|
||||
struct Prefs {
|
||||
uint8_t direct_retry_enabled = 1;
|
||||
uint8_t path_hash_mode = 0;
|
||||
} _prefs;
|
||||
MyMesh() {
|
||||
metadata_filesystem = &policy_fs;
|
||||
assert(room_access.load(&policy_fs));
|
||||
for (unsigned i = 0; i < 2; ++i) {
|
||||
ClientInfo& c = acl.clients[i];
|
||||
memset(&c, 0, sizeof(c));
|
||||
memset(c.id.pub_key, i + 1, PUB_KEY_SIZE);
|
||||
memset(c.shared_secret, i + 0x40, PUB_KEY_SIZE);
|
||||
c.permissions = PERM_ACL_READ_WRITE;
|
||||
c.out_path_len = 1;
|
||||
c.out_path[0] = i + 0xA1;
|
||||
c.alt_path_len = OUT_PATH_UNKNOWN;
|
||||
c.observed_path_len = OUT_PATH_UNKNOWN;
|
||||
c.last_timestamp = 99;
|
||||
}
|
||||
}
|
||||
FakeClock* getRTCClock() { return &clock; }
|
||||
FakeRng* getRNG() { return &rng; }
|
||||
unsigned long futureMillis(unsigned long delay) { return ticks + delay; }
|
||||
mesh::Packet* obtainNewPacket() {
|
||||
if (++allocations == fail_allocation) return nullptr;
|
||||
assert(used < 64);
|
||||
return &pool[used++];
|
||||
}
|
||||
void releasePacket(mesh::Packet* p) { assert(p != nullptr); ++releases; }
|
||||
mesh::Packet* createDatagram(uint8_t type, const mesh::Identity&, const uint8_t*,
|
||||
const uint8_t* data, size_t n) {
|
||||
auto p = obtainNewPacket();
|
||||
if (p) {
|
||||
p->header = type << PH_TYPE_SHIFT;
|
||||
p->payload_len = n;
|
||||
memcpy(p->payload, data, n);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
mesh::Packet* createPathReturn(const mesh::Identity& id, const uint8_t* secret,
|
||||
const uint8_t*, uint8_t, uint8_t type, const uint8_t* data, size_t n) {
|
||||
return createDatagram(type, id, secret, data, n);
|
||||
}
|
||||
mesh::Packet* createAck(uint32_t ack) {
|
||||
mesh::Identity empty{}; uint8_t secret[PUB_KEY_SIZE]{};
|
||||
return createDatagram(PAYLOAD_TYPE_ACK, empty, secret, (const uint8_t*)&ack, 4);
|
||||
}
|
||||
mesh::Packet* createMultiAck(uint32_t ack, uint8_t) { return createAck(ack); }
|
||||
bool sendDirect(mesh::Packet* p, const uint8_t* path, uint8_t n, unsigned long delay = 0) {
|
||||
assert(p && mesh::Packet::isValidPathLen(n));
|
||||
Sent value; value.packet = *p; value.path_len = n; value.delay = delay;
|
||||
value.retry_enabled = _prefs.direct_retry_enabled != 0;
|
||||
memcpy(value.path, path, mesh::encodedClientPathByteLength(n));
|
||||
sent.push_back(value);
|
||||
return send_ok;
|
||||
}
|
||||
bool sendFloodReply(mesh::Packet* p, unsigned long delay, uint8_t hash_size) {
|
||||
Sent value; value.packet = *p; value.delay = delay; value.direct = false;
|
||||
value.path_len = (hash_size - 1) << 6;
|
||||
sent.push_back(value);
|
||||
return send_ok;
|
||||
}
|
||||
bool sendFloodScoped(uint16_t, mesh::Packet* p, unsigned long delay, uint8_t hash_size) {
|
||||
return sendFloodReply(p, delay, hash_size);
|
||||
}
|
||||
void replaceActiveMessageRetries(mesh::Packet* p, const uint8_t*, uint32_t timestamp) {
|
||||
++retry_replacements; retry_packet = *p; retry_timestamp = timestamp;
|
||||
}
|
||||
void handleCommand(uint32_t, char*, char* reply, int, uint8_t) {
|
||||
++general_commands; strcpy(reply, "OK admin");
|
||||
}
|
||||
bool addPost(ClientInfo*, const char*) { ++posts; return true; }
|
||||
void serviceRoomQuotas();
|
||||
uint8_t getUnsyncedCount(ClientInfo*) { return 0; }
|
||||
int getExtraAckTransmitCount() { return 0; }
|
||||
int handleRequest(ClientInfo*, uint32_t, uint8_t*, size_t, size_t) { return 0; }
|
||||
static bool saveFilter(ClientInfo*);
|
||||
bool handleClientPathCommand(ClientInfo*, char*, char*);
|
||||
bool sendClientReply(ClientInfo*, mesh::Packet*, unsigned long, uint8_t);
|
||||
bool pushRoomTextToClient(ClientInfo*, uint32_t, const mesh::Identity&, const char*, uint32_t);
|
||||
void onPeerDataRecv(mesh::Packet*, uint8_t, int, const uint8_t*, uint8_t*, size_t);
|
||||
void command(const char* text, uint32_t timestamp = 100, unsigned sender = 0,
|
||||
uint32_t logical = 0, uint8_t flags = TXT_TYPE_CLI_COMMAND) {
|
||||
std::vector<uint8_t> data(5 + strlen(text) + mesh::RemoteCliRequest::EXTENSION_SIZE + 1);
|
||||
memcpy(data.data(), ×tamp, 4); data[4] = flags << 2;
|
||||
memcpy(data.data() + 5, text, strlen(text));
|
||||
size_t length = 5 + strlen(text);
|
||||
if (logical) length = mesh::RemoteCliRequest::append(data.data(), data.size(), 5, strlen(text), logical);
|
||||
mesh::Packet packet; packet.header = ROUTE_TYPE_DIRECT;
|
||||
onPeerDataRecv(&packet, PAYLOAD_TYPE_TXT_MSG, sender, acl.clients[sender].shared_secret,
|
||||
data.data(), length);
|
||||
}
|
||||
std::string reply() const {
|
||||
if (sent.empty()) return "";
|
||||
const auto& p = sent.back().packet;
|
||||
return std::string((const char*)p.payload + 5, p.payload_len - 5);
|
||||
}
|
||||
};
|
||||
@PRODUCTION_METHODS@
|
||||
@TEST_CASES@
|
||||
Reference in new issue
Block a user