LCOV - code coverage report
Current view: top level - messaging - ExchangeContext.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 204 218 93.6 %
Date: 2024-02-15 08:20:41 Functions: 25 26 96.2 %

          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             : 
      18             : /**
      19             :  *    @file
      20             :  *      This file implements the ExchangeContext class.
      21             :  *
      22             :  */
      23             : #ifndef __STDC_FORMAT_MACROS
      24             : #define __STDC_FORMAT_MACROS
      25             : #endif
      26             : 
      27             : #ifndef __STDC_LIMIT_MACROS
      28             : #define __STDC_LIMIT_MACROS
      29             : #endif
      30             : 
      31             : #include <inttypes.h>
      32             : #include <stdint.h>
      33             : #include <stdlib.h>
      34             : 
      35             : #include <app/icd/server/ICDServerConfig.h>
      36             : #if CHIP_CONFIG_ENABLE_ICD_SERVER
      37             : #include <app/icd/server/ICDNotifier.h> // nogncheck
      38             : #endif
      39             : #include <lib/core/CHIPCore.h>
      40             : #include <lib/core/CHIPEncoding.h>
      41             : #include <lib/core/CHIPKeyIds.h>
      42             : #include <lib/support/Defer.h>
      43             : #include <lib/support/TypeTraits.h>
      44             : #include <lib/support/logging/CHIPLogging.h>
      45             : #include <messaging/ApplicationExchangeDispatch.h>
      46             : #include <messaging/EphemeralExchangeDispatch.h>
      47             : #include <messaging/ExchangeContext.h>
      48             : #include <messaging/ExchangeMgr.h>
      49             : #include <platform/LockTracker.h>
      50             : #include <protocols/Protocols.h>
      51             : #include <protocols/secure_channel/Constants.h>
      52             : 
      53             : using namespace chip::Encoding;
      54             : using namespace chip::Inet;
      55             : using namespace chip::System;
      56             : 
      57             : namespace chip {
      58             : namespace Messaging {
      59             : 
      60          82 : static void DefaultOnMessageReceived(ExchangeContext * ec, Protocols::Id protocolId, uint8_t msgType, uint32_t messageCounter,
      61             :                                      PacketBufferHandle && payload)
      62             : {
      63          82 :     ChipLogError(ExchangeManager,
      64             :                  "Dropping unexpected message of type " ChipLogFormatMessageType " with protocolId " ChipLogFormatProtocolId
      65             :                  " and MessageCounter:" ChipLogFormatMessageCounter " on exchange " ChipLogFormatExchange,
      66             :                  msgType, ChipLogValueProtocolId(protocolId), messageCounter, ChipLogValueExchange(ec));
      67          82 : }
      68             : 
      69       36353 : bool ExchangeContext::IsInitiator() const
      70             : {
      71       36353 :     return mFlags.Has(Flags::kFlagInitiator);
      72             : }
      73             : 
      74       33487 : bool ExchangeContext::IsResponseExpected() const
      75             : {
      76       33487 :     return mFlags.Has(Flags::kFlagResponseExpected);
      77             : }
      78             : 
      79       12682 : void ExchangeContext::SetResponseExpected(bool inResponseExpected)
      80             : {
      81       12682 :     mFlags.Set(Flags::kFlagResponseExpected, inResponseExpected);
      82       12682 :     SetWaitingForResponseOrAck(inResponseExpected);
      83       12682 : }
      84             : 
      85        6324 : void ExchangeContext::UseSuggestedResponseTimeout(Timeout applicationProcessingTimeout)
      86             : {
      87        6324 :     SetResponseTimeout(mSession->ComputeRoundTripTimeout(applicationProcessingTimeout));
      88        6324 : }
      89             : 
      90        6362 : void ExchangeContext::SetResponseTimeout(Timeout timeout)
      91             : {
      92        6362 :     mResponseTimeout = timeout;
      93        6362 : }
      94             : 
      95        9554 : CHIP_ERROR ExchangeContext::SendMessage(Protocols::Id protocolId, uint8_t msgType, PacketBufferHandle && msgBuf,
      96             :                                         const SendFlags & sendFlags)
      97             : {
      98             :     // This is the first point all outgoing messages funnel through.  Ensure
      99             :     // that our message sends are all synchronized correctly.
     100        9554 :     assertChipStackLockedByCurrentThread();
     101             : 
     102             :     bool isStandaloneAck =
     103        9554 :         (protocolId == Protocols::SecureChannel::Id) && msgType == to_underlying(Protocols::SecureChannel::MsgType::StandaloneAck);
     104             : 
     105        9554 :     VerifyOrReturnError(mExchangeMgr != nullptr, CHIP_ERROR_INTERNAL);
     106        9554 :     VerifyOrReturnError(mSession, CHIP_ERROR_CONNECTION_ABORTED);
     107             : 
     108             :     // Don't let method get called on a freed object.
     109        9542 :     VerifyOrDie(mExchangeMgr != nullptr && GetReferenceCount() > 0);
     110             : 
     111             :     // we hold the exchange context here in case the entity that
     112             :     // originally generated it tries to close it as a result of
     113             :     // an error arising below. at the end, we have to close it.
     114        9542 :     ExchangeHandle ref(*this);
     115             : 
     116             :     // If session requires MRP, NoAutoRequestAck send flag is not specified and is not a group exchange context, request reliable
     117             :     // transmission.
     118             :     bool reliableTransmissionRequested =
     119        9542 :         GetSessionHandle()->AllowsMRP() && !sendFlags.Has(SendMessageFlags::kNoAutoRequestAck) && !IsGroupExchangeContext();
     120             : 
     121        9542 :     bool currentMessageExpectResponse = false;
     122             :     // If a response message is expected...
     123        9542 :     if (sendFlags.Has(SendMessageFlags::kExpectResponse) && !IsGroupExchangeContext())
     124             :     {
     125             :         // Only one 'response expected' message can be outstanding at a time.
     126        6390 :         if (IsResponseExpected())
     127             :         {
     128             :             // TODO: add a test for this case.
     129           0 :             return CHIP_ERROR_INCORRECT_STATE;
     130             :         }
     131             : 
     132        6390 :         SetResponseExpected(true);
     133             : 
     134             :         // Arm the response timer if a timeout has been specified.
     135        6390 :         if (mResponseTimeout > System::Clock::kZero)
     136             :         {
     137        6337 :             CHIP_ERROR err = StartResponseTimer();
     138        6337 :             if (err != CHIP_NO_ERROR)
     139             :             {
     140           0 :                 SetResponseExpected(false);
     141           0 :                 return err;
     142             :             }
     143        6337 :             currentMessageExpectResponse = true;
     144             :         }
     145             :     }
     146             : 
     147             :     {
     148             :         // ExchangeContext for group are supposed to always be Initiator
     149        9542 :         if (IsGroupExchangeContext() && !IsInitiator())
     150             :         {
     151           0 :             return CHIP_ERROR_INTERNAL;
     152             :         }
     153             : 
     154             :         //
     155             :         // It is possible that we might have evicted a session as a side-effect of processing an inbound message on this exchange.
     156             :         // We cannot proceed any further sending a message since we don't have an attached session, so let's error out.
     157             :         //
     158             :         // This should not happen to well-behaved logic attempting to sending messages on exchanges, so let's print out a warning
     159             :         // to ensure it alerts someone to fixing their logic...
     160             :         //
     161        9542 :         if (!mSession)
     162             :         {
     163           0 :             ChipLogError(ExchangeManager,
     164             :                          "WARNING: We shouldn't be sending a message on an exchange that has no attached session...");
     165           0 :             return CHIP_ERROR_MISSING_SECURE_SESSION;
     166             :         }
     167             : 
     168        9542 :         SessionHandle session = GetSessionHandle();
     169             :         CHIP_ERROR err;
     170             : 
     171             : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
     172        9542 :         if (mInjectedFailures.Has(InjectedFailureType::kFailOnSend))
     173             :         {
     174           3 :             err = CHIP_ERROR_SENDING_BLOCKED;
     175             :         }
     176             :         else
     177             :         {
     178             : #endif
     179        9539 :             err = mDispatch.SendMessage(GetExchangeMgr()->GetSessionManager(), session, mExchangeId, IsInitiator(),
     180             :                                         GetReliableMessageContext(), reliableTransmissionRequested, protocolId, msgType,
     181        9539 :                                         std::move(msgBuf));
     182             : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
     183             :         }
     184             : #endif
     185        9542 :         if (err != CHIP_NO_ERROR)
     186             :         {
     187             :             // We should only cancel the response timer if the ExchangeContext fails to send the message that expects a
     188             :             // response.
     189           8 :             if (currentMessageExpectResponse)
     190             :             {
     191           3 :                 CancelResponseTimer();
     192           3 :                 SetResponseExpected(false);
     193             :             }
     194             : 
     195             :             // If we can't even send a message (send failed with a non-transient
     196             :             // error), mark the session as defunct, just like we would if we
     197             :             // thought we sent the message and never got a response.
     198           8 :             if (session->IsSecureSession() && session->AsSecureSession()->IsCASESession())
     199             :             {
     200           0 :                 session->AsSecureSession()->MarkAsDefunct();
     201             :             }
     202             :         }
     203             :         else
     204             :         {
     205             : #if CHIP_CONFIG_ENABLE_ICD_SERVER
     206             :             app::ICDNotifier::GetInstance().NotifyNetworkActivityNotification();
     207             : #endif // CHIP_CONFIG_ENABLE_ICD_SERVER
     208             : 
     209             :             // Standalone acks are not application-level message sends.
     210        9534 :             if (!isStandaloneAck)
     211             :             {
     212             :                 //
     213             :                 // Once we've sent the message successfully, we can clear out the WillSendMessage flag.
     214             :                 //
     215        8005 :                 mFlags.Clear(Flags::kFlagWillSendMessage);
     216        8005 :                 MessageHandled();
     217             :             }
     218             :         }
     219             : 
     220        9542 :         return err;
     221        9542 :     }
     222        9542 : }
     223             : 
     224        6546 : void ExchangeContext::DoClose(bool clearRetransTable)
     225             : {
     226        6546 :     if (mFlags.Has(Flags::kFlagClosed))
     227             :     {
     228        3278 :         return;
     229             :     }
     230             : 
     231        3268 :     mFlags.Set(Flags::kFlagClosed);
     232             : 
     233             :     // Clear protocol callbacks
     234        3268 :     if (mDelegate != nullptr)
     235             :     {
     236        2406 :         mDelegate->OnExchangeClosing(this);
     237             :     }
     238        3268 :     mDelegate = nullptr;
     239             : 
     240             :     // Closure of an exchange context is based on ref counting. The Protocol, when it calls DoClose(), indicates that
     241             :     // it is done with the exchange context and the message layer sets all callbacks to NULL and does not send anything
     242             :     // received on the exchange context up to higher layers.  At this point, the message layer needs to handle the
     243             :     // remaining work to be done on that exchange, (e.g. send all pending acks) before truly cleaning it up.
     244        3268 :     FlushAcks();
     245             : 
     246             :     // In case the protocol wants a harder release of the EC right away, such as calling Abort(), exchange
     247             :     // needs to clear the MRP retransmission table immediately.
     248        3268 :     if (clearRetransTable)
     249             :     {
     250         202 :         mExchangeMgr->GetReliableMessageMgr()->ClearRetransTable(this);
     251             :     }
     252             : 
     253        3268 :     if (IsResponseExpected())
     254             :     {
     255             :         // Cancel the response timer.
     256          98 :         CancelResponseTimer();
     257             :     }
     258             : }
     259             : 
     260             : /**
     261             :  *  Gracefully close an exchange context. This call decrements the
     262             :  *  reference count and releases the exchange when the reference
     263             :  *  count goes to zero.
     264             :  *
     265             :  */
     266        3071 : void ExchangeContext::Close()
     267             : {
     268        3071 :     VerifyOrDie(mExchangeMgr != nullptr && GetReferenceCount() > 0);
     269             : 
     270             : #if defined(CHIP_EXCHANGE_CONTEXT_DETAIL_LOGGING)
     271             :     ChipLogDetail(ExchangeManager, "ec - close[" ChipLogFormatExchange "], %s", ChipLogValueExchange(this), __func__);
     272             : #endif
     273             : 
     274        3071 :     DoClose(false);
     275        3071 :     Release();
     276        3071 : }
     277             : /**
     278             :  *  Abort the Exchange context immediately and release all
     279             :  *  references to it.
     280             :  *
     281             :  */
     282         197 : void ExchangeContext::Abort()
     283             : {
     284         197 :     VerifyOrDie(mExchangeMgr != nullptr && GetReferenceCount() > 0);
     285             : 
     286             : #if defined(CHIP_EXCHANGE_CONTEXT_DETAIL_LOGGING)
     287             :     ChipLogDetail(ExchangeManager, "ec - abort[" ChipLogFormatExchange "], %s", ChipLogValueExchange(this), __func__);
     288             : #endif
     289             : 
     290         197 :     DoClose(true);
     291         197 :     Release();
     292         197 : }
     293             : 
     294        3268 : void ExchangeContextDeletor::Release(ExchangeContext * ec)
     295             : {
     296        3268 :     ec->mExchangeMgr->ReleaseContext(ec);
     297        3268 : }
     298             : 
     299        3268 : ExchangeContext::ExchangeContext(ExchangeManager * em, uint16_t ExchangeId, const SessionHandle & session, bool Initiator,
     300        3268 :                                  ExchangeDelegate * delegate, bool isEphemeralExchange) :
     301        6536 :     mDispatch(GetMessageDispatch(isEphemeralExchange, delegate)),
     302        3268 :     mSession(*this)
     303             : {
     304        3268 :     VerifyOrDie(mExchangeMgr == nullptr);
     305             : 
     306        3268 :     mExchangeMgr = em;
     307        3268 :     mExchangeId  = ExchangeId;
     308        3268 :     mSession.Grab(session);
     309        3268 :     mFlags.Set(Flags::kFlagInitiator, Initiator);
     310        3268 :     mFlags.Set(Flags::kFlagEphemeralExchange, isEphemeralExchange);
     311        3268 :     mDelegate = delegate;
     312             : 
     313             :     //
     314             :     // If we're an initiator and we just created this exchange, we obviously did so to send a message. Let's go ahead and
     315             :     // set the flag on this to correctly mark it as so.
     316             :     //
     317             :     // This only applies to non-ephemeral exchanges. Ephemeral exchanges do not have an intention of sending out a message
     318             :     // since they're created expressly for the purposes of sending out a standalone ACK when the message could not be handled
     319             :     // through normal means.
     320             :     //
     321        3268 :     if (Initiator && !isEphemeralExchange)
     322             :     {
     323        1642 :         WillSendMessage();
     324             :     }
     325             : 
     326        3268 :     SetAckPending(false);
     327             : 
     328             :     // Try to use MRP by default, if it is allowed.
     329        3268 :     SetAutoRequestAck(session->AllowsMRP());
     330             : 
     331             : #if CHIP_CONFIG_ENABLE_ICD_SERVER
     332             :     app::ICDNotifier::GetInstance().NotifyActiveRequestNotification(app::ICDListener::KeepActiveFlag::kExchangeContextOpen);
     333             : #endif
     334             : 
     335             : #if defined(CHIP_EXCHANGE_CONTEXT_DETAIL_LOGGING)
     336             :     ChipLogDetail(ExchangeManager, "ec++ id: " ChipLogFormatExchange, ChipLogValueExchange(this));
     337             : #endif
     338        3268 :     SYSTEM_STATS_INCREMENT(chip::System::Stats::kExchangeMgr_NumContexts);
     339        3268 : }
     340             : 
     341        3268 : ExchangeContext::~ExchangeContext()
     342             : {
     343        3268 :     VerifyOrDie(mExchangeMgr != nullptr && GetReferenceCount() == 0);
     344             : 
     345             :     //
     346             :     // Ensure that DoClose has been called by the time we get here. If not, we have a leak somewhere.
     347             :     //
     348        3268 :     VerifyOrDie(mFlags.Has(Flags::kFlagClosed));
     349             : 
     350             : #if CHIP_CONFIG_ENABLE_ICD_SERVER
     351             :     app::ICDNotifier::GetInstance().NotifyActiveRequestWithdrawal(app::ICDListener::KeepActiveFlag::kExchangeContextOpen);
     352             : #endif // CHIP_CONFIG_ENABLE_ICD_SERVER
     353             : 
     354             :     // Ideally, in this scenario, the retransmit table should
     355             :     // be clear of any outstanding messages for this context and
     356             :     // the boolean parameter passed to DoClose() should not matter.
     357             : 
     358        3268 :     DoClose(false);
     359        3268 :     mExchangeMgr = nullptr;
     360             : 
     361             : #if defined(CHIP_EXCHANGE_CONTEXT_DETAIL_LOGGING)
     362             :     ChipLogDetail(ExchangeManager, "ec-- id: " ChipLogFormatExchange, ChipLogValueExchange(this));
     363             : #endif
     364        3268 :     SYSTEM_STATS_DECREMENT(chip::System::Stats::kExchangeMgr_NumContexts);
     365        3268 : }
     366             : 
     367       34611 : bool ExchangeContext::MatchExchange(const SessionHandle & session, const PacketHeader & packetHeader,
     368             :                                     const PayloadHeader & payloadHeader)
     369             : {
     370             :     // A given message is part of a particular exchange if...
     371             :     return
     372             : 
     373             :         // The exchange identifier of the message matches the exchange identifier of the context.
     374       34611 :         (mExchangeId == payloadHeader.GetExchangeID())
     375             : 
     376             :         // AND The Session associated with the incoming message matches the Session associated with the exchange.
     377       11855 :         && (mSession.Contains(session))
     378             : 
     379             :         // TODO: This check should be already implied by the equality of session check,
     380             :         // It should be removed after we have implemented the temporary node id for PASE and CASE sessions
     381        7813 :         && (IsEncryptionRequired() == packetHeader.IsEncrypted())
     382             : 
     383             :         // AND The message was sent by an initiator and the exchange context is a responder (IsInitiator==false)
     384             :         //    OR The message was sent by a responder and the exchange context is an initiator (IsInitiator==true) (for the broadcast
     385             :         //    case, the initiator is ill defined)
     386             : 
     387       46466 :         && (payloadHeader.IsInitiator() != IsInitiator());
     388             : }
     389             : 
     390          51 : void ExchangeContext::OnSessionReleased()
     391             : {
     392          51 :     if (ShouldIgnoreSessionRelease())
     393             :     {
     394           7 :         return;
     395             :     }
     396             : 
     397          49 :     if (mFlags.Has(Flags::kFlagClosed))
     398             :     {
     399             :         // Exchange is already being closed. It may occur when closing an exchange after sending
     400             :         // RemoveFabric response which triggers removal of all sessions for the given fabric.
     401           5 :         mExchangeMgr->GetReliableMessageMgr()->ClearRetransTable(this);
     402           5 :         return;
     403             :     }
     404             : 
     405             :     // Hold a ref to ourselves so we can make calls into our delegate that might
     406             :     // decrease our refcount without worrying about use-after-free.
     407          44 :     ExchangeHandle ref(*this);
     408             : 
     409             :     //
     410             :     // If a send is not expected (either because we're waiting for a response OR
     411             :     // we're in the middle of processing a OnMessageReceived call), we can go ahead
     412             :     // and notify our delegate and abort the exchange since we still own the ref.
     413             :     //
     414          44 :     if (!IsSendExpected())
     415             :     {
     416          34 :         if (IsResponseExpected())
     417             :         {
     418             :             // If we're waiting on a response, we now know it's never going to show up
     419             :             // and we should notify our delegate accordingly.
     420          31 :             CancelResponseTimer();
     421             :             // We want to Abort, not just Close, so that RMP bits are cleared, so
     422             :             // don't let NotifyResponseTimeout close us.
     423          31 :             NotifyResponseTimeout(/* aCloseIfNeeded = */ false);
     424             :         }
     425             : 
     426          34 :         Abort();
     427             :     }
     428             :     else
     429             :     {
     430          10 :         DoClose(true /* clearRetransTable */);
     431             :     }
     432          44 : }
     433             : 
     434        6337 : CHIP_ERROR ExchangeContext::StartResponseTimer()
     435             : {
     436        6337 :     System::Layer * lSystemLayer = mExchangeMgr->GetSessionManager()->SystemLayer();
     437        6337 :     if (lSystemLayer == nullptr)
     438             :     {
     439             :         // this is an assertion error, which shall never happen
     440           0 :         return CHIP_ERROR_INTERNAL;
     441             :     }
     442             : 
     443        6337 :     return lSystemLayer->StartTimer(mResponseTimeout, HandleResponseTimeout, this);
     444             : }
     445             : 
     446        6383 : void ExchangeContext::CancelResponseTimer()
     447             : {
     448        6383 :     System::Layer * lSystemLayer = mExchangeMgr->GetSessionManager()->SystemLayer();
     449        6383 :     if (lSystemLayer == nullptr)
     450             :     {
     451             :         // this is an assertion error, which shall never happen
     452           0 :         return;
     453             :     }
     454             : 
     455        6383 :     lSystemLayer->CancelTimer(HandleResponseTimeout, this);
     456             : }
     457             : 
     458           7 : void ExchangeContext::HandleResponseTimeout(System::Layer * aSystemLayer, void * aAppState)
     459             : {
     460           7 :     ExchangeContext * ec = reinterpret_cast<ExchangeContext *>(aAppState);
     461             : 
     462           7 :     if (ec == nullptr)
     463           0 :         return;
     464             : 
     465           7 :     ec->NotifyResponseTimeout(/* aCloseIfNeeded = */ true);
     466             : }
     467             : 
     468          38 : void ExchangeContext::NotifyResponseTimeout(bool aCloseIfNeeded)
     469             : {
     470             :     // Grab the value of WaitingForResponseOrAck() before we mess with our state.
     471          38 :     bool gotMRPAck = !WaitingForResponseOrAck();
     472             : 
     473          38 :     SetResponseExpected(false);
     474             : 
     475             :     // Hold a ref to ourselves so we can make calls into our delegate that might
     476             :     // decrease our refcount (e.g. by expiring out session) without worrying
     477             :     // about use-after-free.
     478          38 :     ExchangeHandle ref(*this);
     479             : 
     480             :     // mSession might be null if this timeout is due to the session being
     481             :     // evicted.
     482          38 :     if (mSession)
     483             :     {
     484             :         // If we timed out _after_ getting an ack for the message, that means
     485             :         // the session is probably fine (since our message and the ack got
     486             :         // through), so don't mark the session defunct if we got an MRP ack.
     487           7 :         if (!gotMRPAck)
     488             :         {
     489           5 :             if (mSession->IsSecureSession() && mSession->AsSecureSession()->IsCASESession())
     490             :             {
     491           1 :                 mSession->AsSecureSession()->MarkAsDefunct();
     492             :             }
     493           5 :             mSession->DispatchSessionEvent(&SessionDelegate::OnSessionHang);
     494             :         }
     495             :     }
     496             : 
     497          38 :     ExchangeDelegate * delegate = GetDelegate();
     498             : 
     499             :     // Call the user's timeout handler.
     500          38 :     if (delegate != nullptr)
     501             :     {
     502          38 :         delegate->OnResponseTimeout(this);
     503             :     }
     504             : 
     505          38 :     if (aCloseIfNeeded)
     506             :     {
     507           7 :         MessageHandled();
     508             :     }
     509          38 : }
     510             : 
     511        9417 : CHIP_ERROR ExchangeContext::HandleMessage(uint32_t messageCounter, const PayloadHeader & payloadHeader, MessageFlags msgFlags,
     512             :                                           PacketBufferHandle && msgBuf)
     513             : {
     514             :     // We hold a reference to the ExchangeContext here to
     515             :     // guard against Close() calls(decrementing the reference
     516             :     // count) by the protocol before the CHIP Exchange
     517             :     // layer has completed its work on the ExchangeContext.
     518        9417 :     ExchangeHandle ref(*this);
     519             : 
     520        9417 :     bool isStandaloneAck = payloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::StandaloneAck);
     521        9417 :     bool isDuplicate     = msgFlags.Has(MessageFlagValues::kDuplicateMessage);
     522             : 
     523        9417 :     auto deferred = MakeDefer([&]() {
     524             :         // Duplicates and standalone acks are not application-level messages, so they should generally not lead to any state
     525             :         // changes.  The one exception to that is that if we have a null mDelegate then our lifetime is not application-defined,
     526             :         // since we don't interact with the application at that point.  That can happen when we are already closed (in which case
     527             :         // MessageHandled is a no-op) or if we were just created to send a standalone ack for this incoming message, in which case
     528             :         // we should treat it as an app-level message for purposes of our state.
     529        9417 :         if ((isStandaloneAck || isDuplicate) && mDelegate != nullptr)
     530             :         {
     531          28 :             return;
     532             :         }
     533             : 
     534        9389 :         MessageHandled();
     535        9417 :     });
     536             : 
     537        9417 :     if (mSession->AllowsMRP())
     538             :     {
     539        9372 :         if (mDispatch.IsReliableTransmissionAllowed())
     540             :         {
     541       17158 :             if (!msgFlags.Has(MessageFlagValues::kDuplicateMessage) && payloadHeader.IsAckMsg() &&
     542        7786 :                 payloadHeader.GetAckMessageCounter().HasValue())
     543             :             {
     544        7786 :                 HandleRcvdAck(payloadHeader.GetAckMessageCounter().Value());
     545             :             }
     546             : 
     547        9372 :             if (payloadHeader.NeedsAck())
     548             :             {
     549             :                 // An acknowledgment needs to be sent back to the peer for this message on this exchange,
     550        7857 :                 HandleNeedsAck(messageCounter, msgFlags);
     551             :             }
     552             :         }
     553             : 
     554        9372 :         if (IsAckPending() && !mDelegate)
     555             :         {
     556             :             // The incoming message wants an ack, but we have no delegate, so
     557             :             // there's not going to be a response to piggyback on.  Just flush the
     558             :             // ack out right now.
     559          92 :             ReturnErrorOnFailure(FlushAcks());
     560             :         }
     561             : 
     562             :         // The SecureChannel::StandaloneAck message type is only used for MRP; do not pass such messages to the application layer.
     563        9372 :         if (isStandaloneAck)
     564             :         {
     565        1479 :             return CHIP_NO_ERROR;
     566             :         }
     567             :     } // AllowsMRP
     568             : 
     569             :     // Since the message is duplicate, let's not forward it up the stack
     570        7938 :     if (isDuplicate)
     571             :     {
     572           5 :         return CHIP_NO_ERROR;
     573             :     }
     574             : 
     575        7933 :     if (mSession->AllowsMRP())
     576             :     {
     577        7888 :         if (IsEphemeralExchange())
     578             :         {
     579             :             // The EphemeralExchange has done its job, since StandaloneAck is sent in previous FlushAcks() call.
     580           9 :             return CHIP_NO_ERROR;
     581             :         }
     582             : 
     583        7879 :         if (IsWaitingForAck())
     584             :         {
     585             :             // The only way we can get here is a spec violation on the other side:
     586             :             // we sent a message that needs an ack, and the other side responded
     587             :             // with a message that does not contain an ack for the message we sent.
     588             :             // Just drop this message; if we delivered it to our delegate it might
     589             :             // try to send another message-needing-an-ack in response, which would
     590             :             // violate our internal invariants.
     591           0 :             ChipLogError(ExchangeManager, "Dropping message without piggyback ack when we are waiting for an ack.");
     592           0 :             return CHIP_ERROR_INCORRECT_STATE;
     593             :         }
     594             :     } // AllowsMRP
     595             : 
     596             : #if CHIP_CONFIG_ENABLE_ICD_SERVER
     597             :     // message received
     598             :     app::ICDNotifier::GetInstance().NotifyNetworkActivityNotification();
     599             : #endif // CHIP_CONFIG_ENABLE_ICD_SERVER
     600             : 
     601             :     // Set kFlagReceivedAtLeastOneMessage to true since we have received at least one new application level message
     602        7924 :     SetHasReceivedAtLeastOneMessage(true);
     603             : 
     604        7924 :     if (IsResponseExpected())
     605             :     {
     606             :         // Since we got the response, cancel the response timer.
     607        6251 :         CancelResponseTimer();
     608             : 
     609             :         // If the context was expecting a response to a previously sent message, this message
     610             :         // is implicitly that response.
     611        6251 :         SetResponseExpected(false);
     612             :     }
     613             : 
     614             :     // Don't send messages on to our delegate if our dispatch does not allow
     615             :     // those messages.
     616        7924 :     if (mDelegate != nullptr && mDispatch.MessagePermitted(payloadHeader.GetProtocolID(), payloadHeader.GetMessageType()))
     617             :     {
     618        7842 :         return mDelegate->OnMessageReceived(this, payloadHeader, std::move(msgBuf));
     619             :     }
     620             : 
     621          82 :     DefaultOnMessageReceived(this, payloadHeader.GetProtocolID(), payloadHeader.GetMessageType(), messageCounter,
     622          82 :                              std::move(msgBuf));
     623          82 :     return CHIP_NO_ERROR;
     624        9417 : }
     625             : 
     626       17401 : void ExchangeContext::MessageHandled()
     627             : {
     628       17401 :     if (mFlags.Has(Flags::kFlagClosed) || IsResponseExpected() || IsSendExpected())
     629             :     {
     630       14361 :         return;
     631             :     }
     632             : 
     633        3040 :     Close();
     634             : }
     635             : 
     636        3268 : ExchangeMessageDispatch & ExchangeContext::GetMessageDispatch(bool isEphemeralExchange, ExchangeDelegate * delegate)
     637             : {
     638        3268 :     if (isEphemeralExchange)
     639          13 :         return EphemeralExchangeDispatch::Instance();
     640             : 
     641        3255 :     if (delegate != nullptr)
     642        3245 :         return delegate->GetMessageDispatch();
     643             : 
     644          10 :     return ApplicationExchangeDispatch::Instance();
     645             : }
     646             : 
     647           2 : void ExchangeContext::AbortAllOtherCommunicationOnFabric()
     648             : {
     649           2 :     if (!mSession || !mSession->IsSecureSession())
     650             :     {
     651           0 :         ChipLogError(ExchangeManager, "AbortAllOtherCommunicationOnFabric called when we don't have a PASE/CASE session");
     652           0 :         return;
     653             :     }
     654             : 
     655             :     // Save our session so it does not actually go away.
     656           2 :     Optional<SessionHandle> session = mSession.Get();
     657             : 
     658           2 :     SetIgnoreSessionRelease(true);
     659             : 
     660           2 :     GetExchangeMgr()->GetSessionManager()->ExpireAllSessionsForFabric(mSession->GetFabricIndex());
     661             : 
     662           2 :     mSession.GrabExpiredSession(session.Value());
     663             : 
     664           2 :     SetIgnoreSessionRelease(false);
     665           2 : }
     666             : 
     667           2 : void ExchangeContext::ExchangeSessionHolder::GrabExpiredSession(const SessionHandle & session)
     668             : {
     669           2 :     VerifyOrDie(session->AsSecureSession()->IsPendingEviction());
     670           2 :     GrabUnchecked(session);
     671           2 : }
     672             : 
     673             : } // namespace Messaging
     674             : } // namespace chip

Generated by: LCOV version 1.14