* refactor of Contact/Client out_path_len (stored in files), from signed to unsigned byte (+2 squashed commits)

Squashed commits:
[f326e25] * misc
[fa5152e] * new 'path mode' parsing in Dispatcher
This commit is contained in:
Scott Powell
2026-02-19 14:37:51 +11:00
parent bbc5f0c11a
commit 3e76161e9c
18 changed files with 222 additions and 167 deletions

View File

@@ -258,11 +258,11 @@ int MyMesh::calcRxDelay(float score, uint32_t air_time) const {
} }
uint32_t MyMesh::getRetransmitDelay(const mesh::Packet *packet) { uint32_t MyMesh::getRetransmitDelay(const mesh::Packet *packet) {
uint32_t t = (_radio->getEstAirtimeFor(packet->path_len + packet->payload_len + 2) * 0.5f); uint32_t t = (_radio->getEstAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2) * 0.5f);
return getRNG()->nextInt(0, 5*t + 1); return getRNG()->nextInt(0, 5*t + 1);
} }
uint32_t MyMesh::getDirectRetransmitDelay(const mesh::Packet *packet) { uint32_t MyMesh::getDirectRetransmitDelay(const mesh::Packet *packet) {
uint32_t t = (_radio->getEstAirtimeFor(packet->path_len + packet->payload_len + 2) * 0.2f); uint32_t t = (_radio->getEstAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2) * 0.2f);
return getRNG()->nextInt(0, 5*t + 1); return getRNG()->nextInt(0, 5*t + 1);
} }
@@ -678,7 +678,7 @@ void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data,
} }
} }
bool MyMesh::onContactPathRecv(ContactInfo& contact, 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) { bool MyMesh::onContactPathRecv(ContactInfo& contact, 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) {
if (extra_type == PAYLOAD_TYPE_RESPONSE && extra_len > 4) { if (extra_type == PAYLOAD_TYPE_RESPONSE && extra_len > 4) {
uint32_t tag; uint32_t tag;
memcpy(&tag, extra, 4); memcpy(&tag, extra, 4);
@@ -785,9 +785,10 @@ uint32_t MyMesh::calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const {
return SEND_TIMEOUT_BASE_MILLIS + (FLOOD_SEND_TIMEOUT_FACTOR * pkt_airtime_millis); return SEND_TIMEOUT_BASE_MILLIS + (FLOOD_SEND_TIMEOUT_FACTOR * pkt_airtime_millis);
} }
uint32_t MyMesh::calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const { uint32_t MyMesh::calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const {
uint8_t path_hash_count = path_len & 63;
return SEND_TIMEOUT_BASE_MILLIS + return SEND_TIMEOUT_BASE_MILLIS +
((pkt_airtime_millis * DIRECT_SEND_PERHOP_FACTOR + DIRECT_SEND_PERHOP_EXTRA_MILLIS) * ((pkt_airtime_millis * DIRECT_SEND_PERHOP_FACTOR + DIRECT_SEND_PERHOP_EXTRA_MILLIS) *
(path_len + 1)); (path_hash_count + 1));
} }
void MyMesh::onSendTimeout() {} void MyMesh::onSendTimeout() {}
@@ -1115,7 +1116,7 @@ void MyMesh::handleCmdFrame(size_t len) {
} }
if (pkt) { if (pkt) {
if (len >= 2 && cmd_frame[1] == 1) { // optional param (1 = flood, 0 = zero hop) if (len >= 2 && cmd_frame[1] == 1) { // optional param (1 = flood, 0 = zero hop)
sendFlood(pkt); sendFlood(pkt); // TODO: which path_hash_size to use??
} else { } else {
sendZeroHop(pkt); sendZeroHop(pkt);
} }
@@ -1127,7 +1128,7 @@ void MyMesh::handleCmdFrame(size_t len) {
uint8_t *pub_key = &cmd_frame[1]; uint8_t *pub_key = &cmd_frame[1];
ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE);
if (recipient) { if (recipient) {
recipient->out_path_len = -1; recipient->out_path_len = OUT_PATH_UNKNOWN;
// recipient->lastmod = ?? shouldn't be needed, app already has this version of contact // recipient->lastmod = ?? shouldn't be needed, app already has this version of contact
dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY);
writeOKFrame(); writeOKFrame();
@@ -1449,7 +1450,7 @@ void MyMesh::handleCmdFrame(size_t len) {
memset(&req_data[2], 0, 3); // reserved memset(&req_data[2], 0, 3); // reserved
getRNG()->random(&req_data[5], 4); // random blob to help make packet-hash unique getRNG()->random(&req_data[5], 4); // random blob to help make packet-hash unique
auto save = recipient->out_path_len; // temporarily force sendRequest() to flood auto save = recipient->out_path_len; // temporarily force sendRequest() to flood
recipient->out_path_len = -1; recipient->out_path_len = OUT_PATH_UNKNOWN;
int result = sendRequest(*recipient, req_data, sizeof(req_data), tag, est_timeout); int result = sendRequest(*recipient, req_data, sizeof(req_data), tag, est_timeout);
recipient->out_path_len = save; recipient->out_path_len = save;
if (result == MSG_SEND_FAILED) { if (result == MSG_SEND_FAILED) {

View File

@@ -129,7 +129,7 @@ uint8_t MyMesh::handleLoginReq(const mesh::Identity& sender, const uint8_t* secr
} }
if (is_flood) { if (is_flood) {
client->out_path_len = -1; // need to rediscover out_path client->out_path_len = OUT_PATH_UNKNOWN; // need to rediscover out_path
} }
uint32_t now = getRTCClock()->getCurrentTimeUnique(); uint32_t now = getRTCClock()->getCurrentTimeUnique();
@@ -147,9 +147,12 @@ uint8_t MyMesh::handleLoginReq(const mesh::Identity& sender, const uint8_t* secr
uint8_t MyMesh::handleAnonRegionsReq(const mesh::Identity& sender, uint32_t sender_timestamp, const uint8_t* data) { uint8_t MyMesh::handleAnonRegionsReq(const mesh::Identity& sender, uint32_t sender_timestamp, const uint8_t* data) {
if (anon_limiter.allow(rtc_clock.getCurrentTime())) { if (anon_limiter.allow(rtc_clock.getCurrentTime())) {
// request data has: {reply-path-len}{reply-path} // request data has: {reply-path-len}{reply-path}
reply_path_len = *data++ & 0x3F; reply_path_len = *data & 63;
memcpy(reply_path, data, reply_path_len); reply_path_hash_size = (*data >> 6) + 1;
// data += reply_path_len; data++;
memcpy(reply_path, data, ((uint8_t)reply_path_len) * reply_path_hash_size);
// data += (uint8_t)reply_path_len * reply_path_hash_size;
memcpy(reply_data, &sender_timestamp, 4); // prefix with sender_timestamp, like a tag memcpy(reply_data, &sender_timestamp, 4); // prefix with sender_timestamp, like a tag
uint32_t now = getRTCClock()->getCurrentTime(); uint32_t now = getRTCClock()->getCurrentTime();
@@ -163,9 +166,12 @@ uint8_t MyMesh::handleAnonRegionsReq(const mesh::Identity& sender, uint32_t send
uint8_t MyMesh::handleAnonOwnerReq(const mesh::Identity& sender, uint32_t sender_timestamp, const uint8_t* data) { uint8_t MyMesh::handleAnonOwnerReq(const mesh::Identity& sender, uint32_t sender_timestamp, const uint8_t* data) {
if (anon_limiter.allow(rtc_clock.getCurrentTime())) { if (anon_limiter.allow(rtc_clock.getCurrentTime())) {
// request data has: {reply-path-len}{reply-path} // request data has: {reply-path-len}{reply-path}
reply_path_len = *data++ & 0x3F; reply_path_len = *data & 63;
memcpy(reply_path, data, reply_path_len); reply_path_hash_size = (*data >> 6) + 1;
// data += reply_path_len; data++;
memcpy(reply_path, data, ((uint8_t)reply_path_len) * reply_path_hash_size);
// data += (uint8_t)reply_path_len * reply_path_hash_size;
memcpy(reply_data, &sender_timestamp, 4); // prefix with sender_timestamp, like a tag memcpy(reply_data, &sender_timestamp, 4); // prefix with sender_timestamp, like a tag
uint32_t now = getRTCClock()->getCurrentTime(); uint32_t now = getRTCClock()->getCurrentTime();
@@ -180,9 +186,12 @@ uint8_t MyMesh::handleAnonOwnerReq(const mesh::Identity& sender, uint32_t sender
uint8_t MyMesh::handleAnonClockReq(const mesh::Identity& sender, uint32_t sender_timestamp, const uint8_t* data) { uint8_t MyMesh::handleAnonClockReq(const mesh::Identity& sender, uint32_t sender_timestamp, const uint8_t* data) {
if (anon_limiter.allow(rtc_clock.getCurrentTime())) { if (anon_limiter.allow(rtc_clock.getCurrentTime())) {
// request data has: {reply-path-len}{reply-path} // request data has: {reply-path-len}{reply-path}
reply_path_len = *data++ & 0x3F; reply_path_len = *data & 63;
memcpy(reply_path, data, reply_path_len); reply_path_hash_size = (*data >> 6) + 1;
// data += reply_path_len; data++;
memcpy(reply_path, data, ((uint8_t)reply_path_len) * reply_path_hash_size);
// data += (uint8_t)reply_path_len * reply_path_hash_size;
memcpy(reply_data, &sender_timestamp, 4); // prefix with sender_timestamp, like a tag memcpy(reply_data, &sender_timestamp, 4); // prefix with sender_timestamp, like a tag
uint32_t now = getRTCClock()->getCurrentTime(); uint32_t now = getRTCClock()->getCurrentTime();
@@ -389,7 +398,7 @@ File MyMesh::openAppend(const char *fname) {
bool MyMesh::allowPacketForward(const mesh::Packet *packet) { bool MyMesh::allowPacketForward(const mesh::Packet *packet) {
if (_prefs.disable_fwd) return false; if (_prefs.disable_fwd) return false;
if (packet->isRouteFlood() && packet->path_len >= _prefs.flood_max) return false; if (packet->isRouteFlood() && packet->getPathHashCount() >= _prefs.flood_max) return false;
if (packet->isRouteFlood() && recv_pkt_region == NULL) { if (packet->isRouteFlood() && recv_pkt_region == NULL) {
MESH_DEBUG_PRINTLN("allowPacketForward: unknown transport code, or wildcard not allowed for FLOOD packet"); MESH_DEBUG_PRINTLN("allowPacketForward: unknown transport code, or wildcard not allowed for FLOOD packet");
return false; return false;
@@ -484,11 +493,11 @@ int MyMesh::calcRxDelay(float score, uint32_t air_time) const {
} }
uint32_t MyMesh::getRetransmitDelay(const mesh::Packet *packet) { uint32_t MyMesh::getRetransmitDelay(const mesh::Packet *packet) {
uint32_t t = (_radio->getEstAirtimeFor(packet->path_len + packet->payload_len + 2) * _prefs.tx_delay_factor); uint32_t t = (_radio->getEstAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2) * _prefs.tx_delay_factor);
return getRNG()->nextInt(0, 5*t + 1); return getRNG()->nextInt(0, 5*t + 1);
} }
uint32_t MyMesh::getDirectRetransmitDelay(const mesh::Packet *packet) { uint32_t MyMesh::getDirectRetransmitDelay(const mesh::Packet *packet) {
uint32_t t = (_radio->getEstAirtimeFor(packet->path_len + packet->payload_len + 2) * _prefs.direct_tx_delay_factor); uint32_t t = (_radio->getEstAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2) * _prefs.direct_tx_delay_factor);
return getRNG()->nextInt(0, 5*t + 1); return getRNG()->nextInt(0, 5*t + 1);
} }
@@ -538,13 +547,14 @@ void MyMesh::onAnonDataRecv(mesh::Packet *packet, const uint8_t *secret, const m
// let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response // let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
mesh::Packet* path = createPathReturn(sender, secret, packet->path, packet->path_len, mesh::Packet* path = createPathReturn(sender, secret, packet->path, packet->path_len,
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len); PAYLOAD_TYPE_RESPONSE, reply_data, reply_len);
if (path) sendFlood(path, SERVER_RESPONSE_DELAY); if (path) sendFlood(path, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
} else if (reply_path_len < 0) { } else if (reply_path_len < 0) {
mesh::Packet* reply = createDatagram(PAYLOAD_TYPE_RESPONSE, sender, secret, reply_data, reply_len); mesh::Packet* reply = createDatagram(PAYLOAD_TYPE_RESPONSE, sender, secret, reply_data, reply_len);
if (reply) sendFlood(reply, SERVER_RESPONSE_DELAY); if (reply) sendFlood(reply, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
} else { } else {
mesh::Packet* reply = createDatagram(PAYLOAD_TYPE_RESPONSE, sender, secret, reply_data, reply_len); mesh::Packet* reply = createDatagram(PAYLOAD_TYPE_RESPONSE, sender, secret, reply_data, reply_len);
if (reply) sendDirect(reply, reply_path, reply_path_len, SERVER_RESPONSE_DELAY); uint8_t path_len = ((reply_path_hash_size - 1) << 6) | (reply_path_len & 63);
if (reply) sendDirect(reply, reply_path, path_len, SERVER_RESPONSE_DELAY);
} }
} }
} }
@@ -613,15 +623,15 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
// let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response // let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
mesh::Packet *path = createPathReturn(client->id, secret, packet->path, packet->path_len, mesh::Packet *path = createPathReturn(client->id, secret, packet->path, packet->path_len,
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len); PAYLOAD_TYPE_RESPONSE, reply_data, reply_len);
if (path) sendFlood(path, SERVER_RESPONSE_DELAY); if (path) sendFlood(path, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
} else { } else {
mesh::Packet *reply = mesh::Packet *reply =
createDatagram(PAYLOAD_TYPE_RESPONSE, client->id, secret, reply_data, reply_len); createDatagram(PAYLOAD_TYPE_RESPONSE, client->id, secret, reply_data, reply_len);
if (reply) { if (reply) {
if (client->out_path_len >= 0) { // we have an out_path, so send DIRECT if (client->out_path_len != OUT_PATH_UNKNOWN) { // we have an out_path, so send DIRECT
sendDirect(reply, client->out_path, client->out_path_len, SERVER_RESPONSE_DELAY); sendDirect(reply, client->out_path, client->out_path_len, SERVER_RESPONSE_DELAY);
} else { } else {
sendFlood(reply, SERVER_RESPONSE_DELAY); sendFlood(reply, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
} }
} }
} }
@@ -651,8 +661,8 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
mesh::Packet *ack = createAck(ack_hash); mesh::Packet *ack = createAck(ack_hash);
if (ack) { if (ack) {
if (client->out_path_len < 0) { if (client->out_path_len == OUT_PATH_UNKNOWN) {
sendFlood(ack, TXT_ACK_DELAY); sendFlood(ack, TXT_ACK_DELAY, packet->getPathHashSize());
} else { } else {
sendDirect(ack, client->out_path, client->out_path_len, TXT_ACK_DELAY); sendDirect(ack, client->out_path, client->out_path_len, TXT_ACK_DELAY);
} }
@@ -679,8 +689,8 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, secret, temp, 5 + text_len); auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, secret, temp, 5 + text_len);
if (reply) { if (reply) {
if (client->out_path_len < 0) { if (client->out_path_len == OUT_PATH_UNKNOWN) {
sendFlood(reply, CLI_REPLY_DELAY_MILLIS); sendFlood(reply, CLI_REPLY_DELAY_MILLIS, packet->getPathHashSize());
} else { } else {
sendDirect(reply, client->out_path, client->out_path_len, CLI_REPLY_DELAY_MILLIS); sendDirect(reply, client->out_path, client->out_path_len, CLI_REPLY_DELAY_MILLIS);
} }
@@ -701,7 +711,8 @@ bool MyMesh::onPeerPathRecv(mesh::Packet *packet, int sender_idx, const uint8_t
MESH_DEBUG_PRINTLN("PATH to client, path_len=%d", (uint32_t)path_len); MESH_DEBUG_PRINTLN("PATH to client, path_len=%d", (uint32_t)path_len);
auto client = acl.getClientByIdx(i); auto client = acl.getClientByIdx(i);
memcpy(client->out_path, path, client->out_path_len = path_len); // store a copy of path, for sendDirect() // store a copy of path, for sendDirect()
client->out_path_len = mesh::Packet::copyPath(client->out_path, path, path_len);
client->last_activity = getRTCClock()->getCurrentTime(); client->last_activity = getRTCClock()->getCurrentTime();
} else { } else {
MESH_DEBUG_PRINTLN("onPeerPathRecv: invalid peer idx: %d", i); MESH_DEBUG_PRINTLN("onPeerPathRecv: invalid peer idx: %d", i);
@@ -906,7 +917,7 @@ void MyMesh::sendSelfAdvertisement(int delay_millis, bool flood) {
mesh::Packet *pkt = createSelfAdvert(); mesh::Packet *pkt = createSelfAdvert();
if (pkt) { if (pkt) {
if (flood) { if (flood) {
sendFlood(pkt, delay_millis); sendFlood(pkt, delay_millis); // TODO: which path_hash_size to use??
} else { } else {
sendZeroHop(pkt, delay_millis); sendZeroHop(pkt, delay_millis);
} }

View File

@@ -92,6 +92,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
uint8_t reply_data[MAX_PACKET_PAYLOAD]; uint8_t reply_data[MAX_PACKET_PAYLOAD];
uint8_t reply_path[MAX_PATH_SIZE]; uint8_t reply_path[MAX_PATH_SIZE];
int8_t reply_path_len; int8_t reply_path_len;
uint8_t reply_path_hash_size;
TransportKeyStore key_store; TransportKeyStore key_store;
RegionMap region_map, temp_map; RegionMap region_map, temp_map;
RegionEntry* load_stack[8]; RegionEntry* load_stack[8];

View File

@@ -73,13 +73,14 @@ void MyMesh::pushPostToClient(ClientInfo *client, PostInfo &post) {
auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, client->shared_secret, reply_data, len); auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, client->shared_secret, reply_data, len);
if (reply) { if (reply) {
if (client->out_path_len < 0) { if (client->out_path_len == OUT_PATH_UNKNOWN) {
sendFlood(reply); sendFlood(reply); // TODO: which path_hash_size to use?
client->extra.room.ack_timeout = futureMillis(PUSH_ACK_TIMEOUT_FLOOD); client->extra.room.ack_timeout = futureMillis(PUSH_ACK_TIMEOUT_FLOOD);
} else { } else {
sendDirect(reply, client->out_path, client->out_path_len); sendDirect(reply, client->out_path, client->out_path_len);
client->extra.room.ack_timeout =
futureMillis(PUSH_TIMEOUT_BASE + PUSH_ACK_TIMEOUT_FACTOR * (client->out_path_len + 1)); uint8_t path_hash_count = client->out_path_len & 63;
client->extra.room.ack_timeout = futureMillis(PUSH_TIMEOUT_BASE + PUSH_ACK_TIMEOUT_FACTOR * (path_hash_count + 1));
} }
_num_post_pushes++; // stats _num_post_pushes++; // stats
} else { } else {
@@ -264,17 +265,17 @@ const char *MyMesh::getLogDateTime() {
} }
uint32_t MyMesh::getRetransmitDelay(const mesh::Packet *packet) { uint32_t MyMesh::getRetransmitDelay(const mesh::Packet *packet) {
uint32_t t = (_radio->getEstAirtimeFor(packet->path_len + packet->payload_len + 2) * _prefs.tx_delay_factor); uint32_t t = (_radio->getEstAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2) * _prefs.tx_delay_factor);
return getRNG()->nextInt(0, 5*t + 1); return getRNG()->nextInt(0, 5*t + 1);
} }
uint32_t MyMesh::getDirectRetransmitDelay(const mesh::Packet *packet) { uint32_t MyMesh::getDirectRetransmitDelay(const mesh::Packet *packet) {
uint32_t t = (_radio->getEstAirtimeFor(packet->path_len + packet->payload_len + 2) * _prefs.direct_tx_delay_factor); uint32_t t = (_radio->getEstAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2) * _prefs.direct_tx_delay_factor);
return getRNG()->nextInt(0, 5*t + 1); return getRNG()->nextInt(0, 5*t + 1);
} }
bool MyMesh::allowPacketForward(const mesh::Packet *packet) { bool MyMesh::allowPacketForward(const mesh::Packet *packet) {
if (_prefs.disable_fwd) return false; if (_prefs.disable_fwd) return false;
if (packet->isRouteFlood() && packet->path_len >= _prefs.flood_max) return false; if (packet->isRouteFlood() && packet->getPathHashCount() >= _prefs.flood_max) return false;
return true; return true;
} }
@@ -333,7 +334,7 @@ void MyMesh::onAnonDataRecv(mesh::Packet *packet, const uint8_t *secret, const m
} }
if (packet->isRouteFlood()) { if (packet->isRouteFlood()) {
client->out_path_len = -1; // need to rediscover out_path client->out_path_len = OUT_PATH_UNKNOWN; // need to rediscover out_path
} }
uint32_t now = getRTCClock()->getCurrentTimeUnique(); uint32_t now = getRTCClock()->getCurrentTimeUnique();
@@ -353,14 +354,14 @@ void MyMesh::onAnonDataRecv(mesh::Packet *packet, const uint8_t *secret, const m
// let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response // let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
mesh::Packet *path = createPathReturn(sender, client->shared_secret, packet->path, packet->path_len, mesh::Packet *path = createPathReturn(sender, client->shared_secret, packet->path, packet->path_len,
PAYLOAD_TYPE_RESPONSE, reply_data, 13); PAYLOAD_TYPE_RESPONSE, reply_data, 13);
if (path) sendFlood(path, SERVER_RESPONSE_DELAY); if (path) sendFlood(path, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
} else { } else {
mesh::Packet *reply = createDatagram(PAYLOAD_TYPE_RESPONSE, sender, client->shared_secret, reply_data, 13); mesh::Packet *reply = createDatagram(PAYLOAD_TYPE_RESPONSE, sender, client->shared_secret, reply_data, 13);
if (reply) { if (reply) {
if (client->out_path_len >= 0) { // we have an out_path, so send DIRECT if (client->out_path_len != OUT_PATH_UNKNOWN) { // we have an out_path, so send DIRECT
sendDirect(reply, client->out_path, client->out_path_len, SERVER_RESPONSE_DELAY); sendDirect(reply, client->out_path, client->out_path_len, SERVER_RESPONSE_DELAY);
} else { } else {
sendFlood(reply, SERVER_RESPONSE_DELAY); sendFlood(reply, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
} }
} }
} }
@@ -448,9 +449,9 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
uint32_t delay_millis; uint32_t delay_millis;
if (send_ack) { if (send_ack) {
if (client->out_path_len < 0) { if (client->out_path_len == OUT_PATH_UNKNOWN) {
mesh::Packet *ack = createAck(ack_hash); mesh::Packet *ack = createAck(ack_hash);
if (ack) sendFlood(ack, TXT_ACK_DELAY); if (ack) sendFlood(ack, TXT_ACK_DELAY, packet->getPathHashSize());
delay_millis = TXT_ACK_DELAY + REPLY_DELAY_MILLIS; delay_millis = TXT_ACK_DELAY + REPLY_DELAY_MILLIS;
} else { } else {
uint32_t d = TXT_ACK_DELAY; uint32_t d = TXT_ACK_DELAY;
@@ -482,8 +483,8 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, secret, temp, 5 + text_len); auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, secret, temp, 5 + text_len);
if (reply) { if (reply) {
if (client->out_path_len < 0) { if (client->out_path_len == OUT_PATH_UNKNOWN) {
sendFlood(reply, delay_millis + SERVER_RESPONSE_DELAY); sendFlood(reply, delay_millis + SERVER_RESPONSE_DELAY, packet->getPathHashSize());
} else { } else {
sendDirect(reply, client->out_path, client->out_path_len, delay_millis + SERVER_RESPONSE_DELAY); sendDirect(reply, client->out_path, client->out_path_len, delay_millis + SERVER_RESPONSE_DELAY);
} }
@@ -521,7 +522,7 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
// if client sends too quickly, evict() // if client sends too quickly, evict()
// RULE: only send keep_alive response DIRECT! // RULE: only send keep_alive response DIRECT!
if (client->out_path_len >= 0) { if (client->out_path_len != OUT_PATH_UNKNOWN) {
uint32_t ack_hash; // calc ACK to prove to sender that we got request uint32_t ack_hash; // calc ACK to prove to sender that we got request
mesh::Utils::sha256((uint8_t *)&ack_hash, 4, data, 9, client->id.pub_key, PUB_KEY_SIZE); mesh::Utils::sha256((uint8_t *)&ack_hash, 4, data, 9, client->id.pub_key, PUB_KEY_SIZE);
@@ -538,14 +539,14 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
// let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response // let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
mesh::Packet *path = createPathReturn(client->id, secret, packet->path, packet->path_len, mesh::Packet *path = createPathReturn(client->id, secret, packet->path, packet->path_len,
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len); PAYLOAD_TYPE_RESPONSE, reply_data, reply_len);
if (path) sendFlood(path, SERVER_RESPONSE_DELAY); if (path) sendFlood(path, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
} else { } else {
mesh::Packet *reply = createDatagram(PAYLOAD_TYPE_RESPONSE, client->id, secret, reply_data, reply_len); mesh::Packet *reply = createDatagram(PAYLOAD_TYPE_RESPONSE, client->id, secret, reply_data, reply_len);
if (reply) { if (reply) {
if (client->out_path_len >= 0) { // we have an out_path, so send DIRECT if (client->out_path_len != OUT_PATH_UNKNOWN) { // we have an out_path, so send DIRECT
sendDirect(reply, client->out_path, client->out_path_len, SERVER_RESPONSE_DELAY); sendDirect(reply, client->out_path, client->out_path_len, SERVER_RESPONSE_DELAY);
} else { } else {
sendFlood(reply, SERVER_RESPONSE_DELAY); sendFlood(reply, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
} }
} }
} }
@@ -563,7 +564,7 @@ bool MyMesh::onPeerPathRecv(mesh::Packet *packet, int sender_idx, const uint8_t
if (i >= 0 && i < acl.getNumClients()) { // get from our known_clients table (sender SHOULD already be known in this context) if (i >= 0 && i < acl.getNumClients()) { // get from our known_clients table (sender SHOULD already be known in this context)
MESH_DEBUG_PRINTLN("PATH to client, path_len=%d", (uint32_t)path_len); MESH_DEBUG_PRINTLN("PATH to client, path_len=%d", (uint32_t)path_len);
auto client = acl.getClientByIdx(i); auto client = acl.getClientByIdx(i);
memcpy(client->out_path, path, client->out_path_len = path_len); // store a copy of path, for sendDirect() client->out_path_len = mesh::Packet::copyPath(client->out_path, path, path_len); // store a copy of path, for sendDirect()
client->last_activity = getRTCClock()->getCurrentTime(); client->last_activity = getRTCClock()->getCurrentTime();
} else { } else {
MESH_DEBUG_PRINTLN("onPeerPathRecv: invalid peer idx: %d", i); MESH_DEBUG_PRINTLN("onPeerPathRecv: invalid peer idx: %d", i);
@@ -679,7 +680,7 @@ void MyMesh::sendSelfAdvertisement(int delay_millis, bool flood) {
mesh::Packet *pkt = createSelfAdvert(); mesh::Packet *pkt = createSelfAdvert();
if (pkt) { if (pkt) {
if (flood) { if (flood) {
sendFlood(pkt, delay_millis); sendFlood(pkt, delay_millis); // TODO: which path_hash_size to use?
} else { } else {
sendZeroHop(pkt, delay_millis); sendZeroHop(pkt, delay_millis);
} }

View File

@@ -213,7 +213,7 @@ protected:
} }
void onContactPathUpdated(const ContactInfo& contact) override { void onContactPathUpdated(const ContactInfo& contact) override {
Serial.printf("PATH to: %s, path_len=%d\n", contact.name, (int32_t) contact.out_path_len); Serial.printf("PATH to: %s, path_len=%d\n", contact.name, (uint32_t) contact.out_path_len);
saveContacts(); saveContacts();
} }
@@ -266,8 +266,9 @@ protected:
return SEND_TIMEOUT_BASE_MILLIS + (FLOOD_SEND_TIMEOUT_FACTOR * pkt_airtime_millis); return SEND_TIMEOUT_BASE_MILLIS + (FLOOD_SEND_TIMEOUT_FACTOR * pkt_airtime_millis);
} }
uint32_t calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const override { uint32_t calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const override {
uint8_t path_hash_count = path_len & 63;
return SEND_TIMEOUT_BASE_MILLIS + return SEND_TIMEOUT_BASE_MILLIS +
( (pkt_airtime_millis*DIRECT_SEND_PERHOP_FACTOR + DIRECT_SEND_PERHOP_EXTRA_MILLIS) * (path_len + 1)); ( (pkt_airtime_millis*DIRECT_SEND_PERHOP_FACTOR + DIRECT_SEND_PERHOP_EXTRA_MILLIS) * (path_hash_count + 1));
} }
void onSendTimeout() override { void onSendTimeout() override {

View File

@@ -258,7 +258,7 @@ void SensorMesh::sendAlert(const ClientInfo* c, Trigger* t) {
auto pkt = createDatagram(PAYLOAD_TYPE_TXT_MSG, c->id, c->shared_secret, data, 5 + text_len); auto pkt = createDatagram(PAYLOAD_TYPE_TXT_MSG, c->id, c->shared_secret, data, 5 + text_len);
if (pkt) { if (pkt) {
if (c->out_path_len >= 0) { // we have an out_path, so send DIRECT if (c->out_path_len != OUT_PATH_UNKNOWN) { // we have an out_path, so send DIRECT
sendDirect(pkt, c->out_path, c->out_path_len); sendDirect(pkt, c->out_path, c->out_path_len);
} else { } else {
sendFlood(pkt); sendFlood(pkt);
@@ -302,7 +302,7 @@ float SensorMesh::getAirtimeBudgetFactor() const {
bool SensorMesh::allowPacketForward(const mesh::Packet* packet) { bool SensorMesh::allowPacketForward(const mesh::Packet* packet) {
if (_prefs.disable_fwd) return false; if (_prefs.disable_fwd) return false;
if (packet->isRouteFlood() && packet->path_len >= _prefs.flood_max) return false; if (packet->isRouteFlood() && packet->getPathHashCount() >= _prefs.flood_max) return false;
return true; return true;
} }
@@ -312,11 +312,11 @@ int SensorMesh::calcRxDelay(float score, uint32_t air_time) const {
} }
uint32_t SensorMesh::getRetransmitDelay(const mesh::Packet* packet) { uint32_t SensorMesh::getRetransmitDelay(const mesh::Packet* packet) {
uint32_t t = (_radio->getEstAirtimeFor(packet->path_len + packet->payload_len + 2) * _prefs.tx_delay_factor); uint32_t t = (_radio->getEstAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2) * _prefs.tx_delay_factor);
return getRNG()->nextInt(0, 6)*t; return getRNG()->nextInt(0, 6)*t;
} }
uint32_t SensorMesh::getDirectRetransmitDelay(const mesh::Packet* packet) { uint32_t SensorMesh::getDirectRetransmitDelay(const mesh::Packet* packet) {
uint32_t t = (_radio->getEstAirtimeFor(packet->path_len + packet->payload_len + 2) * _prefs.direct_tx_delay_factor); uint32_t t = (_radio->getEstAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2) * _prefs.direct_tx_delay_factor);
return getRNG()->nextInt(0, 6)*t; return getRNG()->nextInt(0, 6)*t;
} }
int SensorMesh::getInterferenceThreshold() const { int SensorMesh::getInterferenceThreshold() const {
@@ -360,7 +360,7 @@ uint8_t SensorMesh::handleLoginReq(const mesh::Identity& sender, const uint8_t*
} }
if (is_flood) { if (is_flood) {
client->out_path_len = -1; // need to rediscover out_path client->out_path_len = OUT_PATH_UNKNOWN; // need to rediscover out_path
} }
uint32_t now = getRTCClock()->getCurrentTimeUnique(); uint32_t now = getRTCClock()->getCurrentTimeUnique();
@@ -468,10 +468,10 @@ void SensorMesh::onAnonDataRecv(mesh::Packet* packet, const uint8_t* secret, con
// let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response // let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
mesh::Packet* path = createPathReturn(sender, secret, packet->path, packet->path_len, mesh::Packet* path = createPathReturn(sender, secret, packet->path, packet->path_len,
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len); PAYLOAD_TYPE_RESPONSE, reply_data, reply_len);
if (path) sendFlood(path, SERVER_RESPONSE_DELAY); if (path) sendFlood(path, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
} else { } else {
mesh::Packet* reply = createDatagram(PAYLOAD_TYPE_RESPONSE, sender, secret, reply_data, reply_len); mesh::Packet* reply = createDatagram(PAYLOAD_TYPE_RESPONSE, sender, secret, reply_data, reply_len);
if (reply) sendFlood(reply, SERVER_RESPONSE_DELAY); if (reply) sendFlood(reply, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
} }
} }
} }
@@ -496,10 +496,10 @@ void SensorMesh::getPeerSharedSecret(uint8_t* dest_secret, int peer_idx) {
} }
} }
void SensorMesh::sendAckTo(const ClientInfo& dest, uint32_t ack_hash) { void SensorMesh::sendAckTo(const ClientInfo& dest, uint32_t ack_hash, uint8_t path_hash_size) {
if (dest.out_path_len < 0) { if (dest.out_path_len == OUT_PATH_UNKNOWN) {
mesh::Packet* ack = createAck(ack_hash); mesh::Packet* ack = createAck(ack_hash);
if (ack) sendFlood(ack, TXT_ACK_DELAY); if (ack) sendFlood(ack, TXT_ACK_DELAY, path_hash_size);
} else { } else {
uint32_t d = TXT_ACK_DELAY; uint32_t d = TXT_ACK_DELAY;
if (getExtraAckTransmitCount() > 0) { if (getExtraAckTransmitCount() > 0) {
@@ -537,14 +537,14 @@ void SensorMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_i
// let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response // let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
mesh::Packet* path = createPathReturn(from->id, secret, packet->path, packet->path_len, mesh::Packet* path = createPathReturn(from->id, secret, packet->path, packet->path_len,
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len); PAYLOAD_TYPE_RESPONSE, reply_data, reply_len);
if (path) sendFlood(path, SERVER_RESPONSE_DELAY); if (path) sendFlood(path, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
} else { } else {
mesh::Packet* reply = createDatagram(PAYLOAD_TYPE_RESPONSE, from->id, secret, reply_data, reply_len); mesh::Packet* reply = createDatagram(PAYLOAD_TYPE_RESPONSE, from->id, secret, reply_data, reply_len);
if (reply) { if (reply) {
if (from->out_path_len >= 0) { // we have an out_path, so send DIRECT if (from->out_path_len != OUT_PATH_UNKNOWN) { // we have an out_path, so send DIRECT
sendDirect(reply, from->out_path, from->out_path_len, SERVER_RESPONSE_DELAY); sendDirect(reply, from->out_path, from->out_path_len, SERVER_RESPONSE_DELAY);
} else { } else {
sendFlood(reply, SERVER_RESPONSE_DELAY); sendFlood(reply, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
} }
} }
} }
@@ -569,7 +569,7 @@ void SensorMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_i
PAYLOAD_TYPE_ACK, (uint8_t *) &ack_hash, 4); PAYLOAD_TYPE_ACK, (uint8_t *) &ack_hash, 4);
if (path) sendFlood(path, TXT_ACK_DELAY); if (path) sendFlood(path, TXT_ACK_DELAY);
} else { } else {
sendAckTo(*from, ack_hash); sendAckTo(*from, ack_hash, packet->getPathHashSize());
} }
} }
} else if (flags == TXT_TYPE_CLI_DATA) { } else if (flags == TXT_TYPE_CLI_DATA) {
@@ -596,8 +596,8 @@ void SensorMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_i
auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, from->id, secret, temp, 5 + text_len); auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, from->id, secret, temp, 5 + text_len);
if (reply) { if (reply) {
if (from->out_path_len < 0) { if (from->out_path_len == OUT_PATH_UNKNOWN) {
sendFlood(reply, CLI_REPLY_DELAY_MILLIS); sendFlood(reply, CLI_REPLY_DELAY_MILLIS, packet->getPathHashSize());
} else { } else {
sendDirect(reply, from->out_path, from->out_path_len, CLI_REPLY_DELAY_MILLIS); sendDirect(reply, from->out_path, from->out_path_len, CLI_REPLY_DELAY_MILLIS);
} }
@@ -666,7 +666,7 @@ bool SensorMesh::onPeerPathRecv(mesh::Packet* packet, int sender_idx, const uint
MESH_DEBUG_PRINTLN("PATH to contact, path_len=%d", (uint32_t) path_len); MESH_DEBUG_PRINTLN("PATH to contact, path_len=%d", (uint32_t) path_len);
// NOTE: for this impl, we just replace the current 'out_path' regardless, whenever sender sends us a new out_path. // NOTE: for this impl, we just replace the current 'out_path' regardless, whenever sender sends us a new out_path.
// FUTURE: could store multiple out_paths per contact, and try to find which is the 'best'(?) // FUTURE: could store multiple out_paths per contact, and try to find which is the 'best'(?)
memcpy(from->out_path, path, from->out_path_len = path_len); // store a copy of path, for sendDirect() from->out_path_len = mesh::Packet::copyPath(from->out_path, path, path_len); // store a copy of path, for sendDirect()
from->last_activity = getRTCClock()->getCurrentTime(); from->last_activity = getRTCClock()->getCurrentTime();
// REVISIT: maybe make ALL out_paths non-persisted to minimise flash writes?? // REVISIT: maybe make ALL out_paths non-persisted to minimise flash writes??

View File

@@ -128,7 +128,7 @@ protected:
void onControlDataRecv(mesh::Packet* packet) override; void onControlDataRecv(mesh::Packet* packet) override;
void onAckRecv(mesh::Packet* packet, uint32_t ack_crc) override; void onAckRecv(mesh::Packet* packet, uint32_t ack_crc) override;
virtual bool handleIncomingMsg(ClientInfo& from, uint32_t timestamp, uint8_t* data, uint8_t flags, size_t len); virtual bool handleIncomingMsg(ClientInfo& from, uint32_t timestamp, uint8_t* data, uint8_t flags, size_t len);
void sendAckTo(const ClientInfo& dest, uint32_t ack_hash); void sendAckTo(const ClientInfo& dest, uint32_t ack_hash, uint8_t path_hash_size=1);
private: private:
FILESYSTEM* _fs; FILESYSTEM* _fs;
unsigned long next_local_advert, next_flood_advert; unsigned long next_local_advert, next_flood_advert;

View File

@@ -108,6 +108,48 @@ void Dispatcher::loop() {
checkSend(); checkSend();
} }
bool Dispatcher::tryParsePacket(Packet* pkt, const uint8_t* raw, int len) {
int i = 0;
pkt->header = raw[i++];
if (pkt->getPayloadVer() > PAYLOAD_VER_1) {
MESH_DEBUG_PRINTLN("%s Dispatcher::checkRecv(): unsupported packet version", getLogDateTime());
return false;
}
if (pkt->hasTransportCodes()) {
memcpy(&pkt->transport_codes[0], &raw[i], 2); i += 2;
memcpy(&pkt->transport_codes[1], &raw[i], 2); i += 2;
} else {
pkt->transport_codes[0] = pkt->transport_codes[1] = 0;
}
pkt->path_len = raw[i++];
uint8_t path_mode = pkt->path_len >> 6; // upper 2 bits (legacy firmware: 00)
if (path_mode == 3) { // Reserved for future
MESH_DEBUG_PRINTLN("%s Dispatcher::checkRecv(): unsupported path mode: 3", getLogDateTime());
return false;
}
uint8_t path_byte_len = (pkt->path_len & 63) * pkt->getPathHashSize();
if (path_byte_len > MAX_PATH_SIZE || i + path_byte_len > len) {
MESH_DEBUG_PRINTLN("%s Dispatcher::checkRecv(): partial or corrupt packet received, len=%d", getLogDateTime(), len);
return false;
}
memcpy(pkt->path, &raw[i], path_byte_len); i += path_byte_len;
pkt->payload_len = len - i; // payload is remainder
if (pkt->payload_len > sizeof(pkt->payload)) {
MESH_DEBUG_PRINTLN("%s Dispatcher::checkRecv(): packet payload too big, payload_len=%d", getLogDateTime(), (uint32_t)pkt->payload_len);
return false;
}
memcpy(pkt->payload, &raw[i], pkt->payload_len);
return true; // success
}
void Dispatcher::checkRecv() { void Dispatcher::checkRecv() {
Packet* pkt; Packet* pkt;
float score; float score;
@@ -122,45 +164,14 @@ void Dispatcher::checkRecv() {
if (pkt == NULL) { if (pkt == NULL) {
MESH_DEBUG_PRINTLN("%s Dispatcher::checkRecv(): WARNING: received data, no unused packets available!", getLogDateTime()); MESH_DEBUG_PRINTLN("%s Dispatcher::checkRecv(): WARNING: received data, no unused packets available!", getLogDateTime());
} else { } else {
int i = 0; if (tryParsePacket(pkt, raw, len)) {
#ifdef NODE_ID pkt->_snr = _radio->getLastSNR() * 4.0f;
uint8_t sender_id = raw[i++]; score = _radio->packetScore(_radio->getLastSNR(), len);
if (sender_id == NODE_ID - 1 || sender_id == NODE_ID + 1) { // simulate that NODE_ID can only hear NODE_ID-1 or NODE_ID+1, eg. 3 can't hear 1 air_time = _radio->getEstAirtimeFor(len);
rx_air_time += air_time;
} else { } else {
_mgr->free(pkt); // put back into pool
return;
}
#endif
pkt->header = raw[i++];
if (pkt->hasTransportCodes()) {
memcpy(&pkt->transport_codes[0], &raw[i], 2); i += 2;
memcpy(&pkt->transport_codes[1], &raw[i], 2); i += 2;
} else {
pkt->transport_codes[0] = pkt->transport_codes[1] = 0;
}
pkt->path_len = raw[i++];
if (pkt->path_len > MAX_PATH_SIZE || i + pkt->path_len > len) {
MESH_DEBUG_PRINTLN("%s Dispatcher::checkRecv(): partial or corrupt packet received, len=%d", getLogDateTime(), len);
_mgr->free(pkt); // put back into pool _mgr->free(pkt); // put back into pool
pkt = NULL; pkt = NULL;
} else {
memcpy(pkt->path, &raw[i], pkt->path_len); i += pkt->path_len;
pkt->payload_len = len - i; // payload is remainder
if (pkt->payload_len > sizeof(pkt->payload)) {
MESH_DEBUG_PRINTLN("%s Dispatcher::checkRecv(): packet payload too big, payload_len=%d", getLogDateTime(), (uint32_t)pkt->payload_len);
_mgr->free(pkt); // put back into pool
pkt = NULL;
} else {
memcpy(pkt->payload, &raw[i], pkt->payload_len);
pkt->_snr = _radio->getLastSNR() * 4.0f;
score = _radio->packetScore(_radio->getLastSNR(), len);
air_time = _radio->getEstAirtimeFor(len);
rx_air_time += air_time;
}
} }
} }
} else { } else {
@@ -249,9 +260,6 @@ void Dispatcher::checkSend() {
int len = 0; int len = 0;
uint8_t raw[MAX_TRANS_UNIT]; uint8_t raw[MAX_TRANS_UNIT];
#ifdef NODE_ID
raw[len++] = NODE_ID;
#endif
raw[len++] = outbound->header; raw[len++] = outbound->header;
if (outbound->hasTransportCodes()) { if (outbound->hasTransportCodes()) {
memcpy(&raw[len], &outbound->transport_codes[0], 2); len += 2; memcpy(&raw[len], &outbound->transport_codes[0], 2); len += 2;

View File

@@ -184,6 +184,7 @@ public:
unsigned long futureMillis(int millis_from_now) const; unsigned long futureMillis(int millis_from_now) const;
private: private:
bool tryParsePacket(Packet* pkt, const uint8_t* raw, int len);
void checkRecv(); void checkRecv();
void checkSend(); void checkSend();
}; };

View File

@@ -20,6 +20,10 @@ public:
memcpy(dest, pub_key, PATH_HASH_SIZE); // hash is just prefix of pub_key memcpy(dest, pub_key, PATH_HASH_SIZE); // hash is just prefix of pub_key
return PATH_HASH_SIZE; return PATH_HASH_SIZE;
} }
int copyHashTo(uint8_t* dest, uint8_t len) const {
memcpy(dest, pub_key, len); // hash is just prefix of pub_key
return len;
}
bool isHashMatch(const uint8_t* hash) const { bool isHashMatch(const uint8_t* hash) const {
return memcmp(hash, pub_key, PATH_HASH_SIZE) == 0; return memcmp(hash, pub_key, PATH_HASH_SIZE) == 0;
} }

View File

@@ -39,11 +39,6 @@ int Mesh::searchChannelsByHash(const uint8_t* hash, GroupChannel channels[], int
} }
DispatcherAction Mesh::onRecvPacket(Packet* pkt) { DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
if (pkt->getPayloadVer() > PAYLOAD_VER_1) { // not supported in this firmware version
MESH_DEBUG_PRINTLN("%s Mesh::onRecvPacket(): unsupported packet version", getLogDateTime());
return ACTION_RELEASE;
}
if (pkt->isRouteDirect() && pkt->getPayloadType() == PAYLOAD_TYPE_TRACE) { if (pkt->isRouteDirect() && pkt->getPayloadType() == PAYLOAD_TYPE_TRACE) {
if (pkt->path_len < MAX_PATH_SIZE) { if (pkt->path_len < MAX_PATH_SIZE) {
uint8_t i = 0; uint8_t i = 0;
@@ -70,14 +65,14 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
} }
if (pkt->isRouteDirect() && pkt->getPayloadType() == PAYLOAD_TYPE_CONTROL && (pkt->payload[0] & 0x80) != 0) { if (pkt->isRouteDirect() && pkt->getPayloadType() == PAYLOAD_TYPE_CONTROL && (pkt->payload[0] & 0x80) != 0) {
if (pkt->path_len == 0) { if (pkt->getPathHashCount() == 0) {
onControlDataRecv(pkt); onControlDataRecv(pkt);
} }
// just zero-hop control packets allowed (for this subset of payloads) // just zero-hop control packets allowed (for this subset of payloads)
return ACTION_RELEASE; return ACTION_RELEASE;
} }
if (pkt->isRouteDirect() && pkt->path_len >= PATH_HASH_SIZE) { if (pkt->isRouteDirect() && pkt->getPathHashCount() > 0) {
// check for 'early received' ACK // check for 'early received' ACK
if (pkt->getPayloadType() == PAYLOAD_TYPE_ACK) { if (pkt->getPayloadType() == PAYLOAD_TYPE_ACK) {
int i = 0; int i = 0;
@@ -88,7 +83,7 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
} }
} }
if (self_id.isHashMatch(pkt->path) && allowPacketForward(pkt)) { if (self_id.isHashMatch(pkt->path, pkt->getPathHashSize()) && allowPacketForward(pkt)) {
if (pkt->getPayloadType() == PAYLOAD_TYPE_MULTIPART) { if (pkt->getPayloadType() == PAYLOAD_TYPE_MULTIPART) {
return forwardMultipartDirect(pkt); return forwardMultipartDirect(pkt);
} else if (pkt->getPayloadType() == PAYLOAD_TYPE_ACK) { } else if (pkt->getPayloadType() == PAYLOAD_TYPE_ACK) {
@@ -158,7 +153,9 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
if (pkt->getPayloadType() == PAYLOAD_TYPE_PATH) { if (pkt->getPayloadType() == PAYLOAD_TYPE_PATH) {
int k = 0; int k = 0;
uint8_t path_len = data[k++]; uint8_t path_len = data[k++];
uint8_t* path = &data[k]; k += path_len; uint8_t hash_size = (path_len >> 6) + 1;
uint8_t hash_count = path_len & 63;
uint8_t* path = &data[k]; k += hash_size*hash_count;
uint8_t extra_type = data[k++] & 0x0F; // upper 4 bits reserved for future use uint8_t extra_type = data[k++] & 0x0F; // upper 4 bits reserved for future use
uint8_t* extra = &data[k]; uint8_t* extra = &data[k];
uint8_t extra_len = len - k; // remainder of packet (may be padded with zeroes!) uint8_t extra_len = len - k; // remainder of packet (may be padded with zeroes!)
@@ -293,8 +290,7 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
if (type == PAYLOAD_TYPE_ACK && pkt->payload_len >= 5) { // a multipart ACK if (type == PAYLOAD_TYPE_ACK && pkt->payload_len >= 5) { // a multipart ACK
Packet tmp; Packet tmp;
tmp.header = pkt->header; tmp.header = pkt->header;
tmp.path_len = pkt->path_len; tmp.path_len = Packet::copyPath(tmp.path, pkt->path, pkt->path_len);
memcpy(tmp.path, pkt->path, pkt->path_len);
tmp.payload_len = pkt->payload_len - 1; tmp.payload_len = pkt->payload_len - 1;
memcpy(tmp.payload, &pkt->payload[1], tmp.payload_len); memcpy(tmp.payload, &pkt->payload[1], tmp.payload_len);
@@ -321,27 +317,25 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
void Mesh::removeSelfFromPath(Packet* pkt) { void Mesh::removeSelfFromPath(Packet* pkt) {
// remove our hash from 'path' // remove our hash from 'path'
pkt->path_len -= PATH_HASH_SIZE; pkt->setPathHashCount(pkt->getPathHashCount() - 1); // decrement the count
#if 0
memcpy(pkt->path, &pkt->path[PATH_HASH_SIZE], pkt->path_len); uint8_t sz = pkt->getPathHashSize();
#elif PATH_HASH_SIZE == 1 for (int k = 0; k < pkt->getPathHashCount()*sz; k += sz) { // shuffle path by 1 'entry'
for (int k = 0; k < pkt->path_len; k++) { // shuffle bytes by 1 memcpy(&pkt->path[k], &pkt->path[k + sz], sz);
pkt->path[k] = pkt->path[k + 1];
} }
#else
#error "need path remove impl"
#endif
} }
DispatcherAction Mesh::routeRecvPacket(Packet* packet) { DispatcherAction Mesh::routeRecvPacket(Packet* packet) {
uint8_t n = packet->getPathHashCount();
if (packet->isRouteFlood() && !packet->isMarkedDoNotRetransmit() if (packet->isRouteFlood() && !packet->isMarkedDoNotRetransmit()
&& packet->path_len + PATH_HASH_SIZE <= MAX_PATH_SIZE && allowPacketForward(packet)) { && (n + 1)*packet->getPathHashSize() <= MAX_PATH_SIZE && allowPacketForward(packet)) {
// append this node's hash to 'path' // append this node's hash to 'path'
packet->path_len += self_id.copyHashTo(&packet->path[packet->path_len]); self_id.copyHashTo(&packet->path[n * packet->getPathHashSize()], packet->getPathHashSize());
packet->setPathHashCount(n + 1);
uint32_t d = getRetransmitDelay(packet); uint32_t d = getRetransmitDelay(packet);
// as this propagates outwards, give it lower and lower priority // as this propagates outwards, give it lower and lower priority
return ACTION_RETRANSMIT_DELAYED(packet->path_len, d); // give priority to closer sources, than ones further away return ACTION_RETRANSMIT_DELAYED(packet->getPathHashCount(), d); // give priority to closer sources, than ones further away
} }
return ACTION_RELEASE; return ACTION_RELEASE;
} }
@@ -353,8 +347,7 @@ DispatcherAction Mesh::forwardMultipartDirect(Packet* pkt) {
if (type == PAYLOAD_TYPE_ACK && pkt->payload_len >= 5) { // a multipart ACK if (type == PAYLOAD_TYPE_ACK && pkt->payload_len >= 5) { // a multipart ACK
Packet tmp; Packet tmp;
tmp.header = pkt->header; tmp.header = pkt->header;
tmp.path_len = pkt->path_len; tmp.path_len = Packet::copyPath(tmp.path, pkt->path, pkt->path_len);
memcpy(tmp.path, pkt->path, pkt->path_len);
tmp.payload_len = pkt->payload_len - 1; tmp.payload_len = pkt->payload_len - 1;
memcpy(tmp.payload, &pkt->payload[1], tmp.payload_len); memcpy(tmp.payload, &pkt->payload[1], tmp.payload_len);
@@ -376,7 +369,7 @@ void Mesh::routeDirectRecvAcks(Packet* packet, uint32_t delay_millis) {
delay_millis += getDirectRetransmitDelay(packet) + 300; delay_millis += getDirectRetransmitDelay(packet) + 300;
auto a1 = createMultiAck(crc, extra); auto a1 = createMultiAck(crc, extra);
if (a1) { if (a1) {
memcpy(a1->path, packet->path, a1->path_len = packet->path_len); a1->path_len = Packet::copyPath(a1->path, packet->path, packet->path_len);
a1->header &= ~PH_ROUTE_MASK; a1->header &= ~PH_ROUTE_MASK;
a1->header |= ROUTE_TYPE_DIRECT; a1->header |= ROUTE_TYPE_DIRECT;
sendPacket(a1, 0, delay_millis); sendPacket(a1, 0, delay_millis);
@@ -386,7 +379,7 @@ void Mesh::routeDirectRecvAcks(Packet* packet, uint32_t delay_millis) {
auto a2 = createAck(crc); auto a2 = createAck(crc);
if (a2) { if (a2) {
memcpy(a2->path, packet->path, a2->path_len = packet->path_len); a2->path_len = Packet::copyPath(a2->path, packet->path, packet->path_len);
a2->header &= ~PH_ROUTE_MASK; a2->header &= ~PH_ROUTE_MASK;
a2->header |= ROUTE_TYPE_DIRECT; a2->header |= ROUTE_TYPE_DIRECT;
sendPacket(a2, 0, delay_millis); sendPacket(a2, 0, delay_millis);
@@ -439,7 +432,10 @@ Packet* Mesh::createPathReturn(const Identity& dest, const uint8_t* secret, cons
} }
Packet* Mesh::createPathReturn(const uint8_t* dest_hash, const uint8_t* secret, const uint8_t* path, uint8_t path_len, uint8_t extra_type, const uint8_t*extra, size_t extra_len) { Packet* Mesh::createPathReturn(const uint8_t* dest_hash, const uint8_t* secret, const uint8_t* path, uint8_t path_len, uint8_t extra_type, const uint8_t*extra, size_t extra_len) {
if (path_len + extra_len + 5 > MAX_COMBINED_PATH) return NULL; // too long!! uint8_t path_hash_size = (path_len >> 6) + 1;
uint8_t path_hash_count = path_len & 63;
if (path_hash_count*path_hash_size + extra_len + 5 > MAX_COMBINED_PATH) return NULL; // too long!!
Packet* packet = obtainNewPacket(); Packet* packet = obtainNewPacket();
if (packet == NULL) { if (packet == NULL) {
@@ -457,7 +453,7 @@ Packet* Mesh::createPathReturn(const uint8_t* dest_hash, const uint8_t* secret,
uint8_t data[MAX_PACKET_PAYLOAD]; uint8_t data[MAX_PACKET_PAYLOAD];
data[data_len++] = path_len; data[data_len++] = path_len;
memcpy(&data[data_len], path, path_len); data_len += path_len; memcpy(&data[data_len], path, path_hash_count*path_hash_size); data_len += path_hash_count*path_hash_size;
if (extra_len > 0) { if (extra_len > 0) {
data[data_len++] = extra_type; data[data_len++] = extra_type;
memcpy(&data[data_len], extra, extra_len); data_len += extra_len; memcpy(&data[data_len], extra, extra_len); data_len += extra_len;
@@ -624,15 +620,19 @@ Packet* Mesh::createControlData(const uint8_t* data, size_t len) {
return packet; return packet;
} }
void Mesh::sendFlood(Packet* packet, uint32_t delay_millis) { void Mesh::sendFlood(Packet* packet, uint32_t delay_millis, uint8_t path_hash_size) {
if (packet->getPayloadType() == PAYLOAD_TYPE_TRACE) { if (packet->getPayloadType() == PAYLOAD_TYPE_TRACE) {
MESH_DEBUG_PRINTLN("%s Mesh::sendFlood(): TRACE type not suspported", getLogDateTime()); MESH_DEBUG_PRINTLN("%s Mesh::sendFlood(): TRACE type not suspported", getLogDateTime());
return; return;
} }
if (path_hash_size == 0 || path_hash_size > 3) {
MESH_DEBUG_PRINTLN("%s Mesh::sendFlood(): invalid path_hash_size", getLogDateTime());
return;
}
packet->header &= ~PH_ROUTE_MASK; packet->header &= ~PH_ROUTE_MASK;
packet->header |= ROUTE_TYPE_FLOOD; packet->header |= ROUTE_TYPE_FLOOD;
packet->path_len = 0; packet->setPathHashSizeAndCount(path_hash_size, 0);
_tables->hasSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us _tables->hasSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
@@ -647,17 +647,21 @@ void Mesh::sendFlood(Packet* packet, uint32_t delay_millis) {
sendPacket(packet, pri, delay_millis); sendPacket(packet, pri, delay_millis);
} }
void Mesh::sendFlood(Packet* packet, uint16_t* transport_codes, uint32_t delay_millis) { void Mesh::sendFlood(Packet* packet, uint16_t* transport_codes, uint32_t delay_millis, uint8_t path_hash_size) {
if (packet->getPayloadType() == PAYLOAD_TYPE_TRACE) { if (packet->getPayloadType() == PAYLOAD_TYPE_TRACE) {
MESH_DEBUG_PRINTLN("%s Mesh::sendFlood(): TRACE type not suspported", getLogDateTime()); MESH_DEBUG_PRINTLN("%s Mesh::sendFlood(): TRACE type not suspported", getLogDateTime());
return; return;
} }
if (path_hash_size == 0 || path_hash_size > 3) {
MESH_DEBUG_PRINTLN("%s Mesh::sendFlood(): invalid path_hash_size", getLogDateTime());
return;
}
packet->header &= ~PH_ROUTE_MASK; packet->header &= ~PH_ROUTE_MASK;
packet->header |= ROUTE_TYPE_TRANSPORT_FLOOD; packet->header |= ROUTE_TYPE_TRANSPORT_FLOOD;
packet->transport_codes[0] = transport_codes[0]; packet->transport_codes[0] = transport_codes[0];
packet->transport_codes[1] = transport_codes[1]; packet->transport_codes[1] = transport_codes[1];
packet->path_len = 0; packet->setPathHashSizeAndCount(path_hash_size, 0);
_tables->hasSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us _tables->hasSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
@@ -679,13 +683,13 @@ void Mesh::sendDirect(Packet* packet, const uint8_t* path, uint8_t path_len, uin
uint8_t pri; uint8_t pri;
if (packet->getPayloadType() == PAYLOAD_TYPE_TRACE) { // TRACE packets are different if (packet->getPayloadType() == PAYLOAD_TYPE_TRACE) { // TRACE packets are different
// for TRACE packets, path is appended to end of PAYLOAD. (path is used for SNR's) // for TRACE packets, path is appended to end of PAYLOAD. (path is used for SNR's)
memcpy(&packet->payload[packet->payload_len], path, path_len); memcpy(&packet->payload[packet->payload_len], path, path_len); // NOTE: path_len here can be > 64, and NOT in the new scheme
packet->payload_len += path_len; packet->payload_len += path_len;
packet->path_len = 0; packet->path_len = 0;
pri = 5; // maybe make this configurable pri = 5; // maybe make this configurable
} else { } else {
memcpy(packet->path, path, packet->path_len = path_len); packet->path_len = Packet::copyPath(packet->path, path, path_len);
if (packet->getPayloadType() == PAYLOAD_TYPE_PATH) { if (packet->getPayloadType() == PAYLOAD_TYPE_PATH) {
pri = 1; // slightly less priority pri = 1; // slightly less priority
} else { } else {

View File

@@ -196,13 +196,13 @@ public:
/** /**
* \brief send a locally-generated Packet with flood routing * \brief send a locally-generated Packet with flood routing
*/ */
void sendFlood(Packet* packet, uint32_t delay_millis=0); void sendFlood(Packet* packet, uint32_t delay_millis=0, uint8_t path_hash_size=1);
/** /**
* \brief send a locally-generated Packet with flood routing * \brief send a locally-generated Packet with flood routing
* \param transport_codes array of 2 codes to attach to packet * \param transport_codes array of 2 codes to attach to packet
*/ */
void sendFlood(Packet* packet, uint16_t* transport_codes, uint32_t delay_millis=0); void sendFlood(Packet* packet, uint16_t* transport_codes, uint32_t delay_millis=0, uint8_t path_hash_size=1);
/** /**
* \brief send a locally-generated Packet with Direct routing * \brief send a locally-generated Packet with Direct routing

View File

@@ -10,8 +10,19 @@ Packet::Packet() {
payload_len = 0; payload_len = 0;
} }
uint8_t Packet::copyPath(uint8_t* dest, const uint8_t* src, uint8_t path_len) {
uint8_t hash_count = path_len & 63;
uint8_t hash_size = (path_len >> 6) + 1;
if (hash_count*hash_size > MAX_PATH_SIZE) {
MESH_DEBUG_PRINTLN("Packet::copyPath, invalid path_len=%d", (uint32_t)path_len);
return 0; // Error
}
memcpy(dest, src, hash_count*hash_size);
return path_len;
}
int Packet::getRawLength() const { int Packet::getRawLength() const {
return 2 + path_len + payload_len + (hasTransportCodes() ? 4 : 0); return 2 + getPathByteLen() + payload_len + (hasTransportCodes() ? 4 : 0);
} }
void Packet::calculatePacketHash(uint8_t* hash) const { void Packet::calculatePacketHash(uint8_t* hash) const {

View File

@@ -76,6 +76,14 @@ public:
*/ */
uint8_t getPayloadVer() const { return (header >> PH_VER_SHIFT) & PH_VER_MASK; } uint8_t getPayloadVer() const { return (header >> PH_VER_SHIFT) & PH_VER_MASK; }
uint8_t getPathHashSize() const { return (path_len >> 6) + 1; }
uint8_t getPathHashCount() const { return path_len & 63; }
uint8_t getPathByteLen() const { return getPathHashCount() * getPathHashSize(); }
void setPathHashCount(uint8_t n) { path_len &= ~63; path_len |= n; }
void setPathHashSizeAndCount(uint8_t sz, uint8_t n) { path_len = ((sz - 1) << 6) | (n & 63); }
static uint8_t copyPath(uint8_t* dest, const uint8_t* src, uint8_t path_len);
void markDoNotRetransmit() { header = 0xFF; } void markDoNotRetransmit() { header = 0xFF; }
bool isMarkedDoNotRetransmit() const { return header == 0xFF; } bool isMarkedDoNotRetransmit() const { return header == 0xFF; }

View File

@@ -39,7 +39,7 @@ mesh::Packet* BaseChatMesh::createSelfAdvert(const char* name, double lat, doubl
} }
void BaseChatMesh::sendAckTo(const ContactInfo& dest, uint32_t ack_hash) { void BaseChatMesh::sendAckTo(const ContactInfo& dest, uint32_t ack_hash) {
if (dest.out_path_len < 0) { if (dest.out_path_len == OUT_PATH_UNKNOWN) {
mesh::Packet* ack = createAck(ack_hash); mesh::Packet* ack = createAck(ack_hash);
if (ack) sendFloodScoped(dest, ack, TXT_ACK_DELAY); if (ack) sendFloodScoped(dest, ack, TXT_ACK_DELAY);
} else { } else {
@@ -92,7 +92,7 @@ ContactInfo* BaseChatMesh::allocateContactSlot() {
void BaseChatMesh::populateContactFromAdvert(ContactInfo& ci, const mesh::Identity& id, const AdvertDataParser& parser, uint32_t timestamp) { void BaseChatMesh::populateContactFromAdvert(ContactInfo& ci, const mesh::Identity& id, const AdvertDataParser& parser, uint32_t timestamp) {
memset(&ci, 0, sizeof(ci)); memset(&ci, 0, sizeof(ci));
ci.id = id; ci.id = id;
ci.out_path_len = -1; // initially out_path is unknown ci.out_path_len = OUT_PATH_UNKNOWN;
StrHelper::strncpy(ci.name, parser.getName(), sizeof(ci.name)); StrHelper::strncpy(ci.name, parser.getName(), sizeof(ci.name));
ci.type = parser.getType(); ci.type = parser.getType();
if (parser.hasLatLon()) { if (parser.hasLatLon()) {
@@ -263,7 +263,7 @@ void BaseChatMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender
} else { } else {
mesh::Packet* reply = createDatagram(PAYLOAD_TYPE_RESPONSE, from.id, secret, temp_buf, reply_len); mesh::Packet* reply = createDatagram(PAYLOAD_TYPE_RESPONSE, from.id, secret, temp_buf, reply_len);
if (reply) { if (reply) {
if (from.out_path_len >= 0) { // we have an out_path, so send DIRECT if (from.out_path_len != OUT_PATH_UNKNOWN) { // we have an out_path, so send DIRECT
sendDirect(reply, from.out_path, from.out_path_len, SERVER_RESPONSE_DELAY); sendDirect(reply, from.out_path, from.out_path_len, SERVER_RESPONSE_DELAY);
} else { } else {
sendFloodScoped(from, reply, SERVER_RESPONSE_DELAY); sendFloodScoped(from, reply, SERVER_RESPONSE_DELAY);
@@ -273,7 +273,7 @@ void BaseChatMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender
} }
} else if (type == PAYLOAD_TYPE_RESPONSE && len > 0) { } else if (type == PAYLOAD_TYPE_RESPONSE && len > 0) {
onContactResponse(from, data, len); onContactResponse(from, data, len);
if (packet->isRouteFlood() && from.out_path_len >= 0) { if (packet->isRouteFlood() && from.out_path_len != OUT_PATH_UNKNOWN) {
// we have direct path, but other node is still sending flood response, so maybe they didn't receive reciprocal path properly(?) // 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); handleReturnPathRetry(from, packet->path, packet->path_len);
} }
@@ -295,7 +295,7 @@ bool BaseChatMesh::onPeerPathRecv(mesh::Packet* packet, int sender_idx, const ui
bool BaseChatMesh::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) { bool BaseChatMesh::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) {
// NOTE: default impl, we just replace the current 'out_path' regardless, whenever sender sends us a new out_path. // NOTE: default impl, we just replace the current 'out_path' regardless, whenever sender sends us a new out_path.
// FUTURE: could store multiple out_paths per contact, and try to find which is the 'best'(?) // FUTURE: could store multiple out_paths per contact, and try to find which is the 'best'(?)
memcpy(from.out_path, out_path, from.out_path_len = out_path_len); // store a copy of path, for sendDirect() from.out_path_len = mesh::Packet::copyPath(from.out_path, out_path, out_path_len); // store a copy of path, for sendDirect()
from.lastmod = getRTCClock()->getCurrentTime(); from.lastmod = getRTCClock()->getCurrentTime();
onContactPathUpdated(from); onContactPathUpdated(from);
@@ -317,7 +317,7 @@ void BaseChatMesh::onAckRecv(mesh::Packet* packet, uint32_t ack_crc) {
txt_send_timeout = 0; // matched one we're waiting for, cancel timeout timer txt_send_timeout = 0; // matched one we're waiting for, cancel timeout timer
packet->markDoNotRetransmit(); // ACK was for this node, so don't retransmit packet->markDoNotRetransmit(); // ACK was for this node, so don't retransmit
if (packet->isRouteFlood() && from->out_path_len >= 0) { if (packet->isRouteFlood() && from->out_path_len != OUT_PATH_UNKNOWN) {
// we have direct path, but other node is still sending flood, so maybe they didn't receive reciprocal path properly(?) // 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); handleReturnPathRetry(*from, packet->path, packet->path_len);
} }
@@ -386,7 +386,7 @@ int BaseChatMesh::sendMessage(const ContactInfo& recipient, uint32_t timestamp,
uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength()); uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength());
int rc; int rc;
if (recipient.out_path_len < 0) { if (recipient.out_path_len == OUT_PATH_UNKNOWN) {
sendFloodScoped(recipient, pkt); sendFloodScoped(recipient, pkt);
txt_send_timeout = futureMillis(est_timeout = calcFloodTimeoutMillisFor(t)); txt_send_timeout = futureMillis(est_timeout = calcFloodTimeoutMillisFor(t));
rc = MSG_SEND_SENT_FLOOD; rc = MSG_SEND_SENT_FLOOD;
@@ -412,7 +412,7 @@ int BaseChatMesh::sendCommandData(const ContactInfo& recipient, uint32_t timest
uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength()); uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength());
int rc; int rc;
if (recipient.out_path_len < 0) { if (recipient.out_path_len == OUT_PATH_UNKNOWN) {
sendFloodScoped(recipient, pkt); sendFloodScoped(recipient, pkt);
txt_send_timeout = futureMillis(est_timeout = calcFloodTimeoutMillisFor(t)); txt_send_timeout = futureMillis(est_timeout = calcFloodTimeoutMillisFor(t));
rc = MSG_SEND_SENT_FLOOD; rc = MSG_SEND_SENT_FLOOD;
@@ -500,7 +500,7 @@ int BaseChatMesh::sendLogin(const ContactInfo& recipient, const char* password,
} }
if (pkt) { if (pkt) {
uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength()); uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength());
if (recipient.out_path_len < 0) { if (recipient.out_path_len == OUT_PATH_UNKNOWN) {
sendFloodScoped(recipient, pkt); sendFloodScoped(recipient, pkt);
est_timeout = calcFloodTimeoutMillisFor(t); est_timeout = calcFloodTimeoutMillisFor(t);
return MSG_SEND_SENT_FLOOD; return MSG_SEND_SENT_FLOOD;
@@ -525,7 +525,7 @@ int BaseChatMesh::sendAnonReq(const ContactInfo& recipient, const uint8_t* data,
} }
if (pkt) { if (pkt) {
uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength()); uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength());
if (recipient.out_path_len < 0) { if (recipient.out_path_len == OUT_PATH_UNKNOWN) {
sendFloodScoped(recipient, pkt); sendFloodScoped(recipient, pkt);
est_timeout = calcFloodTimeoutMillisFor(t); est_timeout = calcFloodTimeoutMillisFor(t);
return MSG_SEND_SENT_FLOOD; return MSG_SEND_SENT_FLOOD;
@@ -552,7 +552,7 @@ int BaseChatMesh::sendRequest(const ContactInfo& recipient, const uint8_t* req_
} }
if (pkt) { if (pkt) {
uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength()); uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength());
if (recipient.out_path_len < 0) { if (recipient.out_path_len == OUT_PATH_UNKNOWN) {
sendFloodScoped(recipient, pkt); sendFloodScoped(recipient, pkt);
est_timeout = calcFloodTimeoutMillisFor(t); est_timeout = calcFloodTimeoutMillisFor(t);
return MSG_SEND_SENT_FLOOD; return MSG_SEND_SENT_FLOOD;
@@ -579,7 +579,7 @@ int BaseChatMesh::sendRequest(const ContactInfo& recipient, uint8_t req_type, u
} }
if (pkt) { if (pkt) {
uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength()); uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength());
if (recipient.out_path_len < 0) { if (recipient.out_path_len == OUT_PATH_UNKNOWN) {
sendFloodScoped(recipient, pkt); sendFloodScoped(recipient, pkt);
est_timeout = calcFloodTimeoutMillisFor(t); est_timeout = calcFloodTimeoutMillisFor(t);
return MSG_SEND_SENT_FLOOD; return MSG_SEND_SENT_FLOOD;
@@ -683,7 +683,7 @@ void BaseChatMesh::checkConnections() {
MESH_DEBUG_PRINTLN("checkConnections(): Keep_alive contact not found!"); MESH_DEBUG_PRINTLN("checkConnections(): Keep_alive contact not found!");
continue; continue;
} }
if (contact->out_path_len < 0) { if (contact->out_path_len == OUT_PATH_UNKNOWN) {
MESH_DEBUG_PRINTLN("checkConnections(): Keep_alive contact, no out_path!"); MESH_DEBUG_PRINTLN("checkConnections(): Keep_alive contact, no out_path!");
continue; continue;
} }
@@ -710,7 +710,7 @@ void BaseChatMesh::checkConnections() {
} }
void BaseChatMesh::resetPathTo(ContactInfo& recipient) { void BaseChatMesh::resetPathTo(ContactInfo& recipient) {
recipient.out_path_len = -1; recipient.out_path_len = OUT_PATH_UNKNOWN;
} }
static ContactInfo* table; // pass via global :-( static ContactInfo* table; // pass via global :-(

View File

@@ -114,7 +114,7 @@ ClientInfo* ClientACL::putClient(const mesh::Identity& id, uint8_t init_perms) {
memset(c, 0, sizeof(*c)); memset(c, 0, sizeof(*c));
c->permissions = init_perms; c->permissions = init_perms;
c->id = id; c->id = id;
c->out_path_len = -1; // initially out_path is unknown c->out_path_len = OUT_PATH_UNKNOWN;
return c; return c;
} }

View File

@@ -10,10 +10,12 @@
#define PERM_ACL_READ_WRITE 2 #define PERM_ACL_READ_WRITE 2
#define PERM_ACL_ADMIN 3 #define PERM_ACL_ADMIN 3
#define OUT_PATH_UNKNOWN 0xFF
struct ClientInfo { struct ClientInfo {
mesh::Identity id; mesh::Identity id;
uint8_t permissions; uint8_t permissions;
int8_t out_path_len; uint8_t out_path_len;
uint8_t out_path[MAX_PATH_SIZE]; uint8_t out_path[MAX_PATH_SIZE];
uint8_t shared_secret[PUB_KEY_SIZE]; uint8_t shared_secret[PUB_KEY_SIZE];
uint32_t last_timestamp; // by THEIR clock (transient) uint32_t last_timestamp; // by THEIR clock (transient)

View File

@@ -3,12 +3,14 @@
#include <Arduino.h> #include <Arduino.h>
#include <Mesh.h> #include <Mesh.h>
#define OUT_PATH_UNKNOWN 0xFF
struct ContactInfo { struct ContactInfo {
mesh::Identity id; mesh::Identity id;
char name[32]; char name[32];
uint8_t type; // on of ADV_TYPE_* uint8_t type; // on of ADV_TYPE_*
uint8_t flags; uint8_t flags;
int8_t out_path_len; uint8_t out_path_len;
mutable bool shared_secret_valid; // flag to indicate if shared_secret has been calculated mutable bool shared_secret_valid; // flag to indicate if shared_secret has been calculated
uint8_t out_path[MAX_PATH_SIZE]; uint8_t out_path[MAX_PATH_SIZE];
uint32_t last_advert_timestamp; // by THEIR clock uint32_t last_advert_timestamp; // by THEIR clock