diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 7847d652..04d5577e 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -294,7 +294,7 @@ void MyMesh::onContactPathUpdated(const ContactInfo &contact) { dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); } -bool MyMesh::processAck(const uint8_t *data) { +ContactInfo* MyMesh::processAck(const uint8_t *data) { // see if matches any in a table for (int i = 0; i < EXPECTED_ACK_TABLE_SIZE; i++) { if (memcmp(data, &expected_ack_table[i].ack, 4) == 0) { // got an ACK from recipient @@ -306,7 +306,7 @@ bool MyMesh::processAck(const uint8_t *data) { // NOTE: the same ACK can be received multiple times! expected_ack_table[i].ack = 0; // clear expected hash, now that we have received ACK - return true; + return expected_ack_table[i].contact; } } return checkConnectionsAck(data); @@ -825,6 +825,7 @@ void MyMesh::handleCmdFrame(size_t len) { if (expected_ack) { expected_ack_table[next_ack_idx].msg_sent = _ms->getMillis(); // add to circular table expected_ack_table[next_ack_idx].ack = expected_ack; + expected_ack_table[next_ack_idx].contact = recipient; next_ack_idx = (next_ack_idx + 1) % EXPECTED_ACK_TABLE_SIZE; } diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h index e3235128..0dc9ad61 100644 --- a/examples/companion_radio/MyMesh.h +++ b/examples/companion_radio/MyMesh.h @@ -112,7 +112,7 @@ protected: bool onContactPathRecv(ContactInfo& from, uint8_t* in_path, uint8_t in_path_len, uint8_t* out_path, uint8_t out_path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len) 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; + ContactInfo* processAck(const uint8_t *data) override; void queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packet *pkt, uint32_t sender_timestamp, const uint8_t *extra, int extra_len, const char *text); @@ -205,6 +205,7 @@ private: struct AckTableEntry { unsigned long msg_sent; uint32_t ack; + ContactInfo* contact; }; #define EXPECTED_ACK_TABLE_SIZE 8 AckTableEntry expected_ack_table[EXPECTED_ACK_TABLE_SIZE]; // circular table diff --git a/examples/simple_secure_chat/main.cpp b/examples/simple_secure_chat/main.cpp index a6b048a1..eac35898 100644 --- a/examples/simple_secure_chat/main.cpp +++ b/examples/simple_secure_chat/main.cpp @@ -217,18 +217,18 @@ protected: saveContacts(); } - bool processAck(const uint8_t *data) override { + ContactInfo* processAck(const uint8_t *data) override { if (memcmp(data, &expected_ack_crc, 4) == 0) { // got an ACK from recipient Serial.printf(" Got ACK! (round trip: %d millis)\n", _ms->getMillis() - last_msg_sent); // NOTE: the same ACK can be received multiple times! expected_ack_crc = 0; // reset our expected hash, now that we have received ACK - return true; + return NULL; // TODO: really should return ContactInfo pointer } //uint32_t crc; //memcpy(&crc, data, 4); //MESH_DEBUG_PRINTLN("unknown ACK received: %08X (expected: %08X)", crc, expected_ack_crc); - return false; + return NULL; } void onMessageRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) override { diff --git a/src/helpers/BaseChatMesh.cpp b/src/helpers/BaseChatMesh.cpp index 60366c65..eb199ef5 100644 --- a/src/helpers/BaseChatMesh.cpp +++ b/src/helpers/BaseChatMesh.cpp @@ -223,6 +223,10 @@ void BaseChatMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender } } else if (type == PAYLOAD_TYPE_RESPONSE && len > 0) { onContactResponse(from, data, len); + if (packet->isRouteFlood() && from.out_path_len >= 0) { + // we have direct path, but other node is still sending flood response, so maybe they didn't receive reciprocal path properly(?) + handleReturnPathRetry(from, packet->path, packet->path_len); + } } } @@ -248,7 +252,7 @@ bool BaseChatMesh::onContactPathRecv(ContactInfo& from, uint8_t* in_path, uint8_ if (extra_type == PAYLOAD_TYPE_ACK && extra_len >= 4) { // also got an encoded ACK! - if (processAck(extra)) { + if (processAck(extra) != NULL) { txt_send_timeout = 0; // matched one we're waiting for, cancel timeout timer } } else if (extra_type == PAYLOAD_TYPE_RESPONSE && extra_len > 0) { @@ -258,12 +262,25 @@ bool BaseChatMesh::onContactPathRecv(ContactInfo& from, uint8_t* in_path, uint8_ } void BaseChatMesh::onAckRecv(mesh::Packet* packet, uint32_t ack_crc) { - if (processAck((uint8_t *)&ack_crc)) { + ContactInfo* from; + if ((from = processAck((uint8_t *)&ack_crc)) != NULL) { txt_send_timeout = 0; // matched one we're waiting for, cancel timeout timer packet->markDoNotRetransmit(); // ACK was for this node, so don't retransmit + + if (packet->isRouteFlood() && from->out_path_len >= 0) { + // we have direct path, but other node is still sending flood, so maybe they didn't receive reciprocal path properly(?) + handleReturnPathRetry(*from, packet->path, packet->path_len); + } } } +void BaseChatMesh::handleReturnPathRetry(const ContactInfo& contact, const uint8_t* path, uint8_t path_len) { + // NOTE: simplest impl is just to re-send a reciprocal return path to sender (DIRECTLY) + // override this method in various firmwares, if there's a better strategy + mesh::Packet* rpath = createPathReturn(contact.id, contact.shared_secret, path, path_len, 0, NULL, 0); + if (rpath) sendDirect(rpath, contact.out_path, contact.out_path_len, 3000); // 3 second delay +} + #ifdef MAX_GROUP_CHANNELS int BaseChatMesh::searchChannelsByHash(const uint8_t* hash, mesh::GroupChannel dest[], int max_matches) { int n = 0; @@ -550,7 +567,7 @@ void BaseChatMesh::markConnectionActive(const ContactInfo& contact) { } } -bool BaseChatMesh::checkConnectionsAck(const uint8_t* data) { +ContactInfo* BaseChatMesh::checkConnectionsAck(const uint8_t* data) { for (int i = 0; i < MAX_CONNECTIONS; i++) { if (connections[i].keep_alive_millis > 0 && memcmp(&connections[i].expected_ack, data, 4) == 0) { // yes, got an ack for our keep_alive request! @@ -559,10 +576,12 @@ bool BaseChatMesh::checkConnectionsAck(const uint8_t* data) { // re-schedule next KEEP_ALIVE, now that we have heard from server connections[i].next_ping = futureMillis(connections[i].keep_alive_millis); - return true; // yes, a match + + auto id = &connections[i].server_id; + return lookupContactByPubKey(id->pub_key, PUB_KEY_SIZE); // yes, a match } } - return false; /// no match + return NULL; /// no match } void BaseChatMesh::checkConnections() { diff --git a/src/helpers/BaseChatMesh.h b/src/helpers/BaseChatMesh.h index 9a4aa810..9392001e 100644 --- a/src/helpers/BaseChatMesh.h +++ b/src/helpers/BaseChatMesh.h @@ -93,7 +93,7 @@ protected: // 'UI' concepts, for sub-classes to implement virtual bool isAutoAddEnabled() const { return true; } 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 ContactInfo* processAck(const uint8_t *data) = 0; virtual void onContactPathUpdated(const ContactInfo& contact) = 0; virtual bool onContactPathRecv(ContactInfo& from, uint8_t* in_path, uint8_t in_path_len, uint8_t* out_path, uint8_t out_path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len); virtual void onMessageRecv(const ContactInfo& contact, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) = 0; @@ -105,6 +105,7 @@ protected: virtual void onChannelMessageRecv(const mesh::GroupChannel& channel, mesh::Packet* pkt, uint32_t timestamp, const char *text) = 0; virtual uint8_t onContactRequest(const ContactInfo& contact, uint32_t sender_timestamp, const uint8_t* data, uint8_t len, uint8_t* reply) = 0; virtual void onContactResponse(const ContactInfo& contact, const uint8_t* data, uint8_t len) = 0; + virtual void handleReturnPathRetry(const ContactInfo& contact, const uint8_t* path, uint8_t path_len); // storage concepts, for sub-classes to override/implement virtual int getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]) { return 0; } // not implemented @@ -127,7 +128,7 @@ protected: void stopConnection(const uint8_t* pub_key); bool hasConnectionTo(const uint8_t* pub_key); void markConnectionActive(const ContactInfo& contact); - bool checkConnectionsAck(const uint8_t* data); + ContactInfo* checkConnectionsAck(const uint8_t* data); void checkConnections(); public: