Matter SDK Coverage Report
Current view: top level - transport - UnauthenticatedSessionTable.h (source / functions) Coverage Total Hit
Test: SHA:4cbce7f768f16e614f5a8ccb8cd93c92cbeae70d Lines: 27.4 % 117 32
Test Date: 2025-04-26 07:09:35 Functions: 28.9 % 38 11

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020 Project CHIP Authors
       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              : #pragma once
      18              : 
      19              : #include <ble/Ble.h>
      20              : #include <lib/core/CHIPError.h>
      21              : #include <lib/core/ReferenceCounted.h>
      22              : #include <lib/support/CodeUtils.h>
      23              : #include <lib/support/Pool.h>
      24              : #include <messaging/ReliableMessageProtocolConfig.h>
      25              : #include <system/SystemConfig.h>
      26              : #include <system/TimeSource.h>
      27              : #include <transport/PeerMessageCounter.h>
      28              : #include <transport/Session.h>
      29              : #include <transport/raw/PeerAddress.h>
      30              : 
      31              : namespace chip {
      32              : namespace Transport {
      33              : 
      34              : /**
      35              :  * @brief
      36              :  *   An UnauthenticatedSession stores the binding of TransportAddress, and message counters.
      37              :  */
      38              : class UnauthenticatedSession : public Session, public ReferenceCounted<UnauthenticatedSession, UnauthenticatedSession, 0>
      39              : {
      40              : public:
      41              :     enum class SessionRole
      42              :     {
      43              :         kInitiator,
      44              :         kResponder,
      45              :     };
      46              : 
      47              : protected:
      48            0 :     UnauthenticatedSession(SessionRole sessionRole, NodeId ephemeralInitiatorNodeID, const Transport::PeerAddress & peerAddress,
      49            0 :                            const ReliableMessageProtocolConfig & config) :
      50            0 :         mEphemeralInitiatorNodeId(ephemeralInitiatorNodeID),
      51            0 :         mSessionRole(sessionRole), mPeerAddress(peerAddress), mLastActivityTime(System::SystemClock().GetMonotonicTimestamp()),
      52            0 :         mLastPeerActivityTime(System::Clock::kZero), // Start at zero to default to IDLE state
      53            0 :         mRemoteSessionParams(config)
      54            0 :     {}
      55            0 :     ~UnauthenticatedSession() override { VerifyOrDie(GetReferenceCount() == 0); }
      56              : 
      57              : public:
      58              :     UnauthenticatedSession(const UnauthenticatedSession &)             = delete;
      59              :     UnauthenticatedSession & operator=(const UnauthenticatedSession &) = delete;
      60              :     UnauthenticatedSession(UnauthenticatedSession &&)                  = delete;
      61              :     UnauthenticatedSession & operator=(UnauthenticatedSession &&)      = delete;
      62              : 
      63              :     System::Clock::Timestamp GetLastActivityTime() const { return mLastActivityTime; }
      64            0 :     System::Clock::Timestamp GetLastPeerActivityTime() const { return mLastPeerActivityTime; }
      65          209 :     void MarkActive() { mLastActivityTime = System::SystemClock().GetMonotonicTimestamp(); }
      66          106 :     void MarkActiveRx()
      67              :     {
      68          106 :         mLastPeerActivityTime = System::SystemClock().GetMonotonicTimestamp();
      69          106 :         MarkActive();
      70          106 :     }
      71              : 
      72            0 :     Session::SessionType GetSessionType() const override { return Session::SessionType::kUnauthenticated; }
      73              : 
      74            0 :     void Retain() override { ReferenceCounted<UnauthenticatedSession, UnauthenticatedSession, 0>::Retain(); }
      75            0 :     void Release() override { ReferenceCounted<UnauthenticatedSession, UnauthenticatedSession, 0>::Release(); }
      76              : 
      77            0 :     bool IsActiveSession() const override { return true; }
      78              : 
      79            0 :     ScopedNodeId GetPeer() const override { return ScopedNodeId(GetPeerNodeId(), kUndefinedFabricIndex); }
      80            0 :     ScopedNodeId GetLocalScopedNodeId() const override { return ScopedNodeId(kUndefinedNodeId, kUndefinedFabricIndex); }
      81              : 
      82            0 :     Access::SubjectDescriptor GetSubjectDescriptor() const override
      83              :     {
      84            0 :         return Access::SubjectDescriptor(); // return an empty ISD for unauthenticated session.
      85              :     }
      86              : 
      87            0 :     bool AllowsMRP() const override { return (GetPeerAddress().GetTransportType() == Transport::Type::kUdp); }
      88              : 
      89            0 :     bool AllowsLargePayload() const override { return GetPeerAddress().GetTransportType() == Transport::Type::kTcp; }
      90              : 
      91            0 :     System::Clock::Milliseconds32 GetAckTimeout(bool isFirstMessageOnExchange) const override
      92              :     {
      93            0 :         switch (mPeerAddress.GetTransportType())
      94              :         {
      95            0 :         case Transport::Type::kUdp: {
      96            0 :             const ReliableMessageProtocolConfig & remoteMRPConfig = mRemoteSessionParams.GetMRPConfig();
      97            0 :             return GetRetransmissionTimeout(remoteMRPConfig.mActiveRetransTimeout, remoteMRPConfig.mIdleRetransTimeout,
      98            0 :                                             GetLastPeerActivityTime(), remoteMRPConfig.mActiveThresholdTime,
      99            0 :                                             isFirstMessageOnExchange);
     100              :         }
     101            0 :         case Transport::Type::kTcp:
     102            0 :             return System::Clock::Seconds16(30);
     103            0 :         case Transport::Type::kBle:
     104            0 :             return System::Clock::Milliseconds32(BTP_ACK_TIMEOUT_MS);
     105            0 :         default:
     106            0 :             break;
     107              :         }
     108            0 :         return System::Clock::Timeout();
     109              :     }
     110              : 
     111            0 :     System::Clock::Milliseconds32 GetMessageReceiptTimeout(System::Clock::Timestamp ourLastActivity,
     112              :                                                            bool isFirstMessageOnExchange) const override
     113              :     {
     114            0 :         switch (mPeerAddress.GetTransportType())
     115              :         {
     116            0 :         case Transport::Type::kUdp: {
     117            0 :             const auto & maybeLocalMRPConfig = GetLocalMRPConfig();
     118            0 :             const auto & defaultMRRPConfig   = GetDefaultMRPConfig();
     119            0 :             const auto & localMRPConfig      = maybeLocalMRPConfig.ValueOr(defaultMRRPConfig);
     120            0 :             return GetRetransmissionTimeout(localMRPConfig.mActiveRetransTimeout, localMRPConfig.mIdleRetransTimeout,
     121            0 :                                             ourLastActivity, localMRPConfig.mActiveThresholdTime, isFirstMessageOnExchange);
     122              :         }
     123            0 :         case Transport::Type::kTcp:
     124            0 :             return System::Clock::Seconds16(30);
     125            0 :         case Transport::Type::kBle:
     126            0 :             return System::Clock::Milliseconds32(BTP_ACK_TIMEOUT_MS);
     127            0 :         default:
     128            0 :             break;
     129              :         }
     130            0 :         return System::Clock::Timeout();
     131              :     }
     132              : 
     133            0 :     NodeId GetPeerNodeId() const
     134              :     {
     135            0 :         if (mSessionRole == SessionRole::kInitiator)
     136              :         {
     137            0 :             return kUndefinedNodeId;
     138              :         }
     139              : 
     140            0 :         return mEphemeralInitiatorNodeId;
     141              :     }
     142              : 
     143          383 :     SessionRole GetSessionRole() const { return mSessionRole; }
     144          279 :     NodeId GetEphemeralInitiatorNodeID() const { return mEphemeralInitiatorNodeId; }
     145            0 :     const PeerAddress & GetPeerAddress() const { return mPeerAddress; }
     146            0 :     void SetPeerAddress(const PeerAddress & peerAddress) { mPeerAddress = peerAddress; }
     147              : 
     148            0 :     bool IsPeerActive() const
     149              :     {
     150            0 :         return ((System::SystemClock().GetMonotonicTimestamp() - GetLastPeerActivityTime()) <
     151            0 :                 GetRemoteMRPConfig().mActiveThresholdTime);
     152              :     }
     153              : 
     154            0 :     System::Clock::Timestamp GetMRPBaseTimeout() const override
     155              :     {
     156            0 :         return IsPeerActive() ? GetRemoteMRPConfig().mActiveRetransTimeout : GetRemoteMRPConfig().mIdleRetransTimeout;
     157              :     }
     158              : 
     159           17 :     void SetRemoteSessionParameters(const SessionParameters & sessionParams) { mRemoteSessionParams = sessionParams; }
     160              : 
     161            0 :     const SessionParameters & GetRemoteSessionParameters() const override { return mRemoteSessionParams; }
     162              : 
     163          196 :     PeerMessageCounter & GetPeerMessageCounter() { return mPeerMessageCounter; }
     164              : 
     165            0 :     static void Release(UnauthenticatedSession * obj)
     166              :     {
     167              :         // When using heap pools, we need to make sure to release ourselves back to
     168              :         // the pool.  When not using heap pools, we don't want the extra cost of the
     169              :         // table pointer here, and the table itself handles entry reuse and cleanup
     170              :         // as needed.
     171              : #if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     172            0 :         obj->ReleaseSelfToPool();
     173              : #else
     174              :         // Just do nothing.
     175              : #endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     176            0 :     }
     177              : 
     178              : #if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     179              :     virtual void ReleaseSelfToPool() = 0;
     180              : #endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     181              : 
     182              : private:
     183              :     const NodeId mEphemeralInitiatorNodeId;
     184              :     const SessionRole mSessionRole;
     185              :     PeerAddress mPeerAddress;
     186              :     System::Clock::Timestamp mLastActivityTime;     ///< Timestamp of last tx or rx
     187              :     System::Clock::Timestamp mLastPeerActivityTime; ///< Timestamp of last rx
     188              :     SessionParameters mRemoteSessionParams;
     189              :     PeerMessageCounter mPeerMessageCounter;
     190              : };
     191              : 
     192              : template <size_t kMaxSessionCount>
     193              : class UnauthenticatedSessionTable;
     194              : 
     195              : namespace detail {
     196              : 
     197              : template <size_t kMaxSessionCount>
     198              : class UnauthenticatedSessionPoolEntry : public UnauthenticatedSession
     199              : {
     200              : public:
     201            0 :     UnauthenticatedSessionPoolEntry(SessionRole sessionRole, NodeId ephemeralInitiatorNodeID,
     202              :                                     const Transport::PeerAddress & peerAddress, const ReliableMessageProtocolConfig & config,
     203              :                                     UnauthenticatedSessionTable<kMaxSessionCount> & sessionTable) :
     204              :         UnauthenticatedSession(sessionRole, ephemeralInitiatorNodeID, peerAddress, config)
     205              : #if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     206              :         ,
     207            0 :         mSessionTable(sessionTable)
     208              : #endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     209            0 :     {}
     210              : 
     211              : private:
     212              : #if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     213              :     virtual void ReleaseSelfToPool();
     214              : 
     215              :     UnauthenticatedSessionTable<kMaxSessionCount> & mSessionTable;
     216              : #endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     217              : };
     218              : 
     219              : } // namespace detail
     220              : 
     221              : /*
     222              :  * @brief
     223              :  *   An table which manages UnauthenticatedSessions
     224              :  *
     225              :  *   The UnauthenticatedSession entries are rotated using LRU, but entry can be hold by using SessionHandle or
     226              :  *   SessionHolder, which increase the reference count by 1. If the reference count is not 0, the entry won't be pruned.
     227              :  */
     228              : template <size_t kMaxSessionCount>
     229              : class UnauthenticatedSessionTable
     230              : {
     231              : public:
     232          448 :     ~UnauthenticatedSessionTable()
     233              :     {
     234              : #if !CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     235              :         // When not using heap pools, our entries never actually get released
     236              :         // back to the pool (which lets us make the entries 4 bytes smaller by
     237              :         // not storing a reference to the table in them) and we LRU reuse ones
     238              :         // that have 0 refcount.  But we should release them all here, to ensure
     239              :         // that we don't hit fatal asserts in our pool destructor.
     240              :         mEntries.ReleaseAll();
     241              : #endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     242          448 :     }
     243              : 
     244              :     /**
     245              :      * Get a responder session with the given ephemeralInitiatorNodeID. If the session doesn't exist in the cache, allocate a new
     246              :      * entry for it.
     247              :      *
     248              :      * @return the session found or allocated, or Optional::Missing if not found and allocation failed.
     249              :      */
     250              :     CHECK_RETURN_VALUE
     251           57 :     Optional<SessionHandle> FindOrAllocateResponder(NodeId ephemeralInitiatorNodeID, const ReliableMessageProtocolConfig & config,
     252              :                                                     const Transport::PeerAddress & peerAddress)
     253              :     {
     254           57 :         UnauthenticatedSession * result =
     255           57 :             FindEntry(UnauthenticatedSession::SessionRole::kResponder, ephemeralInitiatorNodeID, peerAddress);
     256           57 :         if (result != nullptr)
     257           35 :             return MakeOptional<SessionHandle>(*result);
     258              : 
     259              :         CHIP_ERROR err =
     260           22 :             AllocEntry(UnauthenticatedSession::SessionRole::kResponder, ephemeralInitiatorNodeID, peerAddress, config, result);
     261           22 :         if (err == CHIP_NO_ERROR)
     262              :         {
     263           22 :             return MakeOptional<SessionHandle>(*result);
     264              :         }
     265              : 
     266            0 :         return Optional<SessionHandle>::Missing();
     267              :     }
     268              : 
     269           41 :     CHECK_RETURN_VALUE Optional<SessionHandle> FindInitiator(NodeId ephemeralInitiatorNodeID,
     270              :                                                              const Transport::PeerAddress & peerAddress)
     271              :     {
     272              :         UnauthenticatedSession * result =
     273           41 :             FindEntry(UnauthenticatedSession::SessionRole::kInitiator, ephemeralInitiatorNodeID, peerAddress);
     274           41 :         if (result != nullptr)
     275              :         {
     276           41 :             return MakeOptional<SessionHandle>(*result);
     277              :         }
     278              : 
     279            0 :         return Optional<SessionHandle>::Missing();
     280              :     }
     281              : 
     282            0 :     CHECK_RETURN_VALUE Optional<SessionHandle> AllocInitiator(NodeId ephemeralInitiatorNodeID, const PeerAddress & peerAddress,
     283              :                                                               const ReliableMessageProtocolConfig & config)
     284              :     {
     285            0 :         UnauthenticatedSession * result = nullptr;
     286              :         CHIP_ERROR err =
     287            0 :             AllocEntry(UnauthenticatedSession::SessionRole::kInitiator, ephemeralInitiatorNodeID, peerAddress, config, result);
     288            0 :         if (err == CHIP_NO_ERROR)
     289              :         {
     290            0 :             result->SetPeerAddress(peerAddress);
     291            0 :             return MakeOptional<SessionHandle>(*result);
     292              :         }
     293              : 
     294            0 :         return Optional<SessionHandle>::Missing();
     295              :     }
     296              : 
     297              : private:
     298              :     using EntryType = detail::UnauthenticatedSessionPoolEntry<kMaxSessionCount>;
     299              :     friend EntryType;
     300              : 
     301              :     /**
     302              :      * Allocates a new session out of the internal resource pool.
     303              :      *
     304              :      * @returns CHIP_NO_ERROR if new session created. May fail if maximum session count has been reached (with
     305              :      * CHIP_ERROR_NO_MEMORY).
     306              :      */
     307              :     CHECK_RETURN_VALUE
     308            0 :     CHIP_ERROR AllocEntry(UnauthenticatedSession::SessionRole sessionRole, NodeId ephemeralInitiatorNodeID,
     309              :                           const PeerAddress & peerAddress, const ReliableMessageProtocolConfig & config,
     310              :                           UnauthenticatedSession *& entry)
     311              :     {
     312            0 :         auto entryToUse = mEntries.CreateObject(sessionRole, ephemeralInitiatorNodeID, peerAddress, config, *this);
     313            0 :         if (entryToUse != nullptr)
     314              :         {
     315            0 :             entry = entryToUse;
     316            0 :             return CHIP_NO_ERROR;
     317              :         }
     318              : 
     319              : #if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     320              :         // permanent failure if heap was insufficient
     321            0 :         return CHIP_ERROR_NO_MEMORY;
     322              : #else
     323              :         entryToUse = FindLeastRecentUsedEntry();
     324              :         VerifyOrReturnError(entryToUse != nullptr, CHIP_ERROR_NO_MEMORY);
     325              : 
     326              :         // Drop the least recent entry to allow for a new alloc.
     327              :         mEntries.ReleaseObject(entryToUse);
     328              :         entryToUse = mEntries.CreateObject(sessionRole, ephemeralInitiatorNodeID, peerAddress, config, *this);
     329              : 
     330              :         if (entryToUse == nullptr)
     331              :         {
     332              :             // this is NOT expected: we freed an object to have space
     333              :             return CHIP_ERROR_INTERNAL;
     334              :         }
     335              : 
     336              :         entry = entryToUse;
     337              :         return CHIP_NO_ERROR;
     338              : #endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     339              :     }
     340              : 
     341           98 :     CHECK_RETURN_VALUE UnauthenticatedSession * FindEntry(UnauthenticatedSession::SessionRole sessionRole,
     342              :                                                           NodeId ephemeralInitiatorNodeID,
     343              :                                                           const Transport::PeerAddress & peerAddress)
     344              :     {
     345           98 :         UnauthenticatedSession * result = nullptr;
     346           98 :         mEntries.ForEachActiveObject([&](UnauthenticatedSession * entry) {
     347          200 :             if (entry->GetSessionRole() == sessionRole && entry->GetEphemeralInitiatorNodeID() == ephemeralInitiatorNodeID &&
     348           76 :                 entry->GetPeerAddress().GetTransportType() == peerAddress.GetTransportType())
     349              :             {
     350           76 :                 result = entry;
     351           76 :                 return Loop::Break;
     352              :             }
     353           48 :             return Loop::Continue;
     354              :         });
     355           98 :         return result;
     356              :     }
     357              : 
     358              :     EntryType * FindLeastRecentUsedEntry()
     359              :     {
     360              :         EntryType * result                  = nullptr;
     361              :         System::Clock::Timestamp oldestTime = System::Clock::Timestamp(std::numeric_limits<System::Clock::Timestamp::rep>::max());
     362              : 
     363              :         mEntries.ForEachActiveObject([&](EntryType * entry) {
     364              :             if (entry->GetReferenceCount() == 0 && entry->GetLastActivityTime() < oldestTime)
     365              :             {
     366              :                 result     = entry;
     367              :                 oldestTime = entry->GetLastActivityTime();
     368              :             }
     369              :             return Loop::Continue;
     370              :         });
     371              : 
     372              :         return result;
     373              :     }
     374              : 
     375            0 :     void ReleaseEntry(EntryType * entry) { mEntries.ReleaseObject(entry); }
     376              : 
     377              :     ObjectPool<EntryType, kMaxSessionCount> mEntries;
     378              : };
     379              : 
     380              : #if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     381              : template <size_t kMaxSessionCount>
     382            0 : void detail::UnauthenticatedSessionPoolEntry<kMaxSessionCount>::ReleaseSelfToPool()
     383              : {
     384            0 :     mSessionTable.ReleaseEntry(this);
     385            0 : }
     386              : #endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     387              : 
     388              : } // namespace Transport
     389              : } // namespace chip
        

Generated by: LCOV version 2.0-1