diff --git a/examples/ping_client/main.cpp b/examples/ping_client/main.cpp index 39ebf329..7d7305ae 100644 --- a/examples/ping_client/main.cpp +++ b/examples/ping_client/main.cpp @@ -95,7 +95,7 @@ public: if (!got_adv) return; // have not received Advert yet uint32_t now = getRTCClock()->getCurrentTime(); // important, need timestamp in packet, so that packet_hash will be unique - mesh::Packet* ping = createDatagram(PAYLOAD_TYPE_ANON_REQ, server_id, server_secret, (uint8_t *) &now, sizeof(now)); + mesh::Packet* ping = createAnonDatagram(PAYLOAD_TYPE_ANON_REQ, self_id, server_id, server_secret, (uint8_t *) &now, sizeof(now)); if (ping) { if (server_path_len < 0) { diff --git a/examples/simple_secure_chat/main.cpp b/examples/simple_secure_chat/main.cpp index f652a30c..5715d815 100644 --- a/examples/simple_secure_chat/main.cpp +++ b/examples/simple_secure_chat/main.cpp @@ -28,8 +28,9 @@ #error "need to provide a 'board' object" #endif -#define FLOOD_SEND_TIMEOUT_MILLIS 4000 -#define DIRECT_SEND_TIMEOUT_MILLIS 2000 +#define FLOOD_SEND_TIMEOUT_MILLIS 6000 +#define DIRECT_TIMEOUT_BASE 1000 +#define DIRECT_TIMEOUT_FACTOR 400 // per hop millis /* -------------------------------------------------------------------------------------- */ @@ -108,6 +109,9 @@ protected: void onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_idx, uint8_t* data, size_t len) override { if (type == PAYLOAD_TYPE_TXT_MSG) { + // NOTE: this is a 'first packet wins' impl. When receiving from multiple paths, the first to arrive wins. + // For flood mode, the path may not be the 'best' in terms of hops. + // FUTURE: could send back multiple paths, using createPathReturn(), and let sender choose which to use(?) if (_table->hasSeenPacket(packet)) return; int i = matching_peer_indexes[sender_idx]; @@ -124,10 +128,8 @@ protected: // len can be > original length, but 'text' will be padded with zeroes data[len] = 0; // need to make a C string again, with null terminator - Serial.print("MSG -> from "); - Serial.print(from.name); - Serial.print(": "); - Serial.println((const char *) &data[4]); + Serial.printf("MSG -> from %s\n", from.name); + Serial.printf(" %s\n", (const char *) &data[4]); uint32_t ack_hash; // calc truncated hash of the message timestamp + text + sender pub_key, to prove to sender that we got it mesh::Utils::sha256((uint8_t *) &ack_hash, 4, data, len, from.id.pub_key, PUB_KEY_SIZE); @@ -162,6 +164,8 @@ protected: ContactInfo& from = contacts[i]; Serial.printf("PATH to: %s, path_len=%d\n", from.name, (uint32_t) path_len); + // 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'(?) memcpy(from.out_path, path, from.out_path_len = path_len); // store a copy of path, for sendDirect() if (packet->isRouteFlood()) { @@ -213,10 +217,10 @@ public: return createDatagram(PAYLOAD_TYPE_TXT_MSG, recipient.id, recipient.shared_secret, temp, 4 + text_len); } - void sendSelfAnnounce() { - mesh::Packet* announce = createAdvert(self_id); - if (announce) { - sendFlood(announce); + void sendSelfAdvert() { + mesh::Packet* adv = createAdvert(self_id); + if (adv) { + sendFlood(adv); Serial.println(" (advert sent)."); } else { Serial.println(" ERROR: unable to create packet."); @@ -260,7 +264,7 @@ void setup() { the_mesh.addContact("Alice", mesh::Identity(alice_public)); #endif Serial.println("Help:"); - Serial.println(" enter 'ann' to announce presence to mesh"); + Serial.println(" enter 'adv' to advertise presence to mesh"); Serial.println(" enter 'send {message text}' to send a message"); the_mesh.begin(); @@ -268,8 +272,8 @@ void setup() { command[0] = 0; txt_send_timeout = 0; - // send out initial Announce to the mesh - the_mesh.sendSelfAnnounce(); + // send out initial Advertisement to the mesh + the_mesh.sendSelfAdvert(); } void loop() { @@ -301,14 +305,14 @@ void loop() { txt_send_timeout = the_mesh.futureMillis(FLOOD_SEND_TIMEOUT_MILLIS); } else { the_mesh.sendDirect(pkt, recipient.out_path, recipient.out_path_len); - txt_send_timeout = the_mesh.futureMillis(DIRECT_SEND_TIMEOUT_MILLIS); + txt_send_timeout = the_mesh.futureMillis(DIRECT_TIMEOUT_FACTOR*recipient.out_path_len + DIRECT_TIMEOUT_BASE); } Serial.println(" (message sent)"); } else { Serial.println(" ERROR: unable to create packet."); } - } else if (strcmp(command, "ann") == 0) { - the_mesh.sendSelfAnnounce(); + } else if (strcmp(command, "adv") == 0) { + the_mesh.sendSelfAdvert(); } else if (strcmp(command, "key") == 0) { mesh::LocalIdentity new_id(the_mesh.getRNG()); new_id.printTo(Serial); diff --git a/examples/test_admin/main.cpp b/examples/test_admin/main.cpp index 01612cc7..4816150f 100644 --- a/examples/test_admin/main.cpp +++ b/examples/test_admin/main.cpp @@ -75,7 +75,7 @@ protected: memcpy(temp, &now, 4); memcpy(&temp[4], ADMIN_PASSWORD, 8); - mesh::Packet* login = createDatagram(PAYLOAD_TYPE_ANON_REQ, server_id, server_secret, temp, sizeof(temp)); + mesh::Packet* login = createAnonDatagram(PAYLOAD_TYPE_ANON_REQ, self_id, server_id, server_secret, temp, sizeof(temp)); if (login) sendFlood(login); // server_path won't be known yet } } diff --git a/src/Mesh.cpp b/src/Mesh.cpp index 6a2df1fd..38964f1b 100644 --- a/src/Mesh.cpp +++ b/src/Mesh.cpp @@ -283,9 +283,7 @@ Packet* Mesh::createPathReturn(const Identity& dest, const uint8_t* secret, cons } Packet* Mesh::createDatagram(uint8_t type, const Identity& dest, const uint8_t* secret, const uint8_t* data, size_t data_len) { - if (type == PAYLOAD_TYPE_ANON_REQ) { - if (data_len + 1 + PUB_KEY_SIZE + CIPHER_BLOCK_SIZE-1 > MAX_PACKET_PAYLOAD) return NULL; - } else if (type == PAYLOAD_TYPE_TXT_MSG || type == PAYLOAD_TYPE_REQ || type == PAYLOAD_TYPE_RESPONSE) { + if (type == PAYLOAD_TYPE_TXT_MSG || type == PAYLOAD_TYPE_REQ || type == PAYLOAD_TYPE_RESPONSE) { if (data_len + 2 + CIPHER_BLOCK_SIZE-1 > MAX_PACKET_PAYLOAD) return NULL; } else { return NULL; // invalid type @@ -299,13 +297,37 @@ Packet* Mesh::createDatagram(uint8_t type, const Identity& dest, const uint8_t* packet->header = (type << PH_TYPE_SHIFT); // ROUTE_TYPE_* set later packet->path_len = 0; + int len = 0; + len += dest.copyHashTo(&packet->payload[len]); // dest hash + len += self_id.copyHashTo(&packet->payload[len]); // src hash + len += Utils::encryptThenMAC(secret, &packet->payload[len], data, data_len); + + packet->payload_len = len; + + return packet; +} + +Packet* Mesh::createAnonDatagram(uint8_t type, const LocalIdentity& sender, const Identity& dest, const uint8_t* secret, const uint8_t* data, size_t data_len) { + if (type == PAYLOAD_TYPE_ANON_REQ) { + if (data_len + 1 + PUB_KEY_SIZE + CIPHER_BLOCK_SIZE-1 > MAX_PACKET_PAYLOAD) return NULL; + } else { + return NULL; // invalid type + } + + Packet* packet = obtainNewPacket(); + if (packet == NULL) { + MESH_DEBUG_PRINTLN("Mesh::createAnonDatagram(): error, packet pool empty"); + return NULL; + } + packet->header = (type << PH_TYPE_SHIFT); // ROUTE_TYPE_* set later + packet->path_len = 0; + int len = 0; if (type == PAYLOAD_TYPE_ANON_REQ) { len += dest.copyHashTo(&packet->payload[len]); // dest hash - memcpy(&packet->payload[len], self_id.pub_key, PUB_KEY_SIZE); len += PUB_KEY_SIZE; // sender pub_key + memcpy(&packet->payload[len], sender.pub_key, PUB_KEY_SIZE); len += PUB_KEY_SIZE; // sender pub_key } else { - len += dest.copyHashTo(&packet->payload[len]); // dest hash - len += self_id.copyHashTo(&packet->payload[len]); // src hash + // FUTURE: } len += Utils::encryptThenMAC(secret, &packet->payload[len], data, data_len); diff --git a/src/Mesh.h b/src/Mesh.h index 1984ba3f..2b7a449d 100644 --- a/src/Mesh.h +++ b/src/Mesh.h @@ -128,6 +128,7 @@ public: Packet* createAdvert(const LocalIdentity& id, const uint8_t* app_data=NULL, size_t app_data_len=0); Packet* createDatagram(uint8_t type, const Identity& dest, const uint8_t* secret, const uint8_t* data, size_t len); + Packet* createAnonDatagram(uint8_t type, const LocalIdentity& sender, const Identity& dest, const uint8_t* secret, const uint8_t* data, size_t data_len); Packet* createGroupDatagram(uint8_t type, const GroupChannel& channel, const uint8_t* data, size_t data_len); Packet* createAck(uint32_t ack_crc); Packet* createPathReturn(const Identity& dest, const uint8_t* secret, const uint8_t* path, uint8_t path_len, uint8_t extra_type, const uint8_t*extra, size_t extra_len);