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

Generated by: LCOV version 2.0-1