Matter SDK Coverage Report
Current view: top level - app - SimpleSubscriptionResumptionStorage.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 95.2 % 210 200
Test Date: 2025-01-17 19:00:11 Functions: 100.0 % 14 14

            Line data    Source code
       1              : /*
       2              :  *    Copyright (c) 2023 Project CHIP Authors
       3              :  *    All rights reserved.
       4              :  *
       5              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       6              :  *    you may not use this file except in compliance with the License.
       7              :  *    You may obtain a copy of the License at
       8              :  *
       9              :  *        http://www.apache.org/licenses/LICENSE-2.0
      10              :  *
      11              :  *    Unless required by applicable law or agreed to in writing, software
      12              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      13              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14              :  *    See the License for the specific language governing permissions and
      15              :  *    limitations under the License.
      16              :  */
      17              : 
      18              : /**
      19              :  *    @file
      20              :  *      This file defines a basic implementation of SubscriptionResumptionStorage that
      21              :  *      persists subscriptions in a flat list in TLV.
      22              :  */
      23              : 
      24              : #include <app/SimpleSubscriptionResumptionStorage.h>
      25              : 
      26              : #include <lib/support/Base64.h>
      27              : #include <lib/support/CodeUtils.h>
      28              : #include <lib/support/SafeInt.h>
      29              : #include <lib/support/logging/CHIPLogging.h>
      30              : 
      31              : namespace chip {
      32              : namespace app {
      33              : 
      34              : constexpr TLV::Tag SimpleSubscriptionResumptionStorage::kPeerNodeIdTag;
      35              : constexpr TLV::Tag SimpleSubscriptionResumptionStorage::kFabricIndexTag;
      36              : constexpr TLV::Tag SimpleSubscriptionResumptionStorage::kSubscriptionIdTag;
      37              : constexpr TLV::Tag SimpleSubscriptionResumptionStorage::kMinIntervalTag;
      38              : constexpr TLV::Tag SimpleSubscriptionResumptionStorage::kMaxIntervalTag;
      39              : constexpr TLV::Tag SimpleSubscriptionResumptionStorage::kFabricFilteredTag;
      40              : constexpr TLV::Tag SimpleSubscriptionResumptionStorage::kAttributePathsListTag;
      41              : constexpr TLV::Tag SimpleSubscriptionResumptionStorage::kEventPathsListTag;
      42              : constexpr TLV::Tag SimpleSubscriptionResumptionStorage::kAttributePathTag;
      43              : constexpr TLV::Tag SimpleSubscriptionResumptionStorage::kEventPathTag;
      44              : constexpr TLV::Tag SimpleSubscriptionResumptionStorage::kEndpointIdTag;
      45              : constexpr TLV::Tag SimpleSubscriptionResumptionStorage::kClusterIdTag;
      46              : constexpr TLV::Tag SimpleSubscriptionResumptionStorage::kAttributeIdTag;
      47              : constexpr TLV::Tag SimpleSubscriptionResumptionStorage::kEventIdTag;
      48              : constexpr TLV::Tag SimpleSubscriptionResumptionStorage::kEventPathTypeTag;
      49              : constexpr TLV::Tag SimpleSubscriptionResumptionStorage::kResumptionRetriesTag;
      50              : 
      51           15 : SimpleSubscriptionResumptionStorage::SimpleSubscriptionInfoIterator::SimpleSubscriptionInfoIterator(
      52           15 :     SimpleSubscriptionResumptionStorage & storage) :
      53           15 :     mStorage(storage)
      54              : {
      55           15 :     mNextIndex = 0;
      56           15 : }
      57              : 
      58           10 : size_t SimpleSubscriptionResumptionStorage::SimpleSubscriptionInfoIterator::Count()
      59              : {
      60           10 :     return static_cast<size_t>(mStorage.Count());
      61              : }
      62              : 
      63           46 : bool SimpleSubscriptionResumptionStorage::SimpleSubscriptionInfoIterator::Next(SubscriptionInfo & output)
      64              : {
      65          544 :     for (; mNextIndex < CHIP_IM_MAX_NUM_SUBSCRIPTIONS; mNextIndex++)
      66              :     {
      67          533 :         CHIP_ERROR err = mStorage.Load(mNextIndex, output);
      68          533 :         if (err == CHIP_NO_ERROR)
      69              :         {
      70              :             // increment index for the next call
      71           35 :             mNextIndex++;
      72           35 :             return true;
      73              :         }
      74              : 
      75          498 :         if (err != CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND)
      76              :         {
      77            2 :             ChipLogError(DataManagement, "Failed to load subscription at index %u error %" CHIP_ERROR_FORMAT,
      78              :                          static_cast<unsigned>(mNextIndex), err.Format());
      79            2 :             mStorage.Delete(mNextIndex);
      80              :         }
      81              :     }
      82              : 
      83           11 :     return false;
      84              : }
      85              : 
      86           15 : void SimpleSubscriptionResumptionStorage::SimpleSubscriptionInfoIterator::Release()
      87              : {
      88           15 :     mStorage.mSubscriptionInfoIterators.ReleaseObject(this);
      89           15 : }
      90              : 
      91            8 : CHIP_ERROR SimpleSubscriptionResumptionStorage::Init(PersistentStorageDelegate * storage)
      92              : {
      93            8 :     VerifyOrReturnError(storage != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
      94            8 :     mStorage = storage;
      95              : 
      96              :     uint16_t countMax;
      97            8 :     uint16_t len = sizeof(countMax);
      98              :     CHIP_ERROR err =
      99            8 :         mStorage->SyncGetKeyValue(DefaultStorageKeyAllocator::SubscriptionResumptionMaxCount().KeyName(), &countMax, len);
     100              :     // If there's a previous countMax and it's larger than CHIP_IM_MAX_NUM_SUBSCRIPTIONS,
     101              :     // clean up subscriptions beyond the limit
     102            8 :     if ((err == CHIP_NO_ERROR) && (countMax != CHIP_IM_MAX_NUM_SUBSCRIPTIONS))
     103              :     {
     104           49 :         for (uint16_t subscriptionIndex = CHIP_IM_MAX_NUM_SUBSCRIPTIONS; subscriptionIndex < countMax; subscriptionIndex++)
     105              :         {
     106           48 :             Delete(subscriptionIndex);
     107              :         }
     108              :     }
     109              : 
     110              :     // Always save the current CHIP_IM_MAX_NUM_SUBSCRIPTIONS
     111            8 :     uint16_t countMaxToSave = CHIP_IM_MAX_NUM_SUBSCRIPTIONS;
     112            8 :     ReturnErrorOnFailure(mStorage->SyncSetKeyValue(DefaultStorageKeyAllocator::SubscriptionResumptionMaxCount().KeyName(),
     113              :                                                    &countMaxToSave, sizeof(uint16_t)));
     114              : 
     115            8 :     return CHIP_NO_ERROR;
     116              : }
     117              : 
     118           15 : SubscriptionResumptionStorage::SubscriptionInfoIterator * SimpleSubscriptionResumptionStorage::IterateSubscriptions()
     119              : {
     120           15 :     return mSubscriptionInfoIterators.CreateObject(*this);
     121              : }
     122              : 
     123           10 : uint16_t SimpleSubscriptionResumptionStorage::Count()
     124              : {
     125           10 :     uint16_t subscriptionCount = 0;
     126          490 :     for (uint16_t subscriptionIndex = 0; subscriptionIndex < CHIP_IM_MAX_NUM_SUBSCRIPTIONS; subscriptionIndex++)
     127              :     {
     128          480 :         if (mStorage->SyncDoesKeyExist(DefaultStorageKeyAllocator::SubscriptionResumption(subscriptionIndex).KeyName()))
     129              :         {
     130           31 :             subscriptionCount++;
     131              :         }
     132              :     }
     133              : 
     134           10 :     return subscriptionCount;
     135              : }
     136              : 
     137           79 : CHIP_ERROR SimpleSubscriptionResumptionStorage::Delete(uint16_t subscriptionIndex)
     138              : {
     139           79 :     return mStorage->SyncDeleteKeyValue(DefaultStorageKeyAllocator::SubscriptionResumption(subscriptionIndex).KeyName());
     140              : }
     141              : 
     142         2261 : CHIP_ERROR SimpleSubscriptionResumptionStorage::Load(uint16_t subscriptionIndex, SubscriptionInfo & subscriptionInfo)
     143              : {
     144         2261 :     Platform::ScopedMemoryBuffer<uint8_t> backingBuffer;
     145         2261 :     backingBuffer.Calloc(MaxSubscriptionSize());
     146         2261 :     VerifyOrReturnError(backingBuffer.Get() != nullptr, CHIP_ERROR_NO_MEMORY);
     147              : 
     148         2261 :     uint16_t len = static_cast<uint16_t>(MaxSubscriptionSize());
     149         2261 :     ReturnErrorOnFailure(mStorage->SyncGetKeyValue(DefaultStorageKeyAllocator::SubscriptionResumption(subscriptionIndex).KeyName(),
     150              :                                                    backingBuffer.Get(), len));
     151              : 
     152          350 :     TLV::ScopedBufferTLVReader reader(std::move(backingBuffer), len);
     153              : 
     154          350 :     ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag()));
     155              : 
     156              :     TLV::TLVType subscriptionContainerType;
     157          349 :     ReturnErrorOnFailure(reader.EnterContainer(subscriptionContainerType));
     158              : 
     159              :     // Node ID
     160          349 :     ReturnErrorOnFailure(reader.Next(kPeerNodeIdTag));
     161          349 :     ReturnErrorOnFailure(reader.Get(subscriptionInfo.mNodeId));
     162              : 
     163              :     // Fabric index
     164          349 :     ReturnErrorOnFailure(reader.Next(kFabricIndexTag));
     165          349 :     ReturnErrorOnFailure(reader.Get(subscriptionInfo.mFabricIndex));
     166              : 
     167              :     // Subscription ID
     168          349 :     ReturnErrorOnFailure(reader.Next(kSubscriptionIdTag));
     169          349 :     ReturnErrorOnFailure(reader.Get(subscriptionInfo.mSubscriptionId));
     170              : 
     171              :     // Min interval
     172          349 :     ReturnErrorOnFailure(reader.Next(kMinIntervalTag));
     173          349 :     ReturnErrorOnFailure(reader.Get(subscriptionInfo.mMinInterval));
     174              : 
     175              :     // Max interval
     176          349 :     ReturnErrorOnFailure(reader.Next(kMaxIntervalTag));
     177          349 :     ReturnErrorOnFailure(reader.Get(subscriptionInfo.mMaxInterval));
     178              : 
     179              :     // Fabric filtered boolean
     180          349 :     ReturnErrorOnFailure(reader.Next(kFabricFilteredTag));
     181          349 :     ReturnErrorOnFailure(reader.Get(subscriptionInfo.mFabricFiltered));
     182              : 
     183              :     // Attribute Paths
     184          349 :     ReturnErrorOnFailure(reader.Next(TLV::kTLVType_List, kAttributePathsListTag));
     185              :     TLV::TLVType attributesListType;
     186          349 :     ReturnErrorOnFailure(reader.EnterContainer(attributesListType));
     187              : 
     188          349 :     size_t pathCount = 0;
     189          349 :     ReturnErrorOnFailure(reader.CountRemainingInContainer(&pathCount));
     190              : 
     191              :     // If a stack struct is being reused to iterate, free the previous paths ScopedMemoryBuffer
     192          349 :     subscriptionInfo.mAttributePaths.Free();
     193          349 :     if (pathCount)
     194              :     {
     195           10 :         subscriptionInfo.mAttributePaths.Calloc(pathCount);
     196           10 :         VerifyOrReturnError(subscriptionInfo.mAttributePaths.Get() != nullptr, CHIP_ERROR_NO_MEMORY);
     197           30 :         for (size_t pathIndex = 0; pathIndex < pathCount; pathIndex++)
     198              :         {
     199           20 :             ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, kAttributePathTag));
     200              :             TLV::TLVType attributeContainerType;
     201           20 :             ReturnErrorOnFailure(reader.EnterContainer(attributeContainerType));
     202              : 
     203           20 :             ReturnErrorOnFailure(reader.Next(kEndpointIdTag));
     204           20 :             ReturnErrorOnFailure(reader.Get(subscriptionInfo.mAttributePaths[pathIndex].mEndpointId));
     205              : 
     206           20 :             ReturnErrorOnFailure(reader.Next(kClusterIdTag));
     207           20 :             ReturnErrorOnFailure(reader.Get(subscriptionInfo.mAttributePaths[pathIndex].mClusterId));
     208              : 
     209           20 :             ReturnErrorOnFailure(reader.Next(kAttributeIdTag));
     210           20 :             ReturnErrorOnFailure(reader.Get(subscriptionInfo.mAttributePaths[pathIndex].mAttributeId));
     211              : 
     212           20 :             ReturnErrorOnFailure(reader.ExitContainer(attributeContainerType));
     213              :         }
     214              :     }
     215          349 :     ReturnErrorOnFailure(reader.ExitContainer(attributesListType));
     216              : 
     217              :     // Event Paths
     218          349 :     ReturnErrorOnFailure(reader.Next(TLV::kTLVType_List, kEventPathsListTag));
     219              :     TLV::TLVType eventsListType;
     220          349 :     ReturnErrorOnFailure(reader.EnterContainer(eventsListType));
     221              : 
     222          349 :     ReturnErrorOnFailure(reader.CountRemainingInContainer(&pathCount));
     223              : 
     224              :     // If a stack struct is being reused to iterate, free the previous paths ScopedMemoryBuffer
     225          349 :     subscriptionInfo.mEventPaths.Free();
     226          349 :     if (pathCount)
     227              :     {
     228            9 :         subscriptionInfo.mEventPaths.Calloc(pathCount);
     229            9 :         VerifyOrReturnError(subscriptionInfo.mEventPaths.Get() != nullptr, CHIP_ERROR_NO_MEMORY);
     230           27 :         for (size_t pathIndex = 0; pathIndex < pathCount; pathIndex++)
     231              :         {
     232           18 :             ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, kEventPathTag));
     233              :             TLV::TLVType eventContainerType;
     234           18 :             ReturnErrorOnFailure(reader.EnterContainer(eventContainerType));
     235              : 
     236              :             EventPathType eventPathType;
     237           18 :             ReturnErrorOnFailure(reader.Next(kEventPathTypeTag));
     238           18 :             ReturnErrorOnFailure(reader.Get(eventPathType));
     239              : 
     240           18 :             subscriptionInfo.mEventPaths[pathIndex].mIsUrgentEvent = (eventPathType == EventPathType::kUrgent);
     241              : 
     242           18 :             ReturnErrorOnFailure(reader.Next(kEndpointIdTag));
     243           18 :             ReturnErrorOnFailure(reader.Get(subscriptionInfo.mEventPaths[pathIndex].mEndpointId));
     244              : 
     245           18 :             ReturnErrorOnFailure(reader.Next(kClusterIdTag));
     246           18 :             ReturnErrorOnFailure(reader.Get(subscriptionInfo.mEventPaths[pathIndex].mClusterId));
     247              : 
     248           18 :             ReturnErrorOnFailure(reader.Next(kEventIdTag));
     249           18 :             ReturnErrorOnFailure(reader.Get(subscriptionInfo.mEventPaths[pathIndex].mEventId));
     250              : 
     251           18 :             ReturnErrorOnFailure(reader.ExitContainer(eventContainerType));
     252              :         }
     253              :     }
     254          349 :     ReturnErrorOnFailure(reader.ExitContainer(eventsListType));
     255              : 
     256              : #if CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION
     257              :     // If the reader cannot get resumption retries, set it to 0 for subscriptionInfo
     258          349 :     if (reader.Next(kResumptionRetriesTag) == CHIP_NO_ERROR)
     259              :     {
     260          349 :         ReturnErrorOnFailure(reader.Get(subscriptionInfo.mResumptionRetries));
     261              :     }
     262              :     else
     263              :     {
     264            0 :         subscriptionInfo.mResumptionRetries = 0;
     265              :     }
     266              : #endif // CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION
     267              : 
     268          349 :     ReturnErrorOnFailure(reader.ExitContainer(subscriptionContainerType));
     269              : 
     270          349 :     return CHIP_NO_ERROR;
     271         2261 : }
     272              : 
     273           31 : CHIP_ERROR SimpleSubscriptionResumptionStorage::Save(TLV::TLVWriter & writer, SubscriptionInfo & subscriptionInfo)
     274              : {
     275              :     TLV::TLVType subscriptionContainerType;
     276           31 :     ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, subscriptionContainerType));
     277           31 :     ReturnErrorOnFailure(writer.Put(kPeerNodeIdTag, subscriptionInfo.mNodeId));
     278           31 :     ReturnErrorOnFailure(writer.Put(kFabricIndexTag, subscriptionInfo.mFabricIndex));
     279           31 :     ReturnErrorOnFailure(writer.Put(kSubscriptionIdTag, subscriptionInfo.mSubscriptionId));
     280           31 :     ReturnErrorOnFailure(writer.Put(kMinIntervalTag, subscriptionInfo.mMinInterval));
     281           31 :     ReturnErrorOnFailure(writer.Put(kMaxIntervalTag, subscriptionInfo.mMaxInterval));
     282           31 :     ReturnErrorOnFailure(writer.Put(kFabricFilteredTag, subscriptionInfo.mFabricFiltered));
     283              : 
     284              :     // Attribute paths
     285              :     TLV::TLVType attributesListType;
     286           31 :     ReturnErrorOnFailure(writer.StartContainer(kAttributePathsListTag, TLV::kTLVType_List, attributesListType));
     287           39 :     for (size_t pathIndex = 0; pathIndex < subscriptionInfo.mAttributePaths.AllocatedSize(); pathIndex++)
     288              :     {
     289            8 :         TLV::TLVType attributeContainerType = TLV::kTLVType_Structure;
     290            8 :         ReturnErrorOnFailure(writer.StartContainer(kAttributePathTag, TLV::kTLVType_Structure, attributeContainerType));
     291              : 
     292            8 :         ReturnErrorOnFailure(writer.Put(kEndpointIdTag, subscriptionInfo.mAttributePaths[pathIndex].mEndpointId));
     293            8 :         ReturnErrorOnFailure(writer.Put(kClusterIdTag, subscriptionInfo.mAttributePaths[pathIndex].mClusterId));
     294            8 :         ReturnErrorOnFailure(writer.Put(kAttributeIdTag, subscriptionInfo.mAttributePaths[pathIndex].mAttributeId));
     295              : 
     296            8 :         ReturnErrorOnFailure(writer.EndContainer(attributeContainerType));
     297              :     }
     298           31 :     ReturnErrorOnFailure(writer.EndContainer(attributesListType));
     299              : 
     300              :     // Event paths
     301              :     TLV::TLVType eventsListType;
     302           31 :     ReturnErrorOnFailure(writer.StartContainer(kEventPathsListTag, TLV::kTLVType_List, eventsListType));
     303           35 :     for (size_t pathIndex = 0; pathIndex < subscriptionInfo.mEventPaths.AllocatedSize(); pathIndex++)
     304              :     {
     305            4 :         TLV::TLVType eventContainerType = TLV::kTLVType_Structure;
     306            4 :         ReturnErrorOnFailure(writer.StartContainer(kEventPathTag, TLV::kTLVType_Structure, eventContainerType));
     307              : 
     308            4 :         if (subscriptionInfo.mEventPaths[pathIndex].mIsUrgentEvent)
     309              :         {
     310            1 :             ReturnErrorOnFailure(writer.Put(kEventPathTypeTag, EventPathType::kUrgent));
     311              :         }
     312              :         else
     313              :         {
     314            3 :             ReturnErrorOnFailure(writer.Put(kEventPathTypeTag, EventPathType::kNonUrgent));
     315              :         }
     316            4 :         ReturnErrorOnFailure(writer.Put(kEndpointIdTag, subscriptionInfo.mEventPaths[pathIndex].mEndpointId));
     317            4 :         ReturnErrorOnFailure(writer.Put(kClusterIdTag, subscriptionInfo.mEventPaths[pathIndex].mClusterId));
     318            4 :         ReturnErrorOnFailure(writer.Put(kEventIdTag, subscriptionInfo.mEventPaths[pathIndex].mEventId));
     319              : 
     320            4 :         ReturnErrorOnFailure(writer.EndContainer(eventContainerType));
     321              :     }
     322           31 :     ReturnErrorOnFailure(writer.EndContainer(eventsListType));
     323              : #if CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION
     324           31 :     ReturnErrorOnFailure(writer.Put(kResumptionRetriesTag, subscriptionInfo.mResumptionRetries));
     325              : #endif // CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION
     326              : 
     327           31 :     ReturnErrorOnFailure(writer.EndContainer(subscriptionContainerType));
     328              : 
     329           31 :     return CHIP_NO_ERROR;
     330              : }
     331              : 
     332           29 : CHIP_ERROR SimpleSubscriptionResumptionStorage::Save(SubscriptionInfo & subscriptionInfo)
     333              : {
     334              :     // Find empty index or duplicate if exists
     335              :     uint16_t subscriptionIndex;
     336           29 :     uint16_t firstEmptySubscriptionIndex = CHIP_IM_MAX_NUM_SUBSCRIPTIONS; // initialize to out of bounds as "not set"
     337         1421 :     for (subscriptionIndex = 0; subscriptionIndex < CHIP_IM_MAX_NUM_SUBSCRIPTIONS; subscriptionIndex++)
     338              :     {
     339         1392 :         SubscriptionInfo currentSubscriptionInfo;
     340         1392 :         CHIP_ERROR err = Load(subscriptionIndex, currentSubscriptionInfo);
     341              : 
     342              :         // if empty and firstEmptySubscriptionIndex isn't set yet, then mark empty spot
     343         1392 :         if ((firstEmptySubscriptionIndex == CHIP_IM_MAX_NUM_SUBSCRIPTIONS) && (err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND))
     344              :         {
     345           29 :             firstEmptySubscriptionIndex = subscriptionIndex;
     346              :         }
     347              : 
     348              :         // delete duplicate
     349         1392 :         if (err == CHIP_NO_ERROR)
     350              :         {
     351          280 :             if ((subscriptionInfo.mNodeId == currentSubscriptionInfo.mNodeId) &&
     352          276 :                 (subscriptionInfo.mFabricIndex == currentSubscriptionInfo.mFabricIndex) &&
     353          276 :                 (subscriptionInfo.mSubscriptionId == currentSubscriptionInfo.mSubscriptionId))
     354              :             {
     355            0 :                 Delete(subscriptionIndex);
     356              :                 // if duplicate is the first empty spot, then also set it
     357            0 :                 if (firstEmptySubscriptionIndex == CHIP_IM_MAX_NUM_SUBSCRIPTIONS)
     358              :                 {
     359            0 :                     firstEmptySubscriptionIndex = subscriptionIndex;
     360              :                 }
     361              :             }
     362              :         }
     363         1392 :     }
     364              : 
     365              :     // Fail if no empty space
     366           29 :     if (firstEmptySubscriptionIndex == CHIP_IM_MAX_NUM_SUBSCRIPTIONS)
     367              :     {
     368            0 :         return CHIP_ERROR_NO_MEMORY;
     369              :     }
     370              : 
     371              :     // Now construct subscription state and save
     372           29 :     Platform::ScopedMemoryBuffer<uint8_t> backingBuffer;
     373           29 :     backingBuffer.Calloc(MaxSubscriptionSize());
     374           29 :     VerifyOrReturnError(backingBuffer.Get() != nullptr, CHIP_ERROR_NO_MEMORY);
     375              : 
     376           29 :     TLV::ScopedBufferTLVWriter writer(std::move(backingBuffer), MaxSubscriptionSize());
     377              : 
     378           29 :     ReturnErrorOnFailure(Save(writer, subscriptionInfo));
     379              : 
     380           29 :     const auto len = writer.GetLengthWritten();
     381           29 :     VerifyOrReturnError(CanCastTo<uint16_t>(len), CHIP_ERROR_BUFFER_TOO_SMALL);
     382              : 
     383           29 :     writer.Finalize(backingBuffer);
     384              : 
     385           29 :     ReturnErrorOnFailure(
     386              :         mStorage->SyncSetKeyValue(DefaultStorageKeyAllocator::SubscriptionResumption(firstEmptySubscriptionIndex).KeyName(),
     387              :                                   backingBuffer.Get(), static_cast<uint16_t>(len)));
     388              : 
     389           29 :     return CHIP_NO_ERROR;
     390           29 : }
     391              : 
     392            2 : CHIP_ERROR SimpleSubscriptionResumptionStorage::Delete(NodeId nodeId, FabricIndex fabricIndex, SubscriptionId subscriptionId)
     393              : {
     394            2 :     bool subscriptionFound   = false;
     395            2 :     CHIP_ERROR lastDeleteErr = CHIP_NO_ERROR;
     396              : 
     397            2 :     uint16_t remainingSubscriptionsCount = 0;
     398           98 :     for (uint16_t subscriptionIndex = 0; subscriptionIndex < CHIP_IM_MAX_NUM_SUBSCRIPTIONS; subscriptionIndex++)
     399              :     {
     400           96 :         SubscriptionInfo subscriptionInfo;
     401           96 :         CHIP_ERROR err = Load(subscriptionIndex, subscriptionInfo);
     402              : 
     403              :         // delete match
     404           96 :         if (err == CHIP_NO_ERROR)
     405              :         {
     406            5 :             if ((nodeId == subscriptionInfo.mNodeId) && (fabricIndex == subscriptionInfo.mFabricIndex) &&
     407            2 :                 (subscriptionId == subscriptionInfo.mSubscriptionId))
     408              :             {
     409            2 :                 subscriptionFound    = true;
     410            2 :                 CHIP_ERROR deleteErr = Delete(subscriptionIndex);
     411            2 :                 if (deleteErr != CHIP_NO_ERROR)
     412              :                 {
     413            0 :                     lastDeleteErr = deleteErr;
     414              :                 }
     415            2 :             }
     416              :             else
     417              :             {
     418            3 :                 remainingSubscriptionsCount++;
     419              :             }
     420              :         }
     421           96 :     }
     422              : 
     423              :     // if there are no persisted subscriptions, the MaxCount can also be deleted
     424            2 :     if (remainingSubscriptionsCount == 0)
     425              :     {
     426            0 :         DeleteMaxCount();
     427              :     }
     428              : 
     429            2 :     if (lastDeleteErr != CHIP_NO_ERROR)
     430              :     {
     431            0 :         return lastDeleteErr;
     432              :     }
     433              : 
     434            2 :     return subscriptionFound ? CHIP_NO_ERROR : CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND;
     435              : }
     436              : 
     437            3 : CHIP_ERROR SimpleSubscriptionResumptionStorage::DeleteMaxCount()
     438              : {
     439            3 :     return mStorage->SyncDeleteKeyValue(DefaultStorageKeyAllocator::SubscriptionResumptionMaxCount().KeyName());
     440              : }
     441              : 
     442            5 : CHIP_ERROR SimpleSubscriptionResumptionStorage::DeleteAll(FabricIndex fabricIndex)
     443              : {
     444            5 :     CHIP_ERROR deleteErr = CHIP_NO_ERROR;
     445              : 
     446            5 :     uint16_t count = 0;
     447          245 :     for (uint16_t subscriptionIndex = 0; subscriptionIndex < CHIP_IM_MAX_NUM_SUBSCRIPTIONS; subscriptionIndex++)
     448              :     {
     449          240 :         SubscriptionInfo subscriptionInfo;
     450          240 :         CHIP_ERROR err = Load(subscriptionIndex, subscriptionInfo);
     451              : 
     452          240 :         if (err == CHIP_NO_ERROR)
     453              :         {
     454           29 :             if (fabricIndex == subscriptionInfo.mFabricIndex)
     455              :             {
     456           27 :                 err = Delete(subscriptionIndex);
     457           27 :                 if ((err != CHIP_NO_ERROR) && (err != CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND))
     458              :                 {
     459            0 :                     deleteErr = err;
     460              :                 }
     461              :             }
     462              :             else
     463              :             {
     464            2 :                 count++;
     465              :             }
     466              :         }
     467          240 :     }
     468              : 
     469              :     // if there are no persisted subscriptions, the MaxCount can also be deleted
     470            5 :     if (count == 0)
     471              :     {
     472            3 :         CHIP_ERROR err = DeleteMaxCount();
     473              : 
     474            3 :         if ((err != CHIP_NO_ERROR) && (err != CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND))
     475              :         {
     476            0 :             deleteErr = err;
     477              :         }
     478              :     }
     479              : 
     480            5 :     return deleteErr;
     481              : }
     482              : 
     483              : } // namespace app
     484              : } // namespace chip
        

Generated by: LCOV version 2.0-1