diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 2b98ec04..97781a08 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -44,6 +44,7 @@ #define CMD_SEND_TELEMETRY_REQ 39 #define CMD_GET_CUSTOM_VARS 40 #define CMD_SET_CUSTOM_VAR 41 +#define CMD_GET_ADVERT_PATH 42 #define RESP_CODE_OK 0 #define RESP_CODE_ERR 1 @@ -67,6 +68,7 @@ #define RESP_CODE_SIGN_START 19 #define RESP_CODE_SIGNATURE 20 #define RESP_CODE_CUSTOM_VARS 21 +#define RESP_CODE_ADVERT_PATH 22 #define SEND_TIMEOUT_BASE_MILLIS 500 #define FLOOD_SEND_TIMEOUT_FACTOR 16.0f @@ -219,7 +221,7 @@ bool MyMesh::isAutoAddEnabled() const { return (_prefs.manual_add_contacts & 1) == 0; } -void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new) { +void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) { if (_serial->isConnected()) { if (!isAutoAddEnabled() && is_new) { writeContactRespFrame(PUSH_CODE_NEW_ADVERT, contact); @@ -234,6 +236,27 @@ void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new) { #endif } + // add inbound-path to mem cache + if (path && path_len <= sizeof(AdvertPath::path)) { // check path is valid + AdvertPath* p = advert_paths; + uint32_t oldest = 0xFFFFFFFF; + for (int i = 0; i < ADVERT_PATH_TABLE_SIZE; i++) { // check if already in table, otherwise evict oldest + if (memcmp(advert_paths[i].pubkey_prefix, contact.id.pub_key, sizeof(AdvertPath::pubkey_prefix)) == 0) { + p = &advert_paths[i]; // found + break; + } + if (advert_paths[i].recv_timestamp < oldest) { + oldest = advert_paths[i].recv_timestamp; + p = &advert_paths[i]; + } + } + + memcpy(p->pubkey_prefix, contact.id.pub_key, sizeof(p->pubkey_prefix)); + p->recv_timestamp = getRTCClock()->getCurrentTime(); + p->path_len = path_len; + memcpy(p->path, path, p->path_len); + } + dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); } @@ -541,6 +564,7 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe next_ack_idx = 0; sign_data = NULL; dirty_contacts_expiry = 0; + memset(advert_paths, 0, sizeof(advert_paths)); // defaults memset(&_prefs, 0, sizeof(_prefs)); @@ -1249,6 +1273,26 @@ void MyMesh::handleCmdFrame(size_t len) { } else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); } + } else if (cmd_frame[0] == CMD_GET_ADVERT_PATH && len >= PUB_KEY_SIZE+2) { + // FUTURE use: uint8_t reserved = cmd_frame[1]; + uint8_t *pub_key = &cmd_frame[2]; + AdvertPath* found = NULL; + for (int i = 0; i < ADVERT_PATH_TABLE_SIZE; i++) { + auto p = &advert_paths[i]; + if (memcmp(p->pubkey_prefix, pub_key, sizeof(p->pubkey_prefix)) == 0) { + found = p; + break; + } + } + if (found) { + out_frame[0] = RESP_CODE_ADVERT_PATH; + memcpy(&out_frame[1], &found->recv_timestamp, 4); + out_frame[5] = found->path_len; + memcpy(&out_frame[6], found->path, found->path_len); + _serial->writeFrame(out_frame, 6 + found->path_len); + } else { + writeErrFrame(ERR_CODE_NOT_FOUND); + } } else { writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); MESH_DEBUG_PRINTLN("ERROR: unknown command: %02X", cmd_frame[0]); diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h index f6603feb..407b11d5 100644 --- a/examples/companion_radio/MyMesh.h +++ b/examples/companion_radio/MyMesh.h @@ -100,7 +100,7 @@ protected: void logRxRaw(float snr, float rssi, const uint8_t raw[], int len) override; bool isAutoAddEnabled() const override; - void onDiscoveredContact(ContactInfo &contact, bool is_new) override; + void onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) override; void onContactPathUpdated(const ContactInfo &contact) override; bool processAck(const uint8_t *data) override; void queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packet *pkt, uint32_t sender_timestamp, @@ -190,9 +190,18 @@ private: unsigned long msg_sent; uint32_t ack; }; -#define EXPECTED_ACK_TABLE_SIZE 8 + #define EXPECTED_ACK_TABLE_SIZE 8 AckTableEntry expected_ack_table[EXPECTED_ACK_TABLE_SIZE]; // circular table int next_ack_idx; + + struct AdvertPath { + uint8_t pubkey_prefix[7]; + uint8_t path_len; + uint32_t recv_timestamp; + uint8_t path[MAX_PATH_SIZE]; + }; + #define ADVERT_PATH_TABLE_SIZE 16 + AdvertPath advert_paths[ADVERT_PATH_TABLE_SIZE]; // circular table }; extern MyMesh the_mesh; diff --git a/examples/simple_secure_chat/main.cpp b/examples/simple_secure_chat/main.cpp index 63ff20da..a6b048a1 100644 --- a/examples/simple_secure_chat/main.cpp +++ b/examples/simple_secure_chat/main.cpp @@ -202,7 +202,7 @@ protected: return true; } - void onDiscoveredContact(ContactInfo& contact, bool is_new) override { + void onDiscoveredContact(ContactInfo& contact, bool is_new, uint8_t path_len, const uint8_t* path) override { // TODO: if not in favs, prompt to add as fav(?) Serial.printf("ADVERT from -> %s\n", contact.name); diff --git a/src/helpers/BaseChatMesh.cpp b/src/helpers/BaseChatMesh.cpp index 7efd4735..4649040e 100644 --- a/src/helpers/BaseChatMesh.cpp +++ b/src/helpers/BaseChatMesh.cpp @@ -58,7 +58,7 @@ void BaseChatMesh::onAdvertRecv(mesh::Packet* packet, const mesh::Identity& id, } ci.last_advert_timestamp = timestamp; ci.lastmod = getRTCClock()->getCurrentTime(); - onDiscoveredContact(ci, true); // let UI know + onDiscoveredContact(ci, true, packet->path_len, packet->path); // let UI know return; } @@ -89,7 +89,7 @@ void BaseChatMesh::onAdvertRecv(mesh::Packet* packet, const mesh::Identity& id, from->last_advert_timestamp = timestamp; from->lastmod = getRTCClock()->getCurrentTime(); - onDiscoveredContact(*from, is_new); // let UI know + onDiscoveredContact(*from, is_new, packet->path_len, packet->path); // let UI know } int BaseChatMesh::searchPeersByHash(const uint8_t* hash) { diff --git a/src/helpers/BaseChatMesh.h b/src/helpers/BaseChatMesh.h index 83ad2a89..de73ea78 100644 --- a/src/helpers/BaseChatMesh.h +++ b/src/helpers/BaseChatMesh.h @@ -89,7 +89,7 @@ protected: // 'UI' concepts, for sub-classes to implement virtual bool isAutoAddEnabled() const { return true; } - virtual void onDiscoveredContact(ContactInfo& contact, bool is_new) = 0; + virtual void onDiscoveredContact(ContactInfo& contact, bool is_new, uint8_t path_len, const uint8_t* path) = 0; virtual bool processAck(const uint8_t *data) = 0; virtual void onContactPathUpdated(const ContactInfo& contact) = 0; virtual void onMessageRecv(const ContactInfo& contact, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) = 0;