Matter SDK Coverage Report
Current view: top level - transport - GroupPeerMessageCounter.cpp (source / functions) Coverage Total Hit
Test: SHA:209dc18e4021e7d0dff8120ccc585909391dd862 Lines: 92.8 % 153 142
Test Date: 2026-06-16 07:34:53 Functions: 100.0 % 12 12

            Line data    Source code
       1              : /*
       2              :  *    Copyright (c) 2021 Project CHIP Authors
       3              :  *
       4              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       5              :  *    you may not use this file except in compliance with the License.
       6              :  *    You may obtain a copy of the License at
       7              :  *
       8              :  *        http://www.apache.org/licenses/LICENSE-2.0
       9              :  *
      10              :  *    Unless required by applicable law or agreed to in writing, software
      11              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      12              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13              :  *    See the License for the specific language governing permissions and
      14              :  *    limitations under the License.
      15              :  */
      16              : 
      17              : /**
      18              :  *    @file
      19              :  *      This file defines the Matter Group message counters of remote nodes for groups.
      20              :  *
      21              :  */
      22              : 
      23              : #include <lib/support/DefaultStorageKeyAllocator.h>
      24              : #include <limits>
      25              : #include <transport/GroupPeerMessageCounter.h>
      26              : 
      27              : #include <crypto/RandUtils.h>
      28              : #include <utility>
      29              : 
      30              : namespace chip {
      31              : namespace Transport {
      32              : 
      33              : namespace {
      34              : 
      35              : /// Shift elements right and insert newEntry at front (MRU position).
      36              : ///
      37              : /// All elements [0..oldIndex) are shifted one slot to the right; newEntry
      38              : /// becomes list[0] as the most-recently-used entry.
      39          170 : void ShiftAndInsert(GroupSender * list, uint32_t oldIndex, GroupSender && newEntry)
      40              : {
      41         1855 :     for (uint32_t j = oldIndex; j > 0; j--)
      42              :     {
      43         1685 :         list[j] = std::move(list[j - 1]);
      44              :     }
      45          170 :     list[0] = std::move(newEntry);
      46          170 : }
      47              : 
      48              : /// Find peer by nodeId (move to MRU) or add it; return counter.
      49              : ///
      50              : /// `list` is a list of `maxLimit` items, out of which the first `peerCount` elements are valid.
      51              : /// `nodeId` is searched for and added if not found:
      52              : ///   - if found, it gets moved to `list[0]` as the most recently used element
      53              : ///   - if not found, it will be inserted at index 0, shifting everything else to the right.
      54              : ///     peerCount may increase if space exists, otherwise the LRU entry (at maxLimit - 1) will be evicted
      55              : /// `peerType` is a label used only in eviction log messages.
      56              : ///
      57              : /// `outCounter` is an OUTPUT value, pointing to the PeerMessageCounter of the GroupSender found or inserted.
      58          170 : CHIP_ERROR FindOrAddPeerFabricFound(GroupSender * list, uint32_t maxLimit, uint8_t & peerCount, NodeId nodeId,
      59              :                                     chip::Transport::PeerMessageCounter *& outCounter, const char * peerType)
      60              : {
      61              :     static uint32_t kInvalidIndex = std::numeric_limits<uint32_t>::max();
      62              : 
      63          170 :     GroupSender temp;
      64          170 :     temp.mNodeId = nodeId;
      65              : 
      66          170 :     uint32_t insertPos = kInvalidIndex;
      67              : 
      68              :     // Search for peer
      69         1966 :     for (uint32_t i = 0; i < peerCount; i++)
      70              :     {
      71         1801 :         if (list[i].mNodeId == nodeId)
      72              :         {
      73            5 :             insertPos = i;
      74            5 :             temp      = std::move(list[i]);
      75            5 :             break;
      76              :         }
      77              :     }
      78              : 
      79          170 :     if (insertPos == kInvalidIndex)
      80              :     {
      81              :         // GroupSender was not found, must add a new one for this node id.
      82          165 :         if (peerCount < maxLimit)
      83              :         {
      84           54 :             peerCount++;
      85              :         }
      86              :         else
      87              :         {
      88              :             // Evict LRU
      89          111 :             ChipLogProgress(SecureChannel, "GroupPeerTable: Evicting %s peer " ChipLogFormatX64 " due to table being full",
      90              :                             peerType, ChipLogValueX64(list[maxLimit - 1].mNodeId));
      91              :         }
      92          165 :         insertPos = peerCount - 1;
      93              :     }
      94              : 
      95          170 :     ShiftAndInsert(list, insertPos, std::move(temp));
      96          170 :     outCounter = &(list[0].msgCounter);
      97          170 :     return CHIP_NO_ERROR;
      98          170 : }
      99              : 
     100              : } // anonymous namespace
     101              : 
     102          237 : CHIP_ERROR GroupPeerTable::FindOrAddPeer(FabricIndex fabricIndex, NodeId nodeId, bool isControl,
     103              :                                          chip::Transport::PeerMessageCounter *& counter)
     104              : {
     105          237 :     if (fabricIndex == kUndefinedFabricIndex || nodeId == kUndefinedNodeId)
     106              :     {
     107            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     108              :     }
     109              : 
     110          795 :     for (auto & groupFabric : mGroupFabrics)
     111              :     {
     112          793 :         if (groupFabric.mFabricIndex == kUndefinedFabricIndex)
     113              :         {
     114              :             // Already iterated through all known fabricIndex
     115              :             // Add the new peer to save some processing time
     116           65 :             groupFabric.mFabricIndex = fabricIndex;
     117           65 :             if (isControl)
     118              :             {
     119           27 :                 groupFabric.mControlGroupSenders[0].mNodeId = nodeId;
     120           27 :                 counter                                     = &(groupFabric.mControlGroupSenders[0].msgCounter);
     121           27 :                 groupFabric.mControlPeerCount++;
     122              :             }
     123              :             else
     124              :             {
     125           38 :                 groupFabric.mDataGroupSenders[0].mNodeId = nodeId;
     126           38 :                 counter                                  = &(groupFabric.mDataGroupSenders[0].msgCounter);
     127           38 :                 groupFabric.mDataPeerCount++;
     128              :             }
     129           65 :             return CHIP_NO_ERROR;
     130              :         }
     131              : 
     132          728 :         if (fabricIndex == groupFabric.mFabricIndex)
     133              :         {
     134          170 :             if (isControl)
     135              :             {
     136           29 :                 return FindOrAddPeerFabricFound(groupFabric.mControlGroupSenders, CHIP_CONFIG_MAX_GROUP_CONTROL_PEERS,
     137           29 :                                                 groupFabric.mControlPeerCount, nodeId, counter, "control");
     138              :             }
     139          141 :             return FindOrAddPeerFabricFound(groupFabric.mDataGroupSenders, CHIP_CONFIG_MAX_GROUP_DATA_PEERS,
     140          141 :                                             groupFabric.mDataPeerCount, nodeId, counter, "data");
     141              :         }
     142              :     }
     143              : 
     144              :     // Exceeded the Max number of Group fabrics
     145            2 :     return CHIP_ERROR_NO_MEMORY;
     146              : }
     147              : 
     148              : // Used in case of MCSP failure
     149           38 : CHIP_ERROR GroupPeerTable::RemovePeer(FabricIndex fabricIndex, NodeId nodeId, bool isControl)
     150              : {
     151           38 :     CHIP_ERROR err    = CHIP_ERROR_NOT_FOUND;
     152           38 :     uint32_t fabricIt = CHIP_CONFIG_MAX_FABRICS;
     153              : 
     154           38 :     if (fabricIndex == kUndefinedFabricIndex || nodeId == kUndefinedNodeId)
     155              :     {
     156            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     157              :     }
     158              : 
     159          156 :     for (uint32_t it = 0; it < CHIP_CONFIG_MAX_FABRICS; it++)
     160              :     {
     161          156 :         if (fabricIndex == mGroupFabrics[it].mFabricIndex)
     162              :         {
     163           38 :             if (isControl)
     164              :             {
     165           33 :                 if (RemoveSpecificPeer(mGroupFabrics[it].mControlGroupSenders, nodeId, CHIP_CONFIG_MAX_GROUP_CONTROL_PEERS))
     166              :                 {
     167           33 :                     fabricIt = it;
     168           33 :                     mGroupFabrics[it].mControlPeerCount--;
     169           33 :                     err = CHIP_NO_ERROR;
     170              :                 }
     171              :             }
     172              :             else
     173              :             {
     174            5 :                 if (RemoveSpecificPeer(mGroupFabrics[it].mDataGroupSenders, nodeId, CHIP_CONFIG_MAX_GROUP_DATA_PEERS))
     175              :                 {
     176            5 :                     fabricIt = it;
     177            5 :                     mGroupFabrics[it].mDataPeerCount--;
     178            5 :                     err = CHIP_NO_ERROR;
     179              :                 }
     180              :             }
     181           38 :             break;
     182              :         }
     183              :     }
     184              : 
     185              :     // Remove Fabric entry from PeerTable if empty
     186           38 :     if (fabricIt < CHIP_CONFIG_MAX_FABRICS)
     187              :     {
     188           38 :         if (mGroupFabrics[fabricIt].mDataPeerCount == 0 && mGroupFabrics[fabricIt].mControlPeerCount == 0)
     189              :         {
     190           18 :             RemoveAndCompactFabric(fabricIt);
     191              :         }
     192              :     }
     193              : 
     194              :     // Cannot find Peer to remove
     195           38 :     return err;
     196              : }
     197              : 
     198           11 : CHIP_ERROR GroupPeerTable::FabricRemoved(FabricIndex fabricIndex)
     199              : {
     200           11 :     CHIP_ERROR err = CHIP_ERROR_NOT_FOUND;
     201              : 
     202           11 :     if (fabricIndex == kUndefinedFabricIndex)
     203              :     {
     204            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     205              :     }
     206              : 
     207          170 :     for (uint32_t it = 0; it < CHIP_CONFIG_MAX_FABRICS; it++)
     208              :     {
     209          161 :         if (fabricIndex == mGroupFabrics[it].mFabricIndex)
     210              :         {
     211            2 :             RemoveAndCompactFabric(it);
     212            2 :             return CHIP_NO_ERROR;
     213              :         }
     214              :     }
     215              : 
     216              :     // Cannot find Fabric to remove
     217            9 :     return err;
     218              : }
     219              : 
     220           38 : bool GroupPeerTable::RemoveSpecificPeer(GroupSender * list, NodeId nodeId, uint32_t size)
     221              : {
     222           38 :     bool removed = false;
     223           64 :     for (uint32_t nodeIt = 0; nodeIt < size; nodeIt++)
     224              :     {
     225           64 :         if (list[nodeIt].mNodeId == nodeId)
     226              :         {
     227           38 :             list[nodeIt].mNodeId = kUndefinedNodeId;
     228           38 :             list[nodeIt].msgCounter.Reset();
     229           38 :             removed = true;
     230           38 :             break;
     231              :         }
     232              :     }
     233              : 
     234           38 :     if (removed)
     235              :     {
     236           38 :         CompactPeers(list, size);
     237              :     }
     238              : 
     239           38 :     return removed;
     240              : }
     241              : 
     242           38 : void GroupPeerTable::CompactPeers(GroupSender * list, uint32_t size)
     243              : {
     244           38 :     if (list == nullptr || size == 0)
     245              :     {
     246            0 :         return;
     247              :     }
     248              : 
     249           38 :     uint32_t writeIndex = 0;
     250          179 :     for (uint32_t readIndex = 0; readIndex < size; readIndex++)
     251              :     {
     252              :         // readIndex and writeIndex will iterate together, until a point
     253              :         // is found where the node id at the read index is kUndefinedNodeId. This
     254              :         // means the GroupSender entry at this index has been removed (likely by
     255              :         // RemoveSpecificPeer()). When this removed entry index is found, the read
     256              :         // index will be 1 ahead of the write index, and then all entries
     257              :         // that follow will be shifted down the list (moving 1 to the left).
     258          141 :         if (list[readIndex].mNodeId != kUndefinedNodeId)
     259              :         {
     260           35 :             if (readIndex != writeIndex)
     261              :             {
     262            9 :                 list[writeIndex] = std::move(list[readIndex]);
     263              :             }
     264           35 :             writeIndex++;
     265              :         }
     266              :     }
     267              : 
     268              :     // Cleanup old entries at the end of the list. These were entries that were
     269              :     // moved further up in the list, and the entries from the writeIndex onwards
     270              :     // are in an unspecified state.
     271          144 :     for (uint32_t i = writeIndex; i < size; i++)
     272              :     {
     273          106 :         list[i] = GroupSender();
     274              :     }
     275              : }
     276              : 
     277           20 : void GroupPeerTable::RemoveAndCompactFabric(uint32_t tableIndex)
     278              : {
     279           20 :     if (tableIndex >= CHIP_CONFIG_MAX_FABRICS)
     280              :     {
     281            0 :         return;
     282              :     }
     283           20 :     mGroupFabrics[tableIndex].mFabricIndex = kUndefinedFabricIndex;
     284           20 :     new (&mGroupFabrics[tableIndex]) GroupFabric();
     285              : 
     286              :     // To maintain logic integrity Fabric array cannot have empty slot in between data
     287              :     // Find the last non empty element
     288          153 :     for (uint32_t i = CHIP_CONFIG_MAX_FABRICS - 1; i > tableIndex; i--)
     289              :     {
     290          144 :         if (mGroupFabrics[i].mFabricIndex != kUndefinedFabricIndex)
     291              :         {
     292              :             // Logic works since all buffer are static
     293              :             // move it up front
     294           11 :             new (&mGroupFabrics[tableIndex]) GroupFabric(mGroupFabrics[i]);
     295           11 :             new (&mGroupFabrics[i]) GroupFabric();
     296           11 :             break;
     297              :         }
     298              :     }
     299              : }
     300              : 
     301            4 : GroupOutgoingCounters::GroupOutgoingCounters(chip::PersistentStorageDelegate * storage_delegate)
     302              : {
     303            4 :     TEMPORARY_RETURN_IGNORED Init(storage_delegate);
     304            4 : }
     305              : 
     306          495 : CHIP_ERROR GroupOutgoingCounters::Init(chip::PersistentStorageDelegate * storage_delegate)
     307              : {
     308              : 
     309          495 :     if (storage_delegate == nullptr)
     310              :     {
     311            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     312              :     }
     313              : 
     314              :     // Spec 4.5.1.3
     315          495 :     mStorage      = storage_delegate;
     316          495 :     uint16_t size = static_cast<uint16_t>(sizeof(uint32_t));
     317              :     uint32_t temp;
     318              :     CHIP_ERROR err;
     319          495 :     err = mStorage->SyncGetKeyValue(DefaultStorageKeyAllocator::GroupControlCounter().KeyName(), &temp, size);
     320          990 :     if (err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND)
     321              :     {
     322              :         // First time retrieving the counter
     323          491 :         mGroupControlCounter = (chip::Crypto::GetRandU32() & kMessageCounterRandomInitMask) + 1;
     324              :     }
     325            8 :     else if (err != CHIP_NO_ERROR)
     326              :     {
     327            0 :         return err;
     328              :     }
     329              :     else
     330              :     {
     331            4 :         mGroupControlCounter = temp;
     332              :     }
     333              : 
     334          495 :     err = mStorage->SyncGetKeyValue(DefaultStorageKeyAllocator::GroupDataCounter().KeyName(), &temp, size);
     335          990 :     if (err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND)
     336              :     {
     337              :         // First time retrieving the counter
     338          491 :         mGroupDataCounter = (chip::Crypto::GetRandU32() & kMessageCounterRandomInitMask) + 1;
     339              :     }
     340            8 :     else if (err != CHIP_NO_ERROR)
     341              :     {
     342            0 :         return err;
     343              :     }
     344              :     else
     345              :     {
     346            4 :         mGroupDataCounter = temp;
     347              :     }
     348              : 
     349          495 :     temp = mGroupControlCounter + GROUP_MSG_COUNTER_MIN_INCREMENT;
     350          495 :     size = static_cast<uint16_t>(sizeof(temp));
     351          495 :     ReturnErrorOnFailure(mStorage->SyncSetKeyValue(DefaultStorageKeyAllocator::GroupControlCounter().KeyName(), &temp, size));
     352              : 
     353          495 :     temp = mGroupDataCounter + GROUP_MSG_COUNTER_MIN_INCREMENT;
     354              : 
     355          495 :     return mStorage->SyncSetKeyValue(DefaultStorageKeyAllocator::GroupDataCounter().KeyName(), &temp, size);
     356              : }
     357              : 
     358           17 : uint32_t GroupOutgoingCounters::GetCounter(bool isControl)
     359              : {
     360           17 :     return (isControl) ? mGroupControlCounter : mGroupDataCounter;
     361              : }
     362              : 
     363            7 : CHIP_ERROR GroupOutgoingCounters::IncrementCounter(bool isControl)
     364              : {
     365            7 :     uint32_t temp  = 0;
     366            7 :     uint16_t size  = static_cast<uint16_t>(sizeof(uint32_t));
     367            7 :     uint32_t value = 0;
     368              : 
     369            7 :     StorageKeyName key = StorageKeyName::Uninitialized();
     370              : 
     371            7 :     if (isControl)
     372              :     {
     373            2 :         mGroupControlCounter++;
     374            2 :         key   = DefaultStorageKeyAllocator::GroupControlCounter();
     375            2 :         value = mGroupControlCounter;
     376              :     }
     377              :     else
     378              :     {
     379            5 :         mGroupDataCounter++;
     380            5 :         key   = DefaultStorageKeyAllocator::GroupDataCounter();
     381            5 :         value = mGroupDataCounter;
     382              :     }
     383              : 
     384            7 :     if (mStorage == nullptr)
     385              :     {
     386            0 :         return CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND;
     387              :     }
     388              : 
     389            7 :     ReturnErrorOnFailure(mStorage->SyncGetKeyValue(key.KeyName(), &temp, size));
     390            7 :     if (temp == value)
     391              :     {
     392            0 :         temp = value + GROUP_MSG_COUNTER_MIN_INCREMENT;
     393            0 :         return mStorage->SyncSetKeyValue(key.KeyName(), &temp, sizeof(uint32_t));
     394              :     }
     395            7 :     return CHIP_NO_ERROR;
     396            7 : }
     397              : 
     398              : } // namespace Transport
     399              : } // namespace chip
        

Generated by: LCOV version 2.0-1