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>
diff --git a/src/credentials/GroupDataProvider.h b/src/credentials/GroupDataProvider.h
index a782805..9b694d8 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 @@
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 180d5cb..87eb9d0 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 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 @@
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 @@
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 @@
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 @@
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 @@
if (i == 0)
{
// Remove first fabric
- fabric_list.first_fabric = this->next;
+ fabric_list.first_entry = this->next;
}
else
{
@@ -318,8 +206,8 @@
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 @@
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 @@
{
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 0000000..689625a
--- /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 0000000..24c3e9a
--- /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 6a4b906..dd7098e 100644
--- a/src/lib/support/DefaultStorageKeyAllocator.h
+++ b/src/lib/support/DefaultStorageKeyAllocator.h
@@ -102,6 +102,9 @@
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 @@
// 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 0000000..b1eceaf
--- /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