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

Generated by: LCOV version 2.0-1