Matter SDK Coverage Report
Current view: top level - messaging - ExchangeContext.cpp (source / functions) Coverage Total Hit
Test: SHA:f1767a8b0a3778fdf31b1d979afbdf544892fd94 Lines: 91.2 % 226 206
Test Date: 2026-06-03 07:35:21 Functions: 89.3 % 28 25

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

Generated by: LCOV version 2.0-1