mirror of
https://github.com/esp8266/Arduino.git
synced 2025-06-29 16:03:14 +03:00
- Split most of the EspnowMeshBackend code into utility files and the new ConditionalPrinter, EspnowDatabase, EspnowConnectionManager, EspnowTransmitter and EspnowEncryptionBroker classes.
- Improve mutex handling. - Move verifyEncryptionRequestHmac function from JsonTranslator to EspnowEncryptionBroker. - Remove UtilityMethods.cpp.
This commit is contained in:
585
libraries/ESP8266WiFiMesh/src/EspnowConnectionManager.cpp
Normal file
585
libraries/ESP8266WiFiMesh/src/EspnowConnectionManager.cpp
Normal file
@ -0,0 +1,585 @@
|
||||
/*
|
||||
Copyright (C) 2020 Anders Löfgren
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
extern "C" {
|
||||
#include <espnow.h>
|
||||
}
|
||||
|
||||
#include "EspnowConnectionManager.h"
|
||||
#include "JsonTranslator.h"
|
||||
#include "MeshCryptoInterface.h"
|
||||
#include "Serializer.h"
|
||||
#include "EspnowTransmitter.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
using EspnowProtocolInterpreter::encryptedConnectionKeyLength;
|
||||
using EspnowProtocolInterpreter::hashKeyLength;
|
||||
using EspnowProtocolInterpreter::maxEncryptedConnections;
|
||||
|
||||
namespace TypeCast = MeshTypeConversionFunctions;
|
||||
|
||||
std::vector<EncryptedConnectionLog> _encryptedConnections = {};
|
||||
|
||||
uint32_t _unsynchronizedMessageID = 0;
|
||||
|
||||
uint8_t _espnowEncryptionKok[encryptedConnectionKeyLength] = { 0 };
|
||||
bool _espnowEncryptionKokSet = false;
|
||||
}
|
||||
|
||||
EspnowConnectionManager::EspnowConnectionManager(ConditionalPrinter &conditionalPrinterInstance, EspnowDatabase &databaseInstance)
|
||||
: _conditionalPrinter(conditionalPrinterInstance), _database(databaseInstance)
|
||||
{
|
||||
// Reserve the maximum possible usage early on to prevent heap fragmentation later.
|
||||
encryptedConnections().reserve(maxEncryptedConnections);
|
||||
}
|
||||
|
||||
std::vector<EncryptedConnectionLog> & EspnowConnectionManager::encryptedConnections() { return _encryptedConnections; }
|
||||
|
||||
uint8_t EspnowConnectionManager::numberOfEncryptedConnections()
|
||||
{
|
||||
return encryptedConnections().size();
|
||||
}
|
||||
|
||||
ConnectionType EspnowConnectionManager::getConnectionInfo(uint8_t *peerMac, uint32_t *remainingDuration)
|
||||
{
|
||||
EncryptedConnectionLog *encryptedConnection = nullptr;
|
||||
|
||||
if(peerMac)
|
||||
encryptedConnection = getEncryptedConnection(peerMac);
|
||||
|
||||
return getConnectionInfoHelper(encryptedConnection, remainingDuration);
|
||||
}
|
||||
|
||||
ConnectionType EspnowConnectionManager::getConnectionInfo(const uint32_t connectionIndex, uint32_t *remainingDuration, uint8_t *peerMac)
|
||||
{
|
||||
EncryptedConnectionLog *encryptedConnection = nullptr;
|
||||
|
||||
if(connectionIndex < numberOfEncryptedConnections())
|
||||
encryptedConnection = &encryptedConnections()[connectionIndex];
|
||||
|
||||
return getConnectionInfoHelper(encryptedConnection, remainingDuration, peerMac);
|
||||
}
|
||||
|
||||
EspnowConnectionManager::connectionLogIterator EspnowConnectionManager::connectionLogEndIterator()
|
||||
{
|
||||
return encryptedConnections().end();
|
||||
}
|
||||
|
||||
void EspnowConnectionManager::setEspnowEncryptedConnectionKey(const uint8_t espnowEncryptedConnectionKey[encryptedConnectionKeyLength])
|
||||
{
|
||||
assert(espnowEncryptedConnectionKey != nullptr);
|
||||
|
||||
for(int i = 0; i < encryptedConnectionKeyLength; ++i)
|
||||
{
|
||||
_espnowEncryptedConnectionKey[i] = espnowEncryptedConnectionKey[i];
|
||||
}
|
||||
}
|
||||
|
||||
void EspnowConnectionManager::setEspnowEncryptedConnectionKey(const String &espnowEncryptedConnectionKeySeed)
|
||||
{
|
||||
MeshCryptoInterface::initializeKey(_espnowEncryptedConnectionKey, encryptedConnectionKeyLength, espnowEncryptedConnectionKeySeed);
|
||||
}
|
||||
|
||||
const uint8_t *EspnowConnectionManager::getEspnowEncryptedConnectionKey() const
|
||||
{
|
||||
return _espnowEncryptedConnectionKey;
|
||||
}
|
||||
|
||||
uint8_t *EspnowConnectionManager::getEspnowEncryptedConnectionKey(uint8_t resultArray[encryptedConnectionKeyLength]) const
|
||||
{
|
||||
std::copy_n(_espnowEncryptedConnectionKey, encryptedConnectionKeyLength, resultArray);
|
||||
return resultArray;
|
||||
}
|
||||
|
||||
bool EspnowConnectionManager::initializeEncryptionKok()
|
||||
{
|
||||
// esp_now_set_kok returns 0 on success.
|
||||
return !(_espnowEncryptionKokSet && esp_now_set_kok(_espnowEncryptionKok, encryptedConnectionKeyLength));
|
||||
}
|
||||
|
||||
bool EspnowConnectionManager::setEspnowEncryptionKok(uint8_t espnowEncryptionKok[encryptedConnectionKeyLength])
|
||||
{
|
||||
if(espnowEncryptionKok == nullptr || esp_now_set_kok(espnowEncryptionKok, encryptedConnectionKeyLength)) // esp_now_set_kok failed if not == 0
|
||||
return false;
|
||||
|
||||
for(int i = 0; i < encryptedConnectionKeyLength; ++i)
|
||||
{
|
||||
_espnowEncryptionKok[i] = espnowEncryptionKok[i];
|
||||
}
|
||||
|
||||
_espnowEncryptionKokSet = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EspnowConnectionManager::setEspnowEncryptionKok(const String &espnowEncryptionKokSeed)
|
||||
{
|
||||
uint8_t espnowEncryptionKok[encryptedConnectionKeyLength] {};
|
||||
MeshCryptoInterface::initializeKey(espnowEncryptionKok, encryptedConnectionKeyLength, espnowEncryptionKokSeed);
|
||||
|
||||
return setEspnowEncryptionKok(espnowEncryptionKok);
|
||||
}
|
||||
|
||||
const uint8_t *EspnowConnectionManager::getEspnowEncryptionKok()
|
||||
{
|
||||
if(_espnowEncryptionKokSet)
|
||||
return _espnowEncryptionKok;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void EspnowConnectionManager::setEspnowHashKey(const uint8_t espnowHashKey[hashKeyLength])
|
||||
{
|
||||
assert(espnowHashKey != nullptr);
|
||||
|
||||
for(int i = 0; i < hashKeyLength; ++i)
|
||||
{
|
||||
_espnowHashKey[i] = espnowHashKey[i];
|
||||
}
|
||||
}
|
||||
|
||||
void EspnowConnectionManager::setEspnowHashKey(const String &espnowHashKeySeed)
|
||||
{
|
||||
MeshCryptoInterface::initializeKey(_espnowHashKey, hashKeyLength, espnowHashKeySeed);
|
||||
}
|
||||
|
||||
const uint8_t *EspnowConnectionManager::getEspnowHashKey() const
|
||||
{
|
||||
return _espnowHashKey;
|
||||
}
|
||||
|
||||
uint8_t *EspnowConnectionManager::getEncryptedMac(const uint8_t *peerMac, uint8_t *resultArray)
|
||||
{
|
||||
if(EncryptedConnectionLog *encryptedConnection = getEncryptedConnection(peerMac))
|
||||
{
|
||||
return encryptedConnection->getEncryptedPeerMac(resultArray);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EncryptedConnectionLog *EspnowConnectionManager::getEncryptedConnection(const uint8_t *peerMac)
|
||||
{
|
||||
auto connectionIterator = getEncryptedConnectionIterator(peerMac, encryptedConnections());
|
||||
if(connectionIterator != encryptedConnections().end())
|
||||
{
|
||||
return &(*connectionIterator);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EncryptedConnectionLog *EspnowConnectionManager::getEncryptedConnection(const uint32_t connectionIndex)
|
||||
{
|
||||
if(connectionIndex < numberOfEncryptedConnections())
|
||||
return &encryptedConnections()[connectionIndex];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EncryptedConnectionLog *EspnowConnectionManager::getTemporaryEncryptedConnection(const uint8_t *peerMac)
|
||||
{
|
||||
connectionLogIterator connectionIterator = connectionLogEndIterator();
|
||||
if(getTemporaryEncryptedConnectionIterator(peerMac, connectionIterator))
|
||||
{
|
||||
return &(*connectionIterator);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename T::iterator EspnowConnectionManager::getEncryptedConnectionIterator(const uint8_t *peerMac, T &connectionContainer)
|
||||
{
|
||||
typename T::iterator connectionIterator = connectionContainer.begin();
|
||||
|
||||
while(connectionIterator != connectionContainer.end())
|
||||
{
|
||||
if(connectionIterator->connectedTo(peerMac))
|
||||
break;
|
||||
else
|
||||
++connectionIterator;
|
||||
}
|
||||
|
||||
return connectionIterator;
|
||||
}
|
||||
|
||||
bool EspnowConnectionManager::getEncryptedConnectionIterator(const uint8_t *peerMac, connectionLogIterator &iterator)
|
||||
{
|
||||
connectionLogIterator result = getEncryptedConnectionIterator(peerMac, encryptedConnections());
|
||||
|
||||
if(result != connectionLogEndIterator())
|
||||
{
|
||||
iterator = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EspnowConnectionManager::getTemporaryEncryptedConnectionIterator(const uint8_t *peerMac, connectionLogIterator &iterator)
|
||||
{
|
||||
connectionLogIterator result = connectionLogEndIterator();
|
||||
|
||||
if(getEncryptedConnectionIterator(peerMac, result) && result->temporary())
|
||||
{
|
||||
iterator = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ConnectionType EspnowConnectionManager::getConnectionInfoHelper(const EncryptedConnectionLog *encryptedConnection, uint32_t *remainingDuration, uint8_t *peerMac)
|
||||
{
|
||||
if(!encryptedConnection)
|
||||
{
|
||||
return ConnectionType::NO_CONNECTION;
|
||||
}
|
||||
|
||||
if(peerMac)
|
||||
encryptedConnection->getEncryptedPeerMac(peerMac);
|
||||
|
||||
if(const ExpiringTimeTracker *timeTracker = encryptedConnection->temporary())
|
||||
{
|
||||
if(remainingDuration)
|
||||
*remainingDuration = timeTracker->remainingDuration();
|
||||
|
||||
return ConnectionType::TEMPORARY_CONNECTION;
|
||||
}
|
||||
|
||||
return ConnectionType::PERMANENT_CONNECTION;
|
||||
}
|
||||
|
||||
|
||||
void EspnowConnectionManager::setEncryptedConnectionsSoftLimit(const uint8_t softLimit)
|
||||
{
|
||||
assert(softLimit <= 6); // Valid values are 0 to 6, but uint8_t is always at least 0.
|
||||
_encryptedConnectionsSoftLimit = softLimit;
|
||||
}
|
||||
|
||||
uint8_t EspnowConnectionManager::encryptedConnectionsSoftLimit() const { return _encryptedConnectionsSoftLimit; }
|
||||
|
||||
bool EspnowConnectionManager::addUnencryptedConnection(const String &serializedConnectionState)
|
||||
{
|
||||
return JsonTranslator::getUnsynchronizedMessageID(serializedConnectionState, _unsynchronizedMessageID);
|
||||
}
|
||||
|
||||
EncryptedConnectionStatus EspnowConnectionManager::addEncryptedConnection(uint8_t *peerStaMac, uint8_t *peerApMac, const uint64_t peerSessionKey, const uint64_t ownSessionKey)
|
||||
{
|
||||
assert(encryptedConnections().size() <= maxEncryptedConnections); // If this is not the case, ESP-NOW is no longer in sync with the library
|
||||
|
||||
uint8_t encryptionKeyArray[encryptedConnectionKeyLength] = { 0 };
|
||||
|
||||
if(EncryptedConnectionLog *encryptedConnection = getEncryptedConnection(peerStaMac))
|
||||
{
|
||||
// Encrypted connection with MAC already exists, so no need to replace it, just updating is enough.
|
||||
temporaryEncryptedConnectionToPermanent(peerStaMac);
|
||||
encryptedConnection->setPeerSessionKey(peerSessionKey);
|
||||
encryptedConnection->setOwnSessionKey(ownSessionKey);
|
||||
esp_now_set_peer_key(peerStaMac, getEspnowEncryptedConnectionKey(encryptionKeyArray), encryptedConnectionKeyLength);
|
||||
encryptedConnection->setHashKey(getEspnowHashKey());
|
||||
|
||||
return EncryptedConnectionStatus::CONNECTION_ESTABLISHED;
|
||||
}
|
||||
|
||||
if(encryptedConnections().size() == maxEncryptedConnections)
|
||||
{
|
||||
// No capacity for more encrypted connections.
|
||||
return EncryptedConnectionStatus::MAX_CONNECTIONS_REACHED_SELF;
|
||||
}
|
||||
// returns 0 on success: int esp_now_add_peer(u8 *mac_addr, u8 role, u8 channel, u8 *key, u8 key_len)
|
||||
// Only MAC, encryption key and key length (16) actually matter. The rest is not used by ESP-NOW.
|
||||
else if(0 == esp_now_add_peer(peerStaMac, ESP_NOW_ROLE_CONTROLLER, _database.getWiFiChannel(), getEspnowEncryptedConnectionKey(encryptionKeyArray), encryptedConnectionKeyLength))
|
||||
{
|
||||
encryptedConnections().emplace_back(peerStaMac, peerApMac, peerSessionKey, ownSessionKey, getEspnowHashKey());
|
||||
return EncryptedConnectionStatus::CONNECTION_ESTABLISHED;
|
||||
}
|
||||
else
|
||||
{
|
||||
return EncryptedConnectionStatus::API_CALL_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
EncryptedConnectionStatus EspnowConnectionManager::addEncryptedConnection(const String &serializedConnectionState, const bool ignoreDuration)
|
||||
{
|
||||
uint32_t duration = 0;
|
||||
bool desync = false;
|
||||
uint64_t ownSessionKey = 0;
|
||||
uint64_t peerSessionKey = 0;
|
||||
uint8_t peerStaMac[6] = { 0 };
|
||||
uint8_t peerApMac[6] = { 0 };
|
||||
|
||||
if(JsonTranslator::getDesync(serializedConnectionState, desync)
|
||||
&& JsonTranslator::getOwnSessionKey(serializedConnectionState, ownSessionKey) && JsonTranslator::getPeerSessionKey(serializedConnectionState, peerSessionKey)
|
||||
&& JsonTranslator::getPeerStaMac(serializedConnectionState, peerStaMac) && JsonTranslator::getPeerApMac(serializedConnectionState, peerApMac))
|
||||
{
|
||||
EncryptedConnectionStatus result = EncryptedConnectionStatus::API_CALL_FAILED;
|
||||
|
||||
if(!ignoreDuration && JsonTranslator::getDuration(serializedConnectionState, duration))
|
||||
{
|
||||
result = addTemporaryEncryptedConnection(peerStaMac, peerApMac, peerSessionKey, ownSessionKey, duration);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = addEncryptedConnection(peerStaMac, peerApMac, peerSessionKey, ownSessionKey);
|
||||
}
|
||||
|
||||
if(result == EncryptedConnectionStatus::CONNECTION_ESTABLISHED)
|
||||
{
|
||||
EncryptedConnectionLog *encryptedConnection = getEncryptedConnection(peerStaMac);
|
||||
encryptedConnection->setDesync(desync);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return EncryptedConnectionStatus::REQUEST_TRANSMISSION_FAILED;
|
||||
}
|
||||
|
||||
EncryptedConnectionStatus EspnowConnectionManager::addTemporaryEncryptedConnection(uint8_t *peerStaMac, uint8_t *peerApMac, const uint64_t peerSessionKey, const uint64_t ownSessionKey, const uint32_t duration)
|
||||
{
|
||||
assert(encryptedConnections().size() <= maxEncryptedConnections); // If this is not the case, ESP-NOW is no longer in sync with the library
|
||||
|
||||
uint8_t encryptionKeyArray[encryptedConnectionKeyLength] = { 0 };
|
||||
|
||||
connectionLogIterator encryptedConnection = connectionLogEndIterator();
|
||||
|
||||
if(getEncryptedConnectionIterator(peerStaMac, encryptedConnection))
|
||||
{
|
||||
// There is already an encrypted connection to this mac, so no need to replace it, just updating is enough.
|
||||
encryptedConnection->setPeerSessionKey(peerSessionKey);
|
||||
encryptedConnection->setOwnSessionKey(ownSessionKey);
|
||||
esp_now_set_peer_key(peerStaMac, getEspnowEncryptedConnectionKey(encryptionKeyArray), encryptedConnectionKeyLength);
|
||||
encryptedConnection->setHashKey(getEspnowHashKey());
|
||||
|
||||
if(encryptedConnection->temporary())
|
||||
{
|
||||
encryptedConnection->setRemainingDuration(duration);
|
||||
}
|
||||
|
||||
return EncryptedConnectionStatus::CONNECTION_ESTABLISHED;
|
||||
}
|
||||
|
||||
EncryptedConnectionStatus result = addEncryptedConnection(peerStaMac, peerApMac, peerSessionKey, ownSessionKey);
|
||||
|
||||
if(result == EncryptedConnectionStatus::CONNECTION_ESTABLISHED)
|
||||
{
|
||||
if(!getEncryptedConnectionIterator(peerStaMac, encryptedConnection))
|
||||
assert(false && String(F("No connection found despite being added in addTemporaryEncryptedConnection.")));
|
||||
|
||||
encryptedConnection->setRemainingDuration(duration);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
EncryptedConnectionStatus EspnowConnectionManager::addTemporaryEncryptedConnection(const String &serializedConnectionState, const uint32_t duration)
|
||||
{
|
||||
bool desync = false;
|
||||
uint64_t ownSessionKey = 0;
|
||||
uint64_t peerSessionKey = 0;
|
||||
uint8_t peerStaMac[6] = { 0 };
|
||||
uint8_t peerApMac[6] = { 0 };
|
||||
|
||||
if(JsonTranslator::getDesync(serializedConnectionState, desync)
|
||||
&& JsonTranslator::getOwnSessionKey(serializedConnectionState, ownSessionKey) && JsonTranslator::getPeerSessionKey(serializedConnectionState, peerSessionKey)
|
||||
&& JsonTranslator::getPeerStaMac(serializedConnectionState, peerStaMac) && JsonTranslator::getPeerApMac(serializedConnectionState, peerApMac))
|
||||
{
|
||||
EncryptedConnectionStatus result = addTemporaryEncryptedConnection(peerStaMac, peerApMac, peerSessionKey, ownSessionKey, duration);
|
||||
|
||||
if(result == EncryptedConnectionStatus::CONNECTION_ESTABLISHED)
|
||||
{
|
||||
EncryptedConnectionLog *encryptedConnection = getEncryptedConnection(peerStaMac);
|
||||
encryptedConnection->setDesync(desync);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return EncryptedConnectionStatus::REQUEST_TRANSMISSION_FAILED;
|
||||
}
|
||||
|
||||
EncryptedConnectionRemovalOutcome EspnowConnectionManager::removeEncryptedConnection(const uint8_t *peerMac)
|
||||
{
|
||||
auto connectionIterator = getEncryptedConnectionIterator(peerMac, encryptedConnections());
|
||||
if(connectionIterator != encryptedConnections().end())
|
||||
{
|
||||
MutexTracker mutexTracker(EspnowTransmitter::captureEspnowTransmissionMutex());
|
||||
if(!mutexTracker.mutexCaptured())
|
||||
{
|
||||
// We should not remove an encrypted connection while there is a transmission in progress, since that may cause encrypted data to be sent unencrypted.
|
||||
// Thus when a transmission is in progress we just schedule the encrypted connection for removal, so it will be removed during the next updateTemporaryEncryptedConnections() call.
|
||||
connectionIterator->scheduleForRemoval();
|
||||
return EncryptedConnectionRemovalOutcome::REMOVAL_SCHEDULED;
|
||||
}
|
||||
else
|
||||
{
|
||||
return removeEncryptedConnectionUnprotected(peerMac);
|
||||
}
|
||||
}
|
||||
|
||||
// peerMac is already removed
|
||||
return EncryptedConnectionRemovalOutcome::REMOVAL_SUCCEEDED;
|
||||
}
|
||||
|
||||
|
||||
EncryptedConnectionRemovalOutcome EspnowConnectionManager::removeEncryptedConnectionUnprotected(const uint8_t *peerMac, std::vector<EncryptedConnectionLog>::iterator *resultingIterator)
|
||||
{
|
||||
connectionLogIterator connectionIterator = getEncryptedConnectionIterator(peerMac, encryptedConnections());
|
||||
return removeEncryptedConnectionUnprotected(connectionIterator, resultingIterator);
|
||||
}
|
||||
|
||||
EncryptedConnectionRemovalOutcome EspnowConnectionManager::removeEncryptedConnectionUnprotected(connectionLogIterator &connectionIterator, std::vector<EncryptedConnectionLog>::iterator *resultingIterator)
|
||||
{
|
||||
assert(encryptedConnections().size() <= maxEncryptedConnections); // If this is not the case, ESP-NOW is no longer in sync with the library
|
||||
|
||||
if(connectionIterator != connectionLogEndIterator())
|
||||
{
|
||||
uint8_t encryptedMac[6] {0};
|
||||
connectionIterator->getEncryptedPeerMac(encryptedMac);
|
||||
ConditionalPrinter::staticVerboseModePrint(String(F("Removing connection ")) + TypeCast::macToString(encryptedMac) + String(F("... ")), false);
|
||||
bool removalSucceeded = esp_now_del_peer(encryptedMac) == 0;
|
||||
|
||||
if(removalSucceeded)
|
||||
{
|
||||
if(resultingIterator != nullptr)
|
||||
{
|
||||
*resultingIterator = encryptedConnections().erase(connectionIterator);
|
||||
}
|
||||
else
|
||||
{
|
||||
encryptedConnections().erase(connectionIterator);
|
||||
}
|
||||
ConditionalPrinter::staticVerboseModePrint(String(F("Removal succeeded")));
|
||||
|
||||
// Not deleting encrypted responses here would cause them to be sent unencrypted,
|
||||
// exposing the peer session key which can be misused later if the encrypted connection is re-established.
|
||||
EspnowDatabase::deleteScheduledResponsesByRecipient(encryptedMac, true);
|
||||
|
||||
// Not deleting these entries here may cause issues if the encrypted connection is quickly re-added
|
||||
// and happens to get the same session keys as before (e.g. requestReceived() could then give false positives).
|
||||
EspnowDatabase::deleteEntriesByMac(EspnowDatabase::receivedEspnowTransmissions(), encryptedMac, true);
|
||||
EspnowDatabase::deleteEntriesByMac(EspnowDatabase::sentRequests(), encryptedMac, true);
|
||||
EspnowDatabase::deleteEntriesByMac(EspnowDatabase::receivedRequests(), encryptedMac, true);
|
||||
|
||||
return EncryptedConnectionRemovalOutcome::REMOVAL_SUCCEEDED;
|
||||
}
|
||||
else
|
||||
{
|
||||
ConditionalPrinter::staticVerboseModePrint(String(F("Removal failed")));
|
||||
return EncryptedConnectionRemovalOutcome::REMOVAL_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
// connection is already removed
|
||||
return EncryptedConnectionRemovalOutcome::REMOVAL_SUCCEEDED;
|
||||
}
|
||||
|
||||
bool EspnowConnectionManager::temporaryEncryptedConnectionToPermanent(const uint8_t *peerMac)
|
||||
{
|
||||
if(EncryptedConnectionLog *temporaryConnection = getTemporaryEncryptedConnection(peerMac))
|
||||
{
|
||||
temporaryConnection->removeDuration();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
String EspnowConnectionManager::serializeUnencryptedConnection()
|
||||
{
|
||||
return Serializer::serializeUnencryptedConnection(String(_unsynchronizedMessageID));
|
||||
}
|
||||
|
||||
String EspnowConnectionManager::serializeEncryptedConnection(const uint8_t *peerMac)
|
||||
{
|
||||
String serializedConnection(emptyString);
|
||||
|
||||
EncryptedConnectionLog *encryptedConnection = nullptr;
|
||||
|
||||
if(peerMac)
|
||||
encryptedConnection = getEncryptedConnection(peerMac);
|
||||
|
||||
if(encryptedConnection)
|
||||
serializedConnection = encryptedConnection->serialize();
|
||||
|
||||
return serializedConnection;
|
||||
}
|
||||
|
||||
String EspnowConnectionManager::serializeEncryptedConnection(const uint32_t connectionIndex)
|
||||
{
|
||||
String serializedConnection(emptyString);
|
||||
|
||||
if(EncryptedConnectionLog *encryptedConnection = getEncryptedConnection(connectionIndex))
|
||||
serializedConnection = encryptedConnection->serialize();
|
||||
|
||||
return serializedConnection;
|
||||
}
|
||||
|
||||
void EspnowConnectionManager::handlePostponedRemovals()
|
||||
{
|
||||
MutexTracker mutexTracker(EspnowTransmitter::captureEspnowTransmissionMutex());
|
||||
if(!mutexTracker.mutexCaptured())
|
||||
{
|
||||
assert(false && String(F("ERROR! Transmission in progress. Don't call handlePostponedRemovals from callbacks as this may corrupt program state! Aborting.")));
|
||||
return;
|
||||
}
|
||||
|
||||
if(EncryptedConnectionLog::newRemovalsScheduled())
|
||||
{
|
||||
updateTemporaryEncryptedConnections(true);
|
||||
}
|
||||
}
|
||||
|
||||
void EspnowConnectionManager::updateTemporaryEncryptedConnections(const bool scheduledRemovalOnly)
|
||||
{
|
||||
EncryptedConnectionLog::clearSoonestExpiringConnectionTracker();
|
||||
|
||||
for(auto connectionIterator = encryptedConnections().begin(); connectionIterator != encryptedConnections().end(); )
|
||||
{
|
||||
if(auto timeTrackerPointer = connectionIterator->temporary())
|
||||
{
|
||||
if(timeTrackerPointer->expired() && (!scheduledRemovalOnly || connectionIterator->removalScheduled()))
|
||||
{
|
||||
uint8_t macArray[6] = { 0 };
|
||||
removeEncryptedConnectionUnprotected(connectionIterator->getEncryptedPeerMac(macArray), &connectionIterator);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
EncryptedConnectionLog::updateSoonestExpiringConnectionTracker(timeTrackerPointer->remainingDuration());
|
||||
}
|
||||
}
|
||||
assert(!connectionIterator->removalScheduled()); // timeTracker should always exist and be expired if removal is scheduled.
|
||||
|
||||
++connectionIterator;
|
||||
}
|
||||
|
||||
EncryptedConnectionLog::setNewRemovalsScheduled(false);
|
||||
}
|
||||
|
||||
uint64_t EspnowConnectionManager::generateMessageID(const EncryptedConnectionLog *encryptedConnection)
|
||||
{
|
||||
if(encryptedConnection)
|
||||
{
|
||||
return encryptedConnection->getOwnSessionKey();
|
||||
}
|
||||
|
||||
return _unsynchronizedMessageID++;
|
||||
}
|
Reference in New Issue
Block a user