LCOV - code coverage report
Current view: top level - transport - UnauthenticatedSessionTable.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 30 98 30.6 %
Date: 2024-02-15 08:20:41 Functions: 11 37 29.7 %

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

Generated by: LCOV version 1.14