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
|