Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 62 additions & 12 deletions src/helpers/BaseChatMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ mesh::Packet* BaseChatMesh::createSelfAdvert(const char* name, double lat, doubl
}

void BaseChatMesh::sendAckTo(const ContactInfo& dest, uint32_t ack_hash) {
if (dest.out_path_len < 0) {
if (!shouldUseDirectPath(dest)) {
mesh::Packet* ack = createAck(ack_hash);
if (ack) sendFloodScoped(dest, ack, TXT_ACK_DELAY);
} else {
Expand All @@ -55,6 +55,26 @@ void BaseChatMesh::sendAckTo(const ContactInfo& dest, uint32_t ack_hash) {
}
}

bool BaseChatMesh::isAmbiguousDirectPath(const ContactInfo& recipient) const {
if (recipient.out_path_len <= 0) return false;
for (int i = 0; i < recipient.out_path_len; i++) {
uint8_t hop = recipient.out_path[i];
bool seen_once = false;
for (int j = 0; j < num_contacts; j++) {
if (contacts[j].id.matches(recipient.id)) continue;
if (contacts[j].id.pub_key[0] == hop) {
if (seen_once) return true;
seen_once = true;
}
}
}
return false;
}

bool BaseChatMesh::shouldUseDirectPath(const ContactInfo& recipient) const {
return recipient.out_path_len >= 0 && !isAmbiguousDirectPath(recipient);
}

void BaseChatMesh::bootstrapRTCfromContacts() {
uint32_t latest = 0;
for (int i = 0; i < num_contacts; i++) {
Expand Down Expand Up @@ -263,17 +283,20 @@ void BaseChatMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender
} else {
mesh::Packet* reply = createDatagram(PAYLOAD_TYPE_RESPONSE, from.id, secret, temp_buf, reply_len);
if (reply) {
if (from.out_path_len >= 0) { // we have an out_path, so send DIRECT
if (shouldUseDirectPath(from)) { // we have an unambiguous out_path, so send DIRECT
sendDirect(reply, from.out_path, from.out_path_len, SERVER_RESPONSE_DELAY);
} else {
if (from.out_path_len >= 0) {
ambiguous_direct_avoids++;
}
sendFloodScoped(from, reply, SERVER_RESPONSE_DELAY);
}
}
}
}
} else if (type == PAYLOAD_TYPE_RESPONSE && len > 0) {
onContactResponse(from, data, len);
if (packet->isRouteFlood() && from.out_path_len >= 0) {
if (packet->isRouteFlood() && shouldUseDirectPath(from)) {
// 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);
}
Expand Down Expand Up @@ -317,7 +340,7 @@ void BaseChatMesh::onAckRecv(mesh::Packet* packet, uint32_t ack_crc) {
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) {
if (packet->isRouteFlood() && shouldUseDirectPath(*from)) {
// 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);
}
Expand All @@ -327,6 +350,12 @@ void BaseChatMesh::onAckRecv(mesh::Packet* packet, uint32_t ack_crc) {
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
if (!shouldUseDirectPath(contact)) {
if (contact.out_path_len >= 0) {
ambiguous_direct_avoids++;
}
return;
}
mesh::Packet* rpath = createPathReturn(contact.id, contact.getSharedSecret(self_id), path, path_len, 0, NULL, 0);
if (rpath) sendDirect(rpath, contact.out_path, contact.out_path_len, 3000); // 3 second delay
}
Expand Down Expand Up @@ -386,7 +415,10 @@ int BaseChatMesh::sendMessage(const ContactInfo& recipient, uint32_t timestamp,
uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength());

int rc;
if (recipient.out_path_len < 0) {
if (!shouldUseDirectPath(recipient)) {
if (recipient.out_path_len >= 0) {
ambiguous_direct_avoids++;
}
sendFloodScoped(recipient, pkt);
txt_send_timeout = futureMillis(est_timeout = calcFloodTimeoutMillisFor(t));
rc = MSG_SEND_SENT_FLOOD;
Expand All @@ -412,7 +444,10 @@ int BaseChatMesh::sendCommandData(const ContactInfo& recipient, uint32_t timest

uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength());
int rc;
if (recipient.out_path_len < 0) {
if (!shouldUseDirectPath(recipient)) {
if (recipient.out_path_len >= 0) {
ambiguous_direct_avoids++;
}
sendFloodScoped(recipient, pkt);
txt_send_timeout = futureMillis(est_timeout = calcFloodTimeoutMillisFor(t));
rc = MSG_SEND_SENT_FLOOD;
Expand Down Expand Up @@ -500,7 +535,10 @@ int BaseChatMesh::sendLogin(const ContactInfo& recipient, const char* password,
}
if (pkt) {
uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength());
if (recipient.out_path_len < 0) {
if (!shouldUseDirectPath(recipient)) {
if (recipient.out_path_len >= 0) {
ambiguous_direct_avoids++;
}
sendFloodScoped(recipient, pkt);
est_timeout = calcFloodTimeoutMillisFor(t);
return MSG_SEND_SENT_FLOOD;
Expand All @@ -525,7 +563,10 @@ int BaseChatMesh::sendAnonReq(const ContactInfo& recipient, const uint8_t* data,
}
if (pkt) {
uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength());
if (recipient.out_path_len < 0) {
if (!shouldUseDirectPath(recipient)) {
if (recipient.out_path_len >= 0) {
ambiguous_direct_avoids++;
}
sendFloodScoped(recipient, pkt);
est_timeout = calcFloodTimeoutMillisFor(t);
return MSG_SEND_SENT_FLOOD;
Expand All @@ -552,7 +593,10 @@ int BaseChatMesh::sendRequest(const ContactInfo& recipient, const uint8_t* req_
}
if (pkt) {
uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength());
if (recipient.out_path_len < 0) {
if (!shouldUseDirectPath(recipient)) {
if (recipient.out_path_len >= 0) {
ambiguous_direct_avoids++;
}
sendFloodScoped(recipient, pkt);
est_timeout = calcFloodTimeoutMillisFor(t);
return MSG_SEND_SENT_FLOOD;
Expand All @@ -579,7 +623,10 @@ int BaseChatMesh::sendRequest(const ContactInfo& recipient, uint8_t req_type, u
}
if (pkt) {
uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength());
if (recipient.out_path_len < 0) {
if (!shouldUseDirectPath(recipient)) {
if (recipient.out_path_len >= 0) {
ambiguous_direct_avoids++;
}
sendFloodScoped(recipient, pkt);
est_timeout = calcFloodTimeoutMillisFor(t);
return MSG_SEND_SENT_FLOOD;
Expand Down Expand Up @@ -683,8 +730,11 @@ void BaseChatMesh::checkConnections() {
MESH_DEBUG_PRINTLN("checkConnections(): Keep_alive contact not found!");
continue;
}
if (contact->out_path_len < 0) {
MESH_DEBUG_PRINTLN("checkConnections(): Keep_alive contact, no out_path!");
if (!shouldUseDirectPath(*contact)) {
MESH_DEBUG_PRINTLN("checkConnections(): Keep_alive contact, no direct path candidate");
if (contact->out_path_len >= 0) {
ambiguous_direct_avoids++;
}
continue;
}

Expand Down
4 changes: 4 additions & 0 deletions src/helpers/BaseChatMesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,11 @@ class BaseChatMesh : public mesh::Mesh {
mesh::Packet* _pendingLoopback;
uint8_t temp_buf[MAX_TRANS_UNIT];
ConnectionInfo connections[MAX_CONNECTIONS];
uint32_t ambiguous_direct_avoids;

mesh::Packet* composeMsgPacket(const ContactInfo& recipient, uint32_t timestamp, uint8_t attempt, const char *text, uint32_t& expected_ack);
bool isAmbiguousDirectPath(const ContactInfo& recipient) const;
bool shouldUseDirectPath(const ContactInfo& recipient) const;
void sendAckTo(const ContactInfo& dest, uint32_t ack_hash);

protected:
Expand All @@ -85,6 +88,7 @@ class BaseChatMesh : public mesh::Mesh {
#endif
txt_send_timeout = 0;
_pendingLoopback = NULL;
ambiguous_direct_avoids = 0;
memset(connections, 0, sizeof(connections));
}

Expand Down