Matter SDK Coverage Report
Current view: top level - transport - UnauthenticatedSessionTable.h (source / functions) Coverage Total Hit
Test: SHA:1560a87972ec2c7a76cec101927a563a6862bc2a Lines: 26.9 % 119 32
Test Date: 2025-03-30 07:08:27 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
      88              :     {
      89            0 :         return ((GetPeerAddress().GetTransportType() == Transport::Type::kUdp) ||
      90            0 :                 (GetPeerAddress().GetTransportType() == Transport::Type::kWiFiPAF));
      91              :     }
      92              : 
      93            0 :     bool AllowsLargePayload() const override { return GetPeerAddress().GetTransportType() == Transport::Type::kTcp; }
      94              : 
      95            0 :     System::Clock::Milliseconds32 GetAckTimeout(bool isFirstMessageOnExchange) const override
      96              :     {
      97            0 :         switch (mPeerAddress.GetTransportType())
      98              :         {
      99            0 :         case Transport::Type::kUdp: {
     100            0 :             const ReliableMessageProtocolConfig & remoteMRPConfig = mRemoteSessionParams.GetMRPConfig();
     101            0 :             return GetRetransmissionTimeout(remoteMRPConfig.mActiveRetransTimeout, remoteMRPConfig.mIdleRetransTimeout,
     102            0 :                                             GetLastPeerActivityTime(), remoteMRPConfig.mActiveThresholdTime,
     103            0 :                                             isFirstMessageOnExchange);
     104              :         }
     105            0 :         case Transport::Type::kTcp:
     106            0 :             return System::Clock::Seconds16(30);
     107            0 :         case Transport::Type::kBle:
     108            0 :             return System::Clock::Milliseconds32(BTP_ACK_TIMEOUT_MS);
     109            0 :         default:
     110            0 :             break;
     111              :         }
     112            0 :         return System::Clock::Timeout();
     113              :     }
     114              : 
     115            0 :     System::Clock::Milliseconds32 GetMessageReceiptTimeout(System::Clock::Timestamp ourLastActivity,
     116              :                                                            bool isFirstMessageOnExchange) const override
     117              :     {
     118            0 :         switch (mPeerAddress.GetTransportType())
     119              :         {
     120            0 :         case Transport::Type::kUdp: {
     121            0 :             const auto & maybeLocalMRPConfig = GetLocalMRPConfig();
     122            0 :             const auto & defaultMRRPConfig   = GetDefaultMRPConfig();
     123            0 :             const auto & localMRPConfig      = maybeLocalMRPConfig.ValueOr(defaultMRRPConfig);
     124            0 :             return GetRetransmissionTimeout(localMRPConfig.mActiveRetransTimeout, localMRPConfig.mIdleRetransTimeout,
     125            0 :                                             ourLastActivity, localMRPConfig.mActiveThresholdTime, isFirstMessageOnExchange);
     126              :         }
     127            0 :         case Transport::Type::kTcp:
     128            0 :             return System::Clock::Seconds16(30);
     129            0 :         case Transport::Type::kBle:
     130            0 :             return System::Clock::Milliseconds32(BTP_ACK_TIMEOUT_MS);
     131            0 :         default:
     132            0 :             break;
     133              :         }
     134            0 :         return System::Clock::Timeout();
     135              :     }
     136              : 
     137            0 :     NodeId GetPeerNodeId() const
     138              :     {
     139            0 :         if (mSessionRole == SessionRole::kInitiator)
     140              :         {
     141            0 :             return kUndefinedNodeId;
     142              :         }
     143              : 
     144            0 :         return mEphemeralInitiatorNodeId;
     145              :     }
     146              : 
     147          383 :     SessionRole GetSessionRole() const { return mSessionRole; }
     148          279 :     NodeId GetEphemeralInitiatorNodeID() const { return mEphemeralInitiatorNodeId; }
     149            0 :     const PeerAddress & GetPeerAddress() const { return mPeerAddress; }
     150            0 :     void SetPeerAddress(const PeerAddress & peerAddress) { mPeerAddress = peerAddress; }
     151              : 
     152            0 :     bool IsPeerActive() const
     153              :     {
     154            0 :         return ((System::SystemClock().GetMonotonicTimestamp() - GetLastPeerActivityTime()) <
     155            0 :                 GetRemoteMRPConfig().mActiveThresholdTime);
     156              :     }
     157              : 
     158            0 :     System::Clock::Timestamp GetMRPBaseTimeout() const override
     159              :     {
     160            0 :         return IsPeerActive() ? GetRemoteMRPConfig().mActiveRetransTimeout : GetRemoteMRPConfig().mIdleRetransTimeout;
     161              :     }
     162              : 
     163           17 :     void SetRemoteSessionParameters(const SessionParameters & sessionParams) { mRemoteSessionParams = sessionParams; }
     164              : 
     165            0 :     const SessionParameters & GetRemoteSessionParameters() const override { return mRemoteSessionParams; }
     166              : 
     167          196 :     PeerMessageCounter & GetPeerMessageCounter() { return mPeerMessageCounter; }
     168              : 
     169            0 :     static void Release(UnauthenticatedSession * obj)
     170              :     {
     171              :         // When using heap pools, we need to make sure to release ourselves back to
     172              :         // the pool.  When not using heap pools, we don't want the extra cost of the
     173              :         // table pointer here, and the table itself handles entry reuse and cleanup
     174              :         // as needed.
     175              : #if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     176            0 :         obj->ReleaseSelfToPool();
     177              : #else
     178              :         // Just do nothing.
     179              : #endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     180            0 :     }
     181              : 
     182              : #if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     183              :     virtual void ReleaseSelfToPool() = 0;
     184              : #endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     185              : 
     186              : private:
     187              :     const NodeId mEphemeralInitiatorNodeId;
     188              :     const SessionRole mSessionRole;
     189              :     PeerAddress mPeerAddress;
     190              :     System::Clock::Timestamp mLastActivityTime;     ///< Timestamp of last tx or rx
     191              :     System::Clock::Timestamp mLastPeerActivityTime; ///< Timestamp of last rx
     192              :     SessionParameters mRemoteSessionParams;
     193              :     PeerMessageCounter mPeerMessageCounter;
     194              : };
     195              : 
     196              : template <size_t kMaxSessionCount>
     197              : class UnauthenticatedSessionTable;
     198              : 
     199              : namespace detail {
     200              : 
     201              : template <size_t kMaxSessionCount>
     202              : class UnauthenticatedSessionPoolEntry : public UnauthenticatedSession
     203              : {
     204              : public:
     205            0 :     UnauthenticatedSessionPoolEntry(SessionRole sessionRole, NodeId ephemeralInitiatorNodeID,
     206              :                                     const Transport::PeerAddress & peerAddress, const ReliableMessageProtocolConfig & config,
     207              :                                     UnauthenticatedSessionTable<kMaxSessionCount> & sessionTable) :
     208              :         UnauthenticatedSession(sessionRole, ephemeralInitiatorNodeID, peerAddress, config)
     209              : #if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     210              :         ,
     211            0 :         mSessionTable(sessionTable)
     212              : #endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     213            0 :     {}
     214              : 
     215              : private:
     216              : #if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     217              :     virtual void ReleaseSelfToPool();
     218              : 
     219              :     UnauthenticatedSessionTable<kMaxSessionCount> & mSessionTable;
     220              : #endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     221              : };
     222              : 
     223              : } // namespace detail
     224              : 
     225              : /*
     226              :  * @brief
     227              :  *   An table which manages UnauthenticatedSessions
     228              :  *
     229              :  *   The UnauthenticatedSession entries are rotated using LRU, but entry can be hold by using SessionHandle or
     230              :  *   SessionHolder, which increase the reference count by 1. If the reference count is not 0, the entry won't be pruned.
     231              :  */
     232              : template <size_t kMaxSessionCount>
     233              : class UnauthenticatedSessionTable
     234              : {
     235              : public:
     236          439 :     ~UnauthenticatedSessionTable()
     237              :     {
     238              : #if !CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     239              :         // When not using heap pools, our entries never actually get released
     240              :         // back to the pool (which lets us make the entries 4 bytes smaller by
     241              :         // not storing a reference to the table in them) and we LRU reuse ones
     242              :         // that have 0 refcount.  But we should release them all here, to ensure
     243              :         // that we don't hit fatal asserts in our pool destructor.
     244              :         mEntries.ReleaseAll();
     245              : #endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     246          439 :     }
     247              : 
     248              :     /**
     249              :      * Get a responder session with the given ephemeralInitiatorNodeID. If the session doesn't exist in the cache, allocate a new
     250              :      * entry for it.
     251              :      *
     252              :      * @return the session found or allocated, or Optional::Missing if not found and allocation failed.
     253              :      */
     254              :     CHECK_RETURN_VALUE
     255           57 :     Optional<SessionHandle> FindOrAllocateResponder(NodeId ephemeralInitiatorNodeID, const ReliableMessageProtocolConfig & config,
     256              :                                                     const Transport::PeerAddress & peerAddress)
     257              :     {
     258           57 :         UnauthenticatedSession * result =
     259           57 :             FindEntry(UnauthenticatedSession::SessionRole::kResponder, ephemeralInitiatorNodeID, peerAddress);
     260           57 :         if (result != nullptr)
     261           35 :             return MakeOptional<SessionHandle>(*result);
     262              : 
     263              :         CHIP_ERROR err =
     264           22 :             AllocEntry(UnauthenticatedSession::SessionRole::kResponder, ephemeralInitiatorNodeID, peerAddress, config, result);
     265           22 :         if (err == CHIP_NO_ERROR)
     266              :         {
     267           22 :             return MakeOptional<SessionHandle>(*result);
     268              :         }
     269              : 
     270            0 :         return Optional<SessionHandle>::Missing();
     271              :     }
     272              : 
     273           41 :     CHECK_RETURN_VALUE Optional<SessionHandle> FindInitiator(NodeId ephemeralInitiatorNodeID,
     274              :                                                              const Transport::PeerAddress & peerAddress)
     275              :     {
     276              :         UnauthenticatedSession * result =
     277           41 :             FindEntry(UnauthenticatedSession::SessionRole::kInitiator, ephemeralInitiatorNodeID, peerAddress);
     278           41 :         if (result != nullptr)
     279              :         {
     280           41 :             return MakeOptional<SessionHandle>(*result);
     281              :         }
     282              : 
     283            0 :         return Optional<SessionHandle>::Missing();
     284              :     }
     285              : 
     286            0 :     CHECK_RETURN_VALUE Optional<SessionHandle> AllocInitiator(NodeId ephemeralInitiatorNodeID, const PeerAddress & peerAddress,
     287              :                                                               const ReliableMessageProtocolConfig & config)
     288              :     {
     289            0 :         UnauthenticatedSession * result = nullptr;
     290              :         CHIP_ERROR err =
     291            0 :             AllocEntry(UnauthenticatedSession::SessionRole::kInitiator, ephemeralInitiatorNodeID, peerAddress, config, result);
     292            0 :         if (err == CHIP_NO_ERROR)
     293              :         {
     294            0 :             result->SetPeerAddress(peerAddress);
     295            0 :             return MakeOptional<SessionHandle>(*result);
     296              :         }
     297              : 
     298            0 :         return Optional<SessionHandle>::Missing();
     299              :     }
     300              : 
     301              : private:
     302              :     using EntryType = detail::UnauthenticatedSessionPoolEntry<kMaxSessionCount>;
     303              :     friend EntryType;
     304              : 
     305              :     /**
     306              :      * Allocates a new session out of the internal resource pool.
     307              :      *
     308              :      * @returns CHIP_NO_ERROR if new session created. May fail if maximum session count has been reached (with
     309              :      * CHIP_ERROR_NO_MEMORY).
     310              :      */
     311              :     CHECK_RETURN_VALUE
     312            0 :     CHIP_ERROR AllocEntry(UnauthenticatedSession::SessionRole sessionRole, NodeId ephemeralInitiatorNodeID,
     313              :                           const PeerAddress & peerAddress, const ReliableMessageProtocolConfig & config,
     314              :                           UnauthenticatedSession *& entry)
     315              :     {
     316            0 :         auto entryToUse = mEntries.CreateObject(sessionRole, ephemeralInitiatorNodeID, peerAddress, config, *this);
     317            0 :         if (entryToUse != nullptr)
     318              :         {
     319            0 :             entry = entryToUse;
     320            0 :             return CHIP_NO_ERROR;
     321              :         }
     322              : 
     323              : #if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     324              :         // permanent failure if heap was insufficient
     325            0 :         return CHIP_ERROR_NO_MEMORY;
     326              : #else
     327              :         entryToUse = FindLeastRecentUsedEntry();
     328              :         VerifyOrReturnError(entryToUse != nullptr, CHIP_ERROR_NO_MEMORY);
     329              : 
     330              :         // Drop the least recent entry to allow for a new alloc.
     331              :         mEntries.ReleaseObject(entryToUse);
     332              :         entryToUse = mEntries.CreateObject(sessionRole, ephemeralInitiatorNodeID, peerAddress, config, *this);
     333              : 
     334              :         if (entryToUse == nullptr)
     335              :         {
     336              :             // this is NOT expected: we freed an object to have space
     337              :             return CHIP_ERROR_INTERNAL;
     338              :         }
     339              : 
     340              :         entry = entryToUse;
     341              :         return CHIP_NO_ERROR;
     342              : #endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     343              :     }
     344              : 
     345           98 :     CHECK_RETURN_VALUE UnauthenticatedSession * FindEntry(UnauthenticatedSession::SessionRole sessionRole,
     346              :                                                           NodeId ephemeralInitiatorNodeID,
     347              :                                                           const Transport::PeerAddress & peerAddress)
     348              :     {
     349           98 :         UnauthenticatedSession * result = nullptr;
     350           98 :         mEntries.ForEachActiveObject([&](UnauthenticatedSession * entry) {
     351          200 :             if (entry->GetSessionRole() == sessionRole && entry->GetEphemeralInitiatorNodeID() == ephemeralInitiatorNodeID &&
     352           76 :                 entry->GetPeerAddress().GetTransportType() == peerAddress.GetTransportType())
     353              :             {
     354           76 :                 result = entry;
     355           76 :                 return Loop::Break;
     356              :             }
     357           48 :             return Loop::Continue;
     358              :         });
     359           98 :         return result;
     360              :     }
     361              : 
     362              :     EntryType * FindLeastRecentUsedEntry()
     363              :     {
     364              :         EntryType * result                  = nullptr;
     365              :         System::Clock::Timestamp oldestTime = System::Clock::Timestamp(std::numeric_limits<System::Clock::Timestamp::rep>::max());
     366              : 
     367              :         mEntries.ForEachActiveObject([&](EntryType * entry) {
     368              :             if (entry->GetReferenceCount() == 0 && entry->GetLastActivityTime() < oldestTime)
     369              :             {
     370              :                 result     = entry;
     371              :                 oldestTime = entry->GetLastActivityTime();
     372              :             }
     373              :             return Loop::Continue;
     374              :         });
     375              : 
     376              :         return result;
     377              :     }
     378              : 
     379            0 :     void ReleaseEntry(EntryType * entry) { mEntries.ReleaseObject(entry); }
     380              : 
     381              :     ObjectPool<EntryType, kMaxSessionCount> mEntries;
     382              : };
     383              : 
     384              : #if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     385              : template <size_t kMaxSessionCount>
     386            0 : void detail::UnauthenticatedSessionPoolEntry<kMaxSessionCount>::ReleaseSelfToPool()
     387              : {
     388            0 :     mSessionTable.ReleaseEntry(this);
     389            0 : }
     390              : #endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     391              : 
     392              : } // namespace Transport
     393              : } // namespace chip
        

Generated by: LCOV version 2.0-1