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
|