From d2ae082403226e65e199f2d633d2fa5a577d3598 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Wed, 16 Nov 2022 11:43:39 -0500 Subject: [PATCH] Feature/common storage class (#23409) * Moved structures from group data that could be re-used in scenes in a comon location: PersistentData.h * Refactored the name of Iterator class to CommonIterator Co-authored-by: Andrei Litvin <andy314@gmail.com> --- src/credentials/GroupDataProvider.h | 39 +---- src/credentials/GroupDataProviderImpl.cpp | 154 +++---------------- src/lib/support/CommonIterator.h | 55 +++++++ src/lib/support/CommonPersistentData.h | 92 +++++++++++ src/lib/support/DefaultStorageKeyAllocator.h | 4 +- src/lib/support/PersistentData.h | 91 +++++++++++ 6 files changed, 268 insertions(+), 167 deletions(-) create mode 100644 src/lib/support/CommonIterator.h create mode 100644 src/lib/support/CommonPersistentData.h create mode 100644 src/lib/support/PersistentData.h diff --git a/src/credentials/GroupDataProvider.h b/src/credentials/GroupDataProvider.h index a782805af4d5d3..9b694d82c3a7a6 100644 --- a/src/credentials/GroupDataProvider.h +++ b/src/credentials/GroupDataProvider.h @@ -25,6 +25,7 @@ #include <crypto/CHIPCryptoPAL.h> #include <lib/core/CHIPError.h> #include <lib/support/CHIPMemString.h> +#include <lib/support/CommonIterator.h> namespace chip { namespace Credentials { @@ -186,39 +187,11 @@ class GroupDataProvider virtual void OnGroupRemoved(FabricIndex fabric_index, const GroupInfo & old_group) = 0; }; - /** - * Template used to iterate the stored group data - */ - template <typename T> - class Iterator - { - public: - virtual ~Iterator() = default; - /** - * @retval The number of entries in total that will be iterated. - */ - virtual size_t Count() = 0; - /** - * @param[out] item Value associated with the next element in the iteration. - * @retval true if the next entry is successfully retrieved. - * @retval false if no more entries can be found. - */ - virtual bool Next(T & item) = 0; - /** - * Release the memory allocated by this iterator. - * Must be called before the pointer goes out of scope. - */ - virtual void Release() = 0; - - protected: - Iterator() = default; - }; - - using GroupInfoIterator = Iterator<GroupInfo>; - using GroupKeyIterator = Iterator<GroupKey>; - using EndpointIterator = Iterator<GroupEndpoint>; - using KeySetIterator = Iterator<KeySet>; - using GroupSessionIterator = Iterator<GroupSession>; + using GroupInfoIterator = CommonIterator<GroupInfo>; + using GroupKeyIterator = CommonIterator<GroupKey>; + using EndpointIterator = CommonIterator<GroupEndpoint>; + using KeySetIterator = CommonIterator<KeySet>; + using GroupSessionIterator = CommonIterator<GroupSession>; GroupDataProvider(uint16_t maxGroupsPerFabric = CHIP_CONFIG_MAX_GROUPS_PER_FABRIC, uint16_t maxGroupKeysPerFabric = CHIP_CONFIG_MAX_GROUP_KEYS_PER_FABRIC) : diff --git a/src/credentials/GroupDataProviderImpl.cpp b/src/credentials/GroupDataProviderImpl.cpp index 180d5cbf35b742..87eb9d04d6ee4b 100644 --- a/src/credentials/GroupDataProviderImpl.cpp +++ b/src/credentials/GroupDataProviderImpl.cpp @@ -18,10 +18,11 @@ #include <crypto/CHIPCryptoPAL.h> #include <lib/core/CHIPTLV.h> #include <lib/support/CodeUtils.h> +#include <lib/support/CommonPersistentData.h> #include <lib/support/DefaultStorageKeyAllocator.h> +#include <lib/support/PersistentData.h> #include <lib/support/Pool.h> #include <stdlib.h> -#include <string.h> namespace chip { namespace Credentials { @@ -32,69 +33,9 @@ using GroupEndpoint = GroupDataProvider::GroupEndpoint; using EpochKey = GroupDataProvider::EpochKey; using KeySet = GroupDataProvider::KeySet; using GroupSession = GroupDataProvider::GroupSession; +using FabricList = CommonPersistentData::FabricList; -static constexpr size_t kPersistentBufferMax = 128; - -template <size_t kMaxSerializedSize> -struct PersistentData -{ - virtual ~PersistentData() = default; - - virtual CHIP_ERROR UpdateKey(StorageKeyName & key) = 0; - virtual CHIP_ERROR Serialize(TLV::TLVWriter & writer) const = 0; - virtual CHIP_ERROR Deserialize(TLV::TLVReader & reader) = 0; - virtual void Clear() = 0; - - virtual CHIP_ERROR Save(PersistentStorageDelegate * storage) - { - VerifyOrReturnError(nullptr != storage, CHIP_ERROR_INVALID_ARGUMENT); - - uint8_t buffer[kMaxSerializedSize] = { 0 }; - StorageKeyName key = StorageKeyName::Uninitialized(); - ReturnErrorOnFailure(UpdateKey(key)); - - // Serialize the data - TLV::TLVWriter writer; - writer.Init(buffer, sizeof(buffer)); - ReturnErrorOnFailure(Serialize(writer)); - - // Save serialized data - return storage->SyncSetKeyValue(key.KeyName(), buffer, static_cast<uint16_t>(writer.GetLengthWritten())); - } - - CHIP_ERROR Load(PersistentStorageDelegate * storage) - { - VerifyOrReturnError(nullptr != storage, CHIP_ERROR_INVALID_ARGUMENT); - - uint8_t buffer[kMaxSerializedSize] = { 0 }; - StorageKeyName key = StorageKeyName::Uninitialized(); - - // Set data to defaults - Clear(); - ReturnErrorOnFailure(UpdateKey(key)); - - // Load the serialized data - uint16_t size = static_cast<uint16_t>(sizeof(buffer)); - CHIP_ERROR err = storage->SyncGetKeyValue(key.KeyName(), buffer, size); - VerifyOrReturnError(CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND != err, CHIP_ERROR_NOT_FOUND); - ReturnErrorOnFailure(err); - - // Decode serialized data - TLV::TLVReader reader; - reader.Init(buffer, size); - return Deserialize(reader); - } - - virtual CHIP_ERROR Delete(PersistentStorageDelegate * storage) - { - VerifyOrReturnError(nullptr != storage, CHIP_ERROR_INVALID_ARGUMENT); - - StorageKeyName key = StorageKeyName::Uninitialized(); - ReturnErrorOnFailure(UpdateKey(key)); - - return storage->SyncDeleteKeyValue(key.KeyName()); - } -}; +constexpr size_t kPersistentBufferMax = 128; struct LinkedData : public PersistentData<kPersistentBufferMax> { @@ -110,59 +51,6 @@ struct LinkedData : public PersistentData<kPersistentBufferMax> bool first = true; }; -struct FabricList : public PersistentData<kPersistentBufferMax> -{ - static constexpr TLV::Tag TagFirstFabric() { return TLV::ContextTag(1); } - static constexpr TLV::Tag TagFabricCount() { return TLV::ContextTag(2); } - - chip::FabricIndex first_fabric = kUndefinedFabricIndex; - uint8_t fabric_count = 0; - - FabricList() = default; - FabricList(chip::FabricIndex first) : first_fabric(first), fabric_count(1) {} - - CHIP_ERROR UpdateKey(StorageKeyName & key) override - { - key = DefaultStorageKeyAllocator::GroupFabricList(); - return CHIP_NO_ERROR; - } - - void Clear() override - { - first_fabric = kUndefinedFabricIndex; - fabric_count = 0; - } - - CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override - { - TLV::TLVType container; - ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container)); - - ReturnErrorOnFailure(writer.Put(TagFirstFabric(), static_cast<uint16_t>(first_fabric))); - ReturnErrorOnFailure(writer.Put(TagFabricCount(), static_cast<uint16_t>(fabric_count))); - - return writer.EndContainer(container); - } - - CHIP_ERROR Deserialize(TLV::TLVReader & reader) override - { - ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag())); - VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL); - - TLV::TLVType container; - ReturnErrorOnFailure(reader.EnterContainer(container)); - - // first_fabric - ReturnErrorOnFailure(reader.Next(TagFirstFabric())); - ReturnErrorOnFailure(reader.Get(first_fabric)); - // fabric_count - ReturnErrorOnFailure(reader.Next(TagFabricCount())); - ReturnErrorOnFailure(reader.Get(fabric_count)); - - return reader.ExitContainer(container); - } -}; - struct FabricData : public PersistentData<kPersistentBufferMax> { static constexpr TLV::Tag TagFirstGroup() { return TLV::ContextTag(1); } @@ -257,15 +145,15 @@ struct FabricData : public PersistentData<kPersistentBufferMax> if (CHIP_ERROR_NOT_FOUND == err) { // New fabric list - fabric_list.first_fabric = fabric_index; - fabric_list.fabric_count = 1; + fabric_list.first_entry = fabric_index; + fabric_list.entry_count = 1; return fabric_list.Save(storage); } ReturnErrorOnFailure(err); // Existing fabric list, search for existing entry - FabricData fabric(fabric_list.first_fabric); - for (size_t i = 0; i < fabric_list.fabric_count; i++) + FabricData fabric(fabric_list.first_entry); + for (size_t i = 0; i < fabric_list.entry_count; i++) { err = fabric.Load(storage); if (CHIP_NO_ERROR != err) @@ -280,9 +168,9 @@ struct FabricData : public PersistentData<kPersistentBufferMax> fabric.fabric_index = fabric.next; } // Add this fabric to the fabric list - this->next = fabric_list.first_fabric; - fabric_list.first_fabric = this->fabric_index; - fabric_list.fabric_count++; + this->next = fabric_list.first_entry; + fabric_list.first_entry = this->fabric_index; + fabric_list.entry_count++; return fabric_list.Save(storage); } @@ -294,10 +182,10 @@ struct FabricData : public PersistentData<kPersistentBufferMax> VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err); // Existing fabric list, search for existing entry - FabricData fabric(fabric_list.first_fabric); + FabricData fabric(fabric_list.first_entry); FabricData prev; - for (size_t i = 0; i < fabric_list.fabric_count; i++) + for (size_t i = 0; i < fabric_list.entry_count; i++) { err = fabric.Load(storage); if (CHIP_NO_ERROR != err) @@ -310,7 +198,7 @@ struct FabricData : public PersistentData<kPersistentBufferMax> if (i == 0) { // Remove first fabric - fabric_list.first_fabric = this->next; + fabric_list.first_entry = this->next; } else { @@ -318,8 +206,8 @@ struct FabricData : public PersistentData<kPersistentBufferMax> prev.next = this->next; ReturnErrorOnFailure(prev.Save(storage)); } - VerifyOrReturnError(fabric_list.fabric_count > 0, CHIP_ERROR_INTERNAL); - fabric_list.fabric_count--; + VerifyOrReturnError(fabric_list.entry_count > 0, CHIP_ERROR_INTERNAL); + fabric_list.entry_count--; return fabric_list.Save(storage); } prev = fabric; @@ -336,9 +224,9 @@ struct FabricData : public PersistentData<kPersistentBufferMax> ReturnErrorOnFailure(fabric_list.Load(storage)); // Existing fabric list, search for existing entry - FabricData fabric(fabric_list.first_fabric); + FabricData fabric(fabric_list.first_entry); - for (size_t i = 0; i < fabric_list.fabric_count; i++) + for (size_t i = 0; i < fabric_list.entry_count; i++) { ReturnErrorOnFailure(fabric.Load(storage)); if (fabric.fabric_index == this->fabric_index) @@ -1892,10 +1780,10 @@ GroupDataProviderImpl::GroupSessionIteratorImpl::GroupSessionIteratorImpl(GroupD { FabricList fabric_list; ReturnOnFailure(fabric_list.Load(provider.mStorage)); - mFirstFabric = fabric_list.first_fabric; - mFabric = fabric_list.first_fabric; + mFirstFabric = fabric_list.first_entry; + mFabric = fabric_list.first_entry; mFabricCount = 0; - mFabricTotal = fabric_list.fabric_count; + mFabricTotal = fabric_list.entry_count; mMapCount = 0; mFirstMap = true; } diff --git a/src/lib/support/CommonIterator.h b/src/lib/support/CommonIterator.h new file mode 100644 index 00000000000000..689625aa292a94 --- /dev/null +++ b/src/lib/support/CommonIterator.h @@ -0,0 +1,55 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Contains a standard iterator class. + */ + +#pragma once + +namespace chip { + +/** + * Template used to generate a custom iterator + */ +template <typename T> +class CommonIterator +{ +public: + virtual ~CommonIterator() = default; + /** + * @retval The number of entries in total that will be iterated. + */ + virtual size_t Count() = 0; + /** + * @param[out] item Value associated with the next element in the iteration. + * @retval true if the next entry is successfully retrieved. + * @retval false if no more entries can be found. + */ + virtual bool Next(T & item) = 0; + /** + * Release the memory allocated by this iterator. + * Must be called before the iterator goes out of scope in the iterator was dynamically allocated. + */ + virtual void Release() = 0; + +protected: + CommonIterator() = default; +}; + +} // namespace chip diff --git a/src/lib/support/CommonPersistentData.h b/src/lib/support/CommonPersistentData.h new file mode 100644 index 00000000000000..24c3e9a0354ce4 --- /dev/null +++ b/src/lib/support/CommonPersistentData.h @@ -0,0 +1,92 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Contains a class handling creation of linked list of stored persistent data. + */ + +#include <lib/core/DataModelTypes.h> +#include <lib/support/PersistentData.h> + +namespace chip { +namespace CommonPersistentData { + +constexpr uint8_t kdefaultUndefinedEntry = 0; + +/// @brief Generic class to implement storage of a list persistently +/// @tparam EntryType : Type of entry depends on the stored data +/// @tparam kMaxSerializedSize : inherited from PersistentData class +template <typename EntryType, size_t kMaxSerializedSize> +struct StoredDataList : public PersistentData<kMaxSerializedSize> +{ + static constexpr TLV::Tag TagFirstEntry() { return TLV::ContextTag(1); } + static constexpr TLV::Tag TagEntryCount() { return TLV::ContextTag(2); } + + EntryType first_entry = kdefaultUndefinedEntry; + uint16_t entry_count = 0; + + StoredDataList() = default; + StoredDataList(EntryType first) : first_entry(first), entry_count(1) {} + + CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override + { + TLV::TLVType container; + ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container)); + + ReturnErrorOnFailure(writer.Put(TagFirstEntry(), static_cast<uint16_t>(first_entry))); + ReturnErrorOnFailure(writer.Put(TagEntryCount(), static_cast<uint16_t>(entry_count))); + + return writer.EndContainer(container); + } + + CHIP_ERROR Deserialize(TLV::TLVReader & reader) override + { + ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag())); + VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL); + + TLV::TLVType container; + ReturnErrorOnFailure(reader.EnterContainer(container)); + + // first_entry + ReturnErrorOnFailure(reader.Next(TagFirstEntry())); + ReturnErrorOnFailure(reader.Get(first_entry)); + // entry_count + ReturnErrorOnFailure(reader.Next(TagEntryCount())); + ReturnErrorOnFailure(reader.Get(entry_count)); + + return reader.ExitContainer(container); + } +}; + +constexpr size_t kPersistentFabricBufferMax = 32; +struct FabricList : StoredDataList<FabricIndex, kPersistentFabricBufferMax> +{ + CHIP_ERROR UpdateKey(StorageKeyName & key) override + { + key = DefaultStorageKeyAllocator::FabricList(); + return CHIP_NO_ERROR; + } + + void Clear() override + { + first_entry = kUndefinedFabricIndex; + entry_count = 0; + } +}; +} // namespace CommonPersistentData +} // namespace chip diff --git a/src/lib/support/DefaultStorageKeyAllocator.h b/src/lib/support/DefaultStorageKeyAllocator.h index 6a4b906c2426b8..dd7098ecf607f9 100644 --- a/src/lib/support/DefaultStorageKeyAllocator.h +++ b/src/lib/support/DefaultStorageKeyAllocator.h @@ -102,6 +102,9 @@ class DefaultStorageKeyAllocator static StorageKeyName FabricMetadata(FabricIndex fabric) { return StorageKeyName::Formatted("f/%x/m", fabric); } static StorageKeyName FabricOpKey(FabricIndex fabric) { return StorageKeyName::Formatted("f/%x/o", fabric); } + // Fabric List + static StorageKeyName FabricList() { return StorageKeyName::FromConst("g/fl"); } + // Fail-safe handling static StorageKeyName FailSafeCommitMarkerKey() { return StorageKeyName::FromConst("g/fs/c"); } static StorageKeyName FailSafeNetworkConfig() { return StorageKeyName::FromConst("g/fs/n"); } @@ -144,7 +147,6 @@ class DefaultStorageKeyAllocator // Group Data Provider // List of fabric indices that have endpoint-to-group associations defined. - static StorageKeyName GroupFabricList() { return StorageKeyName::FromConst("g/gfl"); } static StorageKeyName FabricGroups(chip::FabricIndex fabric) { return StorageKeyName::Formatted("f/%x/g", fabric); } static StorageKeyName FabricGroup(chip::FabricIndex fabric, chip::GroupId group) { diff --git a/src/lib/support/PersistentData.h b/src/lib/support/PersistentData.h new file mode 100644 index 00000000000000..b1eceaf6a3bd4d --- /dev/null +++ b/src/lib/support/PersistentData.h @@ -0,0 +1,91 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include <lib/core/CHIPPersistentStorageDelegate.h> +#include <lib/core/CHIPTLV.h> +#include <lib/support/DefaultStorageKeyAllocator.h> + +namespace chip { + +/// @brief Interface to Persistent Storage Delegate allowing storage of data of variable size such as TLV. +/// @tparam kMaxSerializedSize size of the buffer necessary to retrieve an entry from the storage. Varies with the type of data +/// stored. Will be allocated on the stack so the implementation needs to be aware of this when choosing this value. +template <size_t kMaxSerializedSize> +struct PersistentData +{ + virtual ~PersistentData() = default; + + virtual CHIP_ERROR UpdateKey(StorageKeyName & key) = 0; + virtual CHIP_ERROR Serialize(TLV::TLVWriter & writer) const = 0; + virtual CHIP_ERROR Deserialize(TLV::TLVReader & reader) = 0; + virtual void Clear() = 0; + + virtual CHIP_ERROR Save(PersistentStorageDelegate * storage) + { + VerifyOrReturnError(nullptr != storage, CHIP_ERROR_INVALID_ARGUMENT); + + uint8_t buffer[kMaxSerializedSize] = { 0 }; + StorageKeyName key = StorageKeyName::Uninitialized(); + ReturnErrorOnFailure(UpdateKey(key)); + + // Serialize the data + TLV::TLVWriter writer; + writer.Init(buffer, sizeof(buffer)); + ReturnErrorOnFailure(Serialize(writer)); + + // Save serialized data + return storage->SyncSetKeyValue(key.KeyName(), buffer, static_cast<uint16_t>(writer.GetLengthWritten())); + } + + CHIP_ERROR Load(PersistentStorageDelegate * storage) + { + VerifyOrReturnError(nullptr != storage, CHIP_ERROR_INVALID_ARGUMENT); + + uint8_t buffer[kMaxSerializedSize] = { 0 }; + StorageKeyName key = StorageKeyName::Uninitialized(); + + // Set data to defaults + Clear(); + + // Update storage key + ReturnErrorOnFailure(UpdateKey(key)); + + // Load the serialized data + uint16_t size = static_cast<uint16_t>(sizeof(buffer)); + CHIP_ERROR err = storage->SyncGetKeyValue(key.KeyName(), buffer, size); + VerifyOrReturnError(CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND != err, CHIP_ERROR_NOT_FOUND); + ReturnErrorOnFailure(err); + + // Decode serialized data + TLV::TLVReader reader; + reader.Init(buffer, size); + return Deserialize(reader); + } + + virtual CHIP_ERROR Delete(PersistentStorageDelegate * storage) + { + VerifyOrReturnError(nullptr != storage, CHIP_ERROR_INVALID_ARGUMENT); + + StorageKeyName key = StorageKeyName::Uninitialized(); + ReturnErrorOnFailure(UpdateKey(key)); + + return storage->SyncDeleteKeyValue(key.KeyName()); + } +}; + +} // namespace chip