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
|