Matter SDK Coverage Report
Current view: top level - app - OperationalSessionSetup.h (source / functions) Coverage Total Hit
Test: SHA:e021a368d10ac6f3f201c101585146211fdcdaa2 Lines: 5.6 % 36 2
Test Date: 2026-02-13 08:13:38 Functions: 13.3 % 15 2

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020-2021 Project CHIP Authors
       4              :  *    All rights reserved.
       5              :  *
       6              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7              :  *    you may not use this file except in compliance with the License.
       8              :  *    You may obtain a copy of the License at
       9              :  *
      10              :  *        http://www.apache.org/licenses/LICENSE-2.0
      11              :  *
      12              :  *    Unless required by applicable law or agreed to in writing, software
      13              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15              :  *    See the License for the specific language governing permissions and
      16              :  *    limitations under the License.
      17              :  */
      18              : 
      19              : /**
      20              :  *  @file
      21              :  *    This file contains definitions for Device class. The objects of this
      22              :  *    class will be used by Controller applications to interact with CHIP
      23              :  *    devices. The class provides mechanism to construct, send and receive
      24              :  *    messages to and from the corresponding CHIP devices.
      25              :  */
      26              : 
      27              : #pragma once
      28              : 
      29              : #include <app/AppConfig.h>
      30              : #include <app/CASEClient.h>
      31              : #include <app/CASEClientPool.h>
      32              : #include <app/DeviceProxy.h>
      33              : #include <app/util/basic-types.h>
      34              : #include <credentials/GroupDataProvider.h>
      35              : #include <lib/address_resolve/AddressResolve.h>
      36              : #include <lib/core/GroupedCallbackList.h>
      37              : #include <messaging/ExchangeContext.h>
      38              : #include <messaging/ExchangeDelegate.h>
      39              : #include <messaging/ExchangeMgr.h>
      40              : #include <messaging/Flags.h>
      41              : #include <messaging/ReliableMessageProtocolConfig.h>
      42              : #include <platform/CHIPDeviceConfig.h>
      43              : #include <protocols/secure_channel/CASESession.h>
      44              : #include <system/SystemClock.h>
      45              : #include <system/SystemLayer.h>
      46              : #include <transport/SessionManager.h>
      47              : #include <transport/TransportMgr.h>
      48              : #include <transport/raw/MessageHeader.h>
      49              : #include <transport/raw/UDP.h>
      50              : 
      51              : namespace chip {
      52              : 
      53              : class OperationalSessionSetup;
      54              : 
      55              : /**
      56              :  * @brief Delegate provided when creating OperationalSessionSetup.
      57              :  *
      58              :  * Once OperationalSessionSetup establishes a connection (or errors out) and has notified all
      59              :  * registered application callbacks via OnDeviceConnected/OnDeviceConnectionFailure, this delegate
      60              :  * is used to deallocate the OperationalSessionSetup.
      61              :  */
      62              : class OperationalSessionReleaseDelegate
      63              : {
      64              : public:
      65           69 :     virtual ~OperationalSessionReleaseDelegate()                        = default;
      66              :     virtual void ReleaseSession(OperationalSessionSetup * sessionSetup) = 0;
      67              : };
      68              : 
      69              : /**
      70              :  * @brief Minimal implementation of DeviceProxy that encapsulates a SessionHolder to track a CASE session.
      71              :  *
      72              :  * Deprecated - Avoid using this object.
      73              :  *
      74              :  * OperationalDeviceProxy is a minimal implementation of DeviceProxy. It is meant to provide a transition
      75              :  * for existing consumers of OperationalDeviceProxy that were delivered a reference to that object in
      76              :  * their respective OnDeviceConnected callback, but were incorrectly holding onto that object past
      77              :  * the function call. OperationalDeviceProxy can be held on for as long as is desired, while still
      78              :  * minimizing the code changes needed to transition to a more final solution by virtue of
      79              :  * implementing DeviceProxy.
      80              :  */
      81              : class OperationalDeviceProxy : public DeviceProxy
      82              : {
      83              : public:
      84            0 :     OperationalDeviceProxy(Messaging::ExchangeManager * exchangeMgr, const SessionHandle & sessionHandle) :
      85            0 :         mExchangeMgr(exchangeMgr), mSecureSession(sessionHandle), mPeerScopedNodeId(sessionHandle->GetPeer())
      86            0 :     {}
      87           37 :     OperationalDeviceProxy() {}
      88              : 
      89            0 :     void Disconnect() override
      90              :     {
      91            0 :         if (IsSecureConnected())
      92              :         {
      93            0 :             GetSecureSession().Value()->AsSecureSession()->MarkAsDefunct();
      94              :         }
      95            0 :         mSecureSession.Release();
      96            0 :         mExchangeMgr      = nullptr;
      97            0 :         mPeerScopedNodeId = ScopedNodeId();
      98            0 :     }
      99            0 :     Messaging::ExchangeManager * GetExchangeManager() const override { return mExchangeMgr; }
     100            0 :     chip::Optional<SessionHandle> GetSecureSession() const override { return mSecureSession.Get(); }
     101            0 :     NodeId GetDeviceId() const override { return mPeerScopedNodeId.GetNodeId(); }
     102              :     ScopedNodeId GetPeerScopedNodeId() const { return mPeerScopedNodeId; }
     103              : 
     104              :     bool ConnectionReady() const { return (mExchangeMgr != nullptr && IsSecureConnected()); }
     105              : 
     106              : private:
     107            0 :     bool IsSecureConnected() const override { return static_cast<bool>(mSecureSession); }
     108              : 
     109              :     Messaging::ExchangeManager * mExchangeMgr = nullptr;
     110              :     SessionHolder mSecureSession;
     111              :     ScopedNodeId mPeerScopedNodeId;
     112              : };
     113              : 
     114              : /**
     115              :  * @brief Callback prototype when secure session is established.
     116              :  *
     117              :  * Callback implementations are not supposed to store the exchangeMgr or the sessionHandle. Older
     118              :  * application code does incorrectly hold onto this information so do not follow those incorrect
     119              :  * implementations as an example.
     120              :  */
     121              : typedef void (*OnDeviceConnected)(void * context, Messaging::ExchangeManager & exchangeMgr, const SessionHandle & sessionHandle);
     122              : 
     123              : /**
     124              :  * Callback prototype when secure session establishment fails.
     125              :  */
     126              : typedef void (*OnDeviceConnectionFailure)(void * context, const ScopedNodeId & peerId, CHIP_ERROR error);
     127              : 
     128              : /**
     129              :  * Callback prototype when secure session establishement has failed and will be
     130              :  * retried.  retryTimeout indicates how much time will pass before we know
     131              :  * whether the retry has timed out waiting for a response to our Sigma1 message.
     132              :  */
     133              : typedef void (*OnDeviceConnectionRetry)(void * context, const ScopedNodeId & peerId, CHIP_ERROR error,
     134              :                                         System::Clock::Seconds16 retryTimeout);
     135              : 
     136              : /**
     137              :  * Object used to either establish a connection to peer or performing address lookup to a peer.
     138              :  *
     139              :  * OperationalSessionSetup is capable of either:
     140              :  *    1. Establishing a CASE session connection to a peer. Upon success or failure, the OnDeviceConnected or
     141              :  *       OnDeviceConnectionFailure callback will be called to notify the caller the results of trying to
     142              :  *       estblish a CASE session. Some additional details about the steps to establish a connection are:
     143              :  *          - Discover the device using DNSSD (find out what IP address to use and what
     144              :  *            communication parameters are appropriate for it)
     145              :  *          - Establish a secure channel to it via CASE
     146              :  *          - Expose to consumers the secure session for talking to the device via OnDeviceConnected
     147              :  *            callback.
     148              :  *    2. Performing an address lookup for given a scoped nodeid. On success, it will call into
     149              :  *       SessionManager to update the addresses for all matching sessions in the session table.
     150              :  *
     151              :  * OperationalSessionSetup has a very limited lifetime. Once it has completed its purpose outlined above,
     152              :  * it will use `releaseDelegate` to release itself.
     153              :  *
     154              :  * It is possible to determine which of the two purposes the OperationalSessionSetup is for by calling
     155              :  * IsForAddressUpdate().
     156              :  */
     157              : class DLL_EXPORT OperationalSessionSetup : public SessionEstablishmentDelegate, public AddressResolve::NodeListener
     158              : {
     159              : public:
     160              :     struct ConnectionFailureInfo
     161              :     {
     162              :         const ScopedNodeId peerId;
     163              :         CHIP_ERROR error;
     164              :         SessionEstablishmentStage sessionStage;
     165              : 
     166              :         // When the response was BUSY, error will be CHIP_ERROR_BUSY and
     167              :         // requestedBusyDelay will be set, if handling of BUSY responses is
     168              :         // enabled.
     169              : #if CHIP_CONFIG_ENABLE_BUSY_HANDLING_FOR_OPERATIONAL_SESSION_SETUP
     170              :         Optional<System::Clock::Milliseconds16> requestedBusyDelay;
     171              : #endif // CHIP_CONFIG_ENABLE_BUSY_HANDLING_FOR_OPERATIONAL_SESSION_SETUP
     172              : 
     173            0 :         ConnectionFailureInfo(const ScopedNodeId & peer, CHIP_ERROR err, SessionEstablishmentStage stage) :
     174            0 :             peerId(peer), error(err), sessionStage(stage)
     175            0 :         {}
     176              :     };
     177              : 
     178              :     using OnSetupFailure = void (*)(void * context, const ConnectionFailureInfo & failureInfo);
     179              : 
     180              :     ~OperationalSessionSetup() override;
     181              : 
     182            0 :     OperationalSessionSetup(const CASEClientInitParams & params, CASEClientPoolDelegate * clientPool, ScopedNodeId peerId,
     183              :                             OperationalSessionReleaseDelegate * releaseDelegate)
     184            0 :     {
     185            0 :         mInitParams = params;
     186            0 :         if (params.Validate() != CHIP_NO_ERROR || clientPool == nullptr || releaseDelegate == nullptr)
     187              :         {
     188            0 :             mState = State::Uninitialized;
     189            0 :             return;
     190              :         }
     191              : 
     192            0 :         mClientPool      = clientPool;
     193            0 :         mPeerId          = peerId;
     194            0 :         mReleaseDelegate = releaseDelegate;
     195            0 :         mState           = State::NeedsAddress;
     196            0 :         mAddressLookupHandle.SetListener(this);
     197              :     }
     198              : 
     199              :     /*
     200              :      * This function can be called to establish a secure session with the device.
     201              :      *
     202              :      * The device is expected to have been commissioned, A CASE session
     203              :      * setup will be triggered.
     204              :      *
     205              :      * If session setup succeeds, the callback function `onConnection` will be called.
     206              :      * If session setup fails, `onFailure` will be called.
     207              :      *
     208              :      * If the session already exists, `onConnection` will be called immediately,
     209              :      * before the Connect call returns.
     210              :      *
     211              :      * `onFailure` may be called before the Connect call returns, for error
     212              :      * cases that are detected synchronously (e.g. inability to start an address
     213              :      * lookup).
     214              :      *
     215              :      * `transportPayloadCapability` is set to kLargePayload when the session needs to be established
     216              :      * over a transport that allows large payloads to be transferred, e.g., TCP.
     217              :      */
     218              :     void Connect(Callback::Callback<OnDeviceConnected> * onConnection, Callback::Callback<OnDeviceConnectionFailure> * onFailure,
     219              :                  TransportPayloadCapability transportPayloadCapability = TransportPayloadCapability::kMRPPayload);
     220              : 
     221              :     /*
     222              :      * This function can be called to establish a secure session with the device.
     223              :      *
     224              :      * The device is expected to have been commissioned, A CASE session
     225              :      * setup will be triggered.
     226              :      *
     227              :      * If session setup succeeds, the callback function `onConnection` will be called.
     228              :      * If session setup fails, `onSetupFailure` will be called.
     229              :      *
     230              :      * If the session already exists, `onConnection` will be called immediately,
     231              :      * before the Connect call returns.
     232              :      *
     233              :      * `onSetupFailure` may be called before the Connect call returns, for error cases that are detected synchronously
     234              :      * (e.g. inability to start an address lookup).
     235              :      *
     236              :      * `transportPayloadCapability` is set to kLargePayload when the session needs to be established
     237              :      * over a transport that allows large payloads to be transferred, e.g., TCP.
     238              :      */
     239              :     void Connect(Callback::Callback<OnDeviceConnected> * onConnection, Callback::Callback<OnSetupFailure> * onSetupFailure,
     240              :                  TransportPayloadCapability transportPayloadCapability = TransportPayloadCapability::kMRPPayload);
     241              : 
     242            0 :     bool IsForAddressUpdate() const { return mPerformingAddressUpdate; }
     243              : 
     244              :     //////////// SessionEstablishmentDelegate Implementation ///////////////
     245              :     void OnSessionEstablished(const SessionHandle & session) override;
     246              :     void OnSessionEstablishmentError(CHIP_ERROR error, SessionEstablishmentStage stage) override;
     247              :     void OnResponderBusy(System::Clock::Milliseconds16 requestedDelay) override;
     248              : 
     249            0 :     ScopedNodeId GetPeerId() const { return mPeerId; }
     250              : 
     251              :     static Transport::PeerAddress ToPeerAddress(const Dnssd::ResolvedNodeData & nodeData)
     252              :     {
     253              :         Inet::InterfaceId interfaceId = Inet::InterfaceId::Null();
     254              : 
     255              :         // TODO - Revisit usage of InterfaceID only for addresses that are IPv6 LLA
     256              :         // Only use the DNS-SD resolution's InterfaceID for addresses that are IPv6 LLA.
     257              :         // For all other addresses, we should rely on the device's routing table to route messages sent.
     258              :         // Forcing messages down an InterfaceId might fail. For example, in bridged networks like Thread,
     259              :         // mDNS advertisements are not usually received on the same interface the peer is reachable on.
     260              :         if (nodeData.resolutionData.ipAddress[0].IsIPv6LinkLocal())
     261              :         {
     262              :             interfaceId = nodeData.resolutionData.interfaceId;
     263              :         }
     264              : 
     265              :         return Transport::PeerAddress::UDP(nodeData.resolutionData.ipAddress[0], nodeData.resolutionData.port, interfaceId);
     266              :     }
     267              : 
     268              :     /**
     269              :      * @brief Get the fabricIndex
     270              :      */
     271            0 :     FabricIndex GetFabricIndex() const { return mPeerId.GetFabricIndex(); }
     272              : 
     273              :     void PerformAddressUpdate();
     274              : 
     275              :     // AddressResolve::NodeListener - notifications when dnssd finds a node IP address
     276              :     void OnNodeAddressResolved(const PeerId & peerId, const AddressResolve::ResolveResult & result) override;
     277              :     void OnNodeAddressResolutionFailed(const PeerId & peerId, CHIP_ERROR reason) override;
     278              : 
     279              : #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
     280              :     // Update our remaining attempt count to be at least the given value.
     281              :     void UpdateAttemptCount(uint8_t attemptCount);
     282              : 
     283              :     // Add a retry handler for this session setup.
     284              :     void AddRetryHandler(Callback::Callback<OnDeviceConnectionRetry> * onRetry);
     285              : #endif // CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
     286              : 
     287              : #if CHIP_CONFIG_ENABLE_ADDRESS_RESOLVE_FALLBACK
     288              :     /**
     289              :      * Set a fallback resolve result to use if address resolution times out.
     290              :      * This should be called before Connect() to enable the fallback mechanism.
     291              :      */
     292              :     void SetFallbackResolveResult(const AddressResolve::ResolveResult & result);
     293              : #endif // CHIP_CONFIG_ENABLE_ADDRESS_RESOLVE_FALLBACK
     294              : 
     295              : private:
     296              :     enum class State : uint8_t
     297              :     {
     298              :         Uninitialized,    // Error state: OperationalSessionSetup is useless
     299              :         NeedsAddress,     // No address known, lookup not started yet.
     300              :         ResolvingAddress, // Address lookup in progress.
     301              :         HasAddress,       // Have an address, CASE handshake not started yet.
     302              :         Connecting,       // CASE handshake in progress.
     303              :         SecureConnected,  // CASE session established.
     304              :         WaitingForRetry,  // No address known, but a retry is pending.  Added at
     305              :                           // end to make logs easier to understand.
     306              :     };
     307              : 
     308              :     CASEClientInitParams mInitParams;
     309              :     CASEClientPoolDelegate * mClientPool = nullptr;
     310              : 
     311              :     // mCASEClient is only non-null if we are in State::Connecting or just
     312              :     // allocated it as part of an attempt to enter State::Connecting.
     313              :     CASEClient * mCASEClient = nullptr;
     314              : 
     315              :     ScopedNodeId mPeerId;
     316              : 
     317              :     Transport::PeerAddress mDeviceAddress = Transport::PeerAddress::UDP(Inet::IPAddress::Any);
     318              : 
     319              :     SessionHolder mSecureSession;
     320              : 
     321              :     typedef Callback::GroupedCallbackList<OnDeviceConnected, OnDeviceConnectionFailure, OnSetupFailure> SuccessFailureCallbackList;
     322              :     SuccessFailureCallbackList mCallbacks;
     323              : 
     324              :     OperationalSessionReleaseDelegate * mReleaseDelegate;
     325              : 
     326              :     /// This is used when a node address is required.
     327              :     chip::AddressResolve::NodeLookupHandle mAddressLookupHandle;
     328              : 
     329              :     State mState = State::Uninitialized;
     330              : 
     331              :     bool mPerformingAddressUpdate = false;
     332              : 
     333              : #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES || CHIP_CONFIG_ENABLE_BUSY_HANDLING_FOR_OPERATIONAL_SESSION_SETUP
     334              :     System::Clock::Milliseconds16 mRequestedBusyDelay = System::Clock::kZero;
     335              : #endif // CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES || CHIP_CONFIG_ENABLE_BUSY_HANDLING_FOR_OPERATIONAL_SESSION_SETUP
     336              : 
     337              :     TransportPayloadCapability mTransportPayloadCapability = TransportPayloadCapability::kMRPPayload;
     338              : 
     339              : #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
     340              :     // When we TryNextResult on the resolver, it will synchronously call back
     341              :     // into our OnNodeAddressResolved when it succeeds.  We need to track
     342              :     // whether the OnNodeAddressResolved is coming from handling a session
     343              :     // establishment error or whether it's happening because we didn't even
     344              :     // manage to start a session establishment at all.  Use this member to keep
     345              :     // track of that.
     346              :     bool mTryingNextResultDueToSessionEstablishmentError = false;
     347              : 
     348              :     uint8_t mRemainingAttempts = 0;
     349              :     uint8_t mAttemptsDone      = 0;
     350              : 
     351              :     uint8_t mResolveAttemptsAllowed = 0;
     352              : 
     353              :     Callback::CallbackDeque mConnectionRetry;
     354              : #endif // CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
     355              : 
     356              : #if CHIP_CONFIG_ENABLE_ADDRESS_RESOLVE_FALLBACK
     357              :     // Fallback address resolve result to use if normal address resolution times out
     358              :     Optional<AddressResolve::ResolveResult> mFallbackResolveResult;
     359              :     System::Clock::Timeout mFallbackTimeout = System::Clock::Seconds16(CHIP_CONFIG_ADDRESS_RESOLVE_FALLBACK_TIMEOUT_SECONDS);
     360              : #endif // CHIP_CONFIG_ENABLE_ADDRESS_RESOLVE_FALLBACK
     361              : 
     362              :     void MoveToState(State aTargetState);
     363              : 
     364              :     CHIP_ERROR EstablishConnection(const AddressResolve::ResolveResult & result);
     365              : 
     366              :     /*
     367              :      * This checks to see if an existing CASE session exists to the peer within the SessionManager
     368              :      * and if one exists, to load that into mSecureSession.
     369              :      *
     370              :      * Returns true if a valid session was found, false otherwise.
     371              :      *
     372              :      */
     373              :     bool AttachToExistingSecureSession();
     374              : 
     375              :     void CleanupCASEClient();
     376              : 
     377              :     void Connect(Callback::Callback<OnDeviceConnected> * onConnection, Callback::Callback<OnDeviceConnectionFailure> * onFailure,
     378              :                  Callback::Callback<OnSetupFailure> * onSetupFailure,
     379              :                  TransportPayloadCapability transportPayloadCapability = TransportPayloadCapability::kMRPPayload);
     380              : 
     381              :     void EnqueueConnectionCallbacks(Callback::Callback<OnDeviceConnected> * onConnection,
     382              :                                     Callback::Callback<OnDeviceConnectionFailure> * onFailure,
     383              :                                     Callback::Callback<OnSetupFailure> * onSetupFailure);
     384              : 
     385              :     enum class ReleaseBehavior
     386              :     {
     387              :         Release,
     388              :         DoNotRelease
     389              :     };
     390              : 
     391              :     /*
     392              :      * This dequeues all failure and success callbacks and appropriately invokes either set depending
     393              :      * on the value of error.
     394              :      *
     395              :      * If error == CHIP_NO_ERROR, only success callbacks are invoked. Otherwise, only failure callbacks are invoked.
     396              :      *
     397              :      * The state offers additional context regarding the failure, indicating the specific state in which
     398              :      * the error occurs. It is only relayed through failure callbacks when the error is not equal to CHIP_NO_ERROR.
     399              :      *
     400              :      * If releaseBehavior is Release, this uses mReleaseDelegate to release
     401              :      * ourselves (aka `this`). As a result any caller should return right away
     402              :      * without touching `this`.
     403              :      *
     404              :      * Setting releaseBehavior to DoNotRelease is meant for use from the destructor
     405              :      */
     406              :     void DequeueConnectionCallbacks(CHIP_ERROR error, SessionEstablishmentStage stage,
     407              :                                     ReleaseBehavior releaseBehavior = ReleaseBehavior::Release);
     408              : 
     409            0 :     void DequeueConnectionCallbacks(CHIP_ERROR error, ReleaseBehavior releaseBehavior = ReleaseBehavior::Release)
     410              :     {
     411              :         // NOLINTNEXTLINE(clang-analyzer-core.StackAddressEscape): TODO #41631
     412            0 :         this->DequeueConnectionCallbacks(error, SessionEstablishmentStage::kNotInKeyExchange, releaseBehavior);
     413            0 :     }
     414              : 
     415              :     /**
     416              :      * Helper for DequeueConnectionCallbacks that handles the actual callback
     417              :      * notifications. This happens after the object has been released, if it's
     418              :      * being released.
     419              :      */
     420              :     static void NotifyConnectionCallbacks(SuccessFailureCallbackList & ready, CHIP_ERROR error, SessionEstablishmentStage stage,
     421              :                                           const ScopedNodeId & peerId, Messaging::ExchangeManager * exchangeMgr,
     422              :                                           const Optional<SessionHandle> & optionalSessionHandle,
     423              :                                           // requestedBusyDelay will be 0 if not
     424              :                                           // CHIP_CONFIG_ENABLE_BUSY_HANDLING_FOR_OPERATIONAL_SESSION_SETUP,
     425              :                                           // and only has a meaningful value
     426              :                                           // when the error is CHIP_ERROR_BUSY.
     427              :                                           System::Clock::Milliseconds16 requestedBusyDelay);
     428              : 
     429              :     /**
     430              :      * Triggers a DNSSD lookup to find a usable peer address.
     431              :      */
     432              :     CHIP_ERROR LookupPeerAddress();
     433              : 
     434              :     /**
     435              :      * This function will set new IP address, port and MRP retransmission intervals of the device.
     436              :      */
     437              :     void UpdateDeviceData(const AddressResolve::ResolveResult & result);
     438              : 
     439              : #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
     440              :     /**
     441              :      * Schedule a setup reattempt, if possible.  The outparam indicates how long
     442              :      * it will be before the reattempt happens.
     443              :      */
     444              :     CHIP_ERROR ScheduleSessionSetupReattempt(System::Clock::Seconds16 & timerDelay);
     445              : 
     446              :     /**
     447              :      * Cancel a scheduled setup reattempt, if we can (i.e. if we still have
     448              :      * access to the SystemLayer).
     449              :      */
     450              :     void CancelSessionSetupReattempt();
     451              : 
     452              :     /**
     453              :      * Helper for our backoff retry timer.
     454              :      */
     455              :     static void TrySetupAgain(System::Layer * systemLayer, void * state);
     456              : 
     457              :     /**
     458              :      * Helper to notify our retry callbacks that a setup error occurred and we
     459              :      * will retry.
     460              :      */
     461              :     void NotifyRetryHandlers(CHIP_ERROR error, const ReliableMessageProtocolConfig & remoteMrpConfig,
     462              :                              System::Clock::Seconds16 retryDelay);
     463              : 
     464              :     /**
     465              :      * A version of NotifyRetryHandlers that passes in a retry timeout estimate
     466              :      * directly.
     467              :      */
     468              :     void NotifyRetryHandlers(CHIP_ERROR error, System::Clock::Seconds16 timeoutEstimate);
     469              : #endif // CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
     470              : 
     471              : #if CHIP_CONFIG_ENABLE_ADDRESS_RESOLVE_FALLBACK
     472              :     /**
     473              :      * Timer callback invoked when DNS-SD resolution doesn't complete within the configured timeout.
     474              :      *
     475              :      * When this fires:
     476              :      * - Cancels the ongoing DNS-SD lookup to prevent race conditions
     477              :      * - Uses the cached IP/port from the successful PASE session seconds ago
     478              :      * - Assumes the cached address is still valid (IP hasn't changed)
     479              :      */
     480              :     static void OnFallbackTimeout(System::Layer * systemLayer, void * appState);
     481              : 
     482              :     /**
     483              :      * Cancel the fallback timeout timer if it's running.
     484              :      */
     485              :     void CancelFallbackTimer();
     486              : 
     487              :     /**
     488              :      * Start the fallback timeout timer.
     489              :      */
     490              :     CHIP_ERROR StartFallbackTimer();
     491              : 
     492              :     /**
     493              :      * Helper to get the System::Layer from the session manager.
     494              :      * Returns nullptr if not available.
     495              :      */
     496              :     System::Layer * GetSystemLayer();
     497              : #endif // CHIP_CONFIG_ENABLE_ADDRESS_RESOLVE_FALLBACK
     498              : };
     499              : 
     500              : } // namespace chip
        

Generated by: LCOV version 2.0-1