Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020 Project CHIP Authors
4 : * All rights reserved.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 : #include <app/AppConfig.h>
19 : #include <app/AttributePathExpandIterator.h>
20 : #include <app/InteractionModelEngine.h>
21 : #include <app/MessageDef/EventPathIB.h>
22 : #include <app/MessageDef/StatusResponseMessage.h>
23 : #include <app/MessageDef/SubscribeRequestMessage.h>
24 : #include <app/MessageDef/SubscribeResponseMessage.h>
25 : #include <app/data-model-provider/Provider.h>
26 : #include <app/icd/server/ICDServerConfig.h>
27 : #include <lib/core/TLVUtilities.h>
28 : #include <lib/support/CodeUtils.h>
29 : #include <messaging/ExchangeContext.h>
30 :
31 : #include <app/ReadHandler.h>
32 : #include <app/reporting/Engine.h>
33 :
34 : #if CHIP_CONFIG_ENABLE_ICD_SERVER
35 : #include <app/icd/server/ICDConfigurationData.h> //nogncheck
36 : #endif
37 :
38 : namespace chip {
39 : namespace app {
40 : using Status = Protocols::InteractionModel::Status;
41 :
42 33 : uint16_t ReadHandler::GetPublisherSelectedIntervalLimit()
43 : {
44 : #if CHIP_CONFIG_ENABLE_ICD_SERVER
45 : // We don't need to check for precision loss since the max value of the IdleModeDuration can fit inside a uint16_t
46 : const auto idleModeDuration =
47 : std::chrono::duration_cast<System::Clock::Seconds16>(ICDConfigurationData::GetInstance().GetIdleModeDuration()).count();
48 : return std::max(idleModeDuration, kSubscriptionMaxIntervalPublisherLimit);
49 : #else
50 33 : return kSubscriptionMaxIntervalPublisherLimit;
51 : #endif
52 : }
53 :
54 1136 : ReadHandler::ReadHandler(ManagementCallback & apCallback, Messaging::ExchangeContext * apExchangeContext,
55 1136 : InteractionType aInteractionType, Observer * observer) :
56 1136 : mExchangeCtx(*this),
57 2272 : mManagementCallback(apCallback)
58 : {
59 1136 : VerifyOrDie(apExchangeContext != nullptr);
60 :
61 1136 : mExchangeCtx.Grab(apExchangeContext);
62 : #if CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
63 : // TODO: this should be replaced by a pointer to the InteractionModelEngine that created the ReadHandler
64 : // once InteractionModelEngine is no longer a singleton (see issue 23625)
65 : mExchangeMgr = apExchangeContext->GetExchangeMgr();
66 : #endif // CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
67 :
68 1136 : mInteractionType = aInteractionType;
69 1136 : mLastWrittenEventsBytes = 0;
70 1136 : mTransactionStartGeneration = mManagementCallback.GetInteractionModelEngine()->GetReportingEngine().GetDirtySetGeneration();
71 1136 : mFlags.ClearAll();
72 1136 : SetStateFlag(ReadHandlerFlags::PrimingReports);
73 :
74 1136 : mSessionHandle.Grab(mExchangeCtx->GetSessionHandle());
75 :
76 1136 : VerifyOrDie(observer != nullptr);
77 1136 : mObserver = observer;
78 1136 : }
79 :
80 : #if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
81 0 : ReadHandler::ReadHandler(ManagementCallback & apCallback, Observer * observer) :
82 0 : mExchangeCtx(*this), mManagementCallback(apCallback)
83 : {
84 0 : mInteractionType = InteractionType::Subscribe;
85 0 : mFlags.ClearAll();
86 :
87 0 : VerifyOrDie(observer != nullptr);
88 0 : mObserver = observer;
89 0 : }
90 :
91 0 : void ReadHandler::OnSubscriptionResumed(const SessionHandle & sessionHandle,
92 : SubscriptionResumptionSessionEstablisher & resumptionSessionEstablisher)
93 : {
94 0 : mSubscriptionId = resumptionSessionEstablisher.mSubscriptionInfo.mSubscriptionId;
95 0 : mMinIntervalFloorSeconds = resumptionSessionEstablisher.mSubscriptionInfo.mMinInterval;
96 0 : mMaxInterval = resumptionSessionEstablisher.mSubscriptionInfo.mMaxInterval;
97 0 : SetStateFlag(ReadHandlerFlags::FabricFiltered, resumptionSessionEstablisher.mSubscriptionInfo.mFabricFiltered);
98 :
99 : // Move dynamically allocated attributes and events from the SubscriptionInfo struct into
100 : // the object pool managed by the IM engine
101 0 : for (size_t i = 0; i < resumptionSessionEstablisher.mSubscriptionInfo.mAttributePaths.AllocatedSize(); i++)
102 : {
103 0 : AttributePathParams params = resumptionSessionEstablisher.mSubscriptionInfo.mAttributePaths[i].GetParams();
104 0 : CHIP_ERROR err = mManagementCallback.GetInteractionModelEngine()->PushFrontAttributePathList(mpAttributePathList, params);
105 0 : if (err != CHIP_NO_ERROR)
106 : {
107 0 : Close();
108 0 : return;
109 : }
110 : }
111 0 : for (size_t i = 0; i < resumptionSessionEstablisher.mSubscriptionInfo.mEventPaths.AllocatedSize(); i++)
112 : {
113 0 : EventPathParams params = resumptionSessionEstablisher.mSubscriptionInfo.mEventPaths[i].GetParams();
114 0 : CHIP_ERROR err = mManagementCallback.GetInteractionModelEngine()->PushFrontEventPathParamsList(mpEventPathList, params);
115 0 : if (err != CHIP_NO_ERROR)
116 : {
117 0 : Close();
118 0 : return;
119 : }
120 : }
121 :
122 0 : mSessionHandle.Grab(sessionHandle);
123 :
124 0 : SetStateFlag(ReadHandlerFlags::ActiveSubscription);
125 :
126 0 : auto * appCallback = mManagementCallback.GetAppCallback();
127 0 : if (appCallback)
128 : {
129 0 : appCallback->OnSubscriptionEstablished(*this);
130 : }
131 : // Notify the observer that a subscription has been resumed
132 0 : mObserver->OnSubscriptionEstablished(this);
133 :
134 0 : MoveToState(HandlerState::CanStartReporting);
135 :
136 0 : SingleLinkedListNode<AttributePathParams> * attributePath = mpAttributePathList;
137 0 : while (attributePath)
138 : {
139 0 : TEMPORARY_RETURN_IGNORED mManagementCallback.GetInteractionModelEngine()->GetReportingEngine().SetDirty(
140 0 : attributePath->mValue);
141 0 : attributePath = attributePath->mpNext;
142 : }
143 : }
144 :
145 : #endif // CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
146 :
147 1136 : ReadHandler::~ReadHandler()
148 : {
149 1136 : mObserver->OnReadHandlerDestroyed(this);
150 :
151 1136 : auto * appCallback = mManagementCallback.GetAppCallback();
152 1136 : if (mFlags.Has(ReadHandlerFlags::ActiveSubscription) && appCallback)
153 : {
154 240 : mFlags.Clear(ReadHandlerFlags::ActiveSubscription);
155 240 : appCallback->OnSubscriptionTerminated(*this);
156 : }
157 :
158 1136 : if (IsAwaitingReportResponse())
159 : {
160 2 : mManagementCallback.GetInteractionModelEngine()->GetReportingEngine().OnReportConfirm();
161 : }
162 1136 : mManagementCallback.GetInteractionModelEngine()->ReleaseAttributePathList(mpAttributePathList);
163 1136 : mManagementCallback.GetInteractionModelEngine()->ReleaseEventPathList(mpEventPathList);
164 1136 : mManagementCallback.GetInteractionModelEngine()->ReleaseDataVersionFilterList(mpDataVersionFilterList);
165 1136 : }
166 :
167 868 : void ReadHandler::Close(CloseOptions options)
168 : {
169 : #if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
170 868 : if (IsType(InteractionType::Subscribe) && options == CloseOptions::kDropPersistedSubscription)
171 : {
172 102 : auto * subscriptionResumptionStorage = mManagementCallback.GetInteractionModelEngine()->GetSubscriptionResumptionStorage();
173 102 : if (subscriptionResumptionStorage)
174 : {
175 0 : TEMPORARY_RETURN_IGNORED subscriptionResumptionStorage->Delete(GetInitiatorNodeId(), GetAccessingFabricIndex(),
176 : mSubscriptionId);
177 : }
178 : }
179 : #endif // CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
180 :
181 : #if CHIP_PROGRESS_LOGGING
182 868 : if (IsType(InteractionType::Subscribe))
183 : {
184 116 : const ScopedNodeId & peer = mSessionHandle ? mSessionHandle->GetPeer() : ScopedNodeId();
185 116 : ChipLogProgress(DataManagement, "Subscription id 0x%" PRIx32 " from node " ChipLogFormatScopedNodeId " torn down",
186 : mSubscriptionId, ChipLogValueScopedNodeId(peer));
187 : }
188 : #endif // CHIP_PROGRESS_LOGGING
189 :
190 868 : MoveToState(HandlerState::AwaitingDestruction);
191 868 : mManagementCallback.OnDone(*this);
192 868 : }
193 :
194 1090 : void ReadHandler::OnInitialRequest(System::PacketBufferHandle && aPayload)
195 : {
196 1090 : CHIP_ERROR err = CHIP_NO_ERROR;
197 1090 : System::PacketBufferHandle response;
198 :
199 1090 : if (IsType(InteractionType::Subscribe))
200 : {
201 303 : err = ProcessSubscribeRequest(std::move(aPayload));
202 : }
203 : else
204 : {
205 787 : err = ProcessReadRequest(std::move(aPayload));
206 : }
207 :
208 2180 : if (err != CHIP_NO_ERROR)
209 : {
210 8 : Status status = Status::InvalidAction;
211 8 : if (err.IsIMStatus())
212 : {
213 0 : status = StatusIB(err).mStatus;
214 : }
215 8 : TEMPORARY_RETURN_IGNORED StatusResponse::Send(status, mExchangeCtx.Get(), /* aExpectResponse = */ false);
216 : // At this point we can't have a persisted subscription, since that
217 : // happens only when ProcessSubscribeRequest returns success. And our
218 : // subscription id is almost certainly not actually useful at this
219 : // point, either. So don't try to mess with persisted subscriptions in
220 : // Close().
221 8 : Close(CloseOptions::kKeepPersistedSubscription);
222 : }
223 : else
224 : {
225 : // Force us to be in a dirty state so we get processed by the reporting
226 1082 : SetStateFlag(ReadHandlerFlags::ForceDirty);
227 : }
228 1090 : }
229 :
230 1231 : CHIP_ERROR ReadHandler::OnStatusResponse(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload,
231 : bool & aSendStatusResponse)
232 : {
233 1231 : CHIP_ERROR err = CHIP_NO_ERROR;
234 1231 : aSendStatusResponse = true;
235 1231 : CHIP_ERROR statusError = CHIP_NO_ERROR;
236 1231 : SuccessOrExit(err = StatusResponse::ProcessStatusResponse(std::move(aPayload), statusError));
237 : // Since this is a valid Status Response message, we don't have to send a Status Response in reply to it.
238 1229 : aSendStatusResponse = false;
239 1229 : SuccessOrExit(err = statusError);
240 1217 : switch (mState)
241 : {
242 1217 : case HandlerState::AwaitingReportResponse:
243 1217 : if (IsChunkedReport())
244 : {
245 856 : mExchangeCtx->WillSendMessage();
246 : }
247 361 : else if (IsType(InteractionType::Subscribe))
248 : {
249 361 : if (IsPriming())
250 : {
251 284 : err = SendSubscribeResponse();
252 :
253 284 : SetStateFlag(ReadHandlerFlags::ActiveSubscription);
254 284 : auto * appCallback = mManagementCallback.GetAppCallback();
255 284 : if (appCallback)
256 : {
257 240 : appCallback->OnSubscriptionEstablished(*this);
258 : }
259 284 : mObserver->OnSubscriptionEstablished(this);
260 : }
261 : }
262 : else
263 : {
264 : //
265 : // We're done processing a read, so let's close out and return.
266 : //
267 0 : Close();
268 0 : return CHIP_NO_ERROR;
269 : }
270 :
271 1217 : MoveToState(HandlerState::CanStartReporting);
272 1217 : break;
273 :
274 0 : case HandlerState::CanStartReporting:
275 : case HandlerState::Idle:
276 : default:
277 0 : err = CHIP_ERROR_INCORRECT_STATE;
278 0 : break;
279 : }
280 :
281 1231 : exit:
282 1231 : return err;
283 : }
284 :
285 31 : CHIP_ERROR ReadHandler::SendStatusReport(Protocols::InteractionModel::Status aStatus)
286 : {
287 31 : VerifyOrReturnLogError(mState == HandlerState::CanStartReporting, CHIP_ERROR_INCORRECT_STATE);
288 31 : if (IsPriming() || IsChunkedReport())
289 : {
290 31 : mSessionHandle.Grab(mExchangeCtx->GetSessionHandle());
291 : }
292 : else
293 : {
294 0 : VerifyOrReturnLogError(!mExchangeCtx, CHIP_ERROR_INCORRECT_STATE);
295 0 : VerifyOrReturnLogError(mSessionHandle, CHIP_ERROR_INCORRECT_STATE);
296 : #if CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
297 : auto exchange = mExchangeMgr->NewContext(mSessionHandle.Get().Value(), this);
298 : #else // CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
299 : auto exchange =
300 0 : mManagementCallback.GetInteractionModelEngine()->GetExchangeManager()->NewContext(mSessionHandle.Get().Value(), this);
301 : #endif // CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
302 0 : VerifyOrReturnLogError(exchange != nullptr, CHIP_ERROR_INCORRECT_STATE);
303 0 : mExchangeCtx.Grab(exchange);
304 : }
305 :
306 31 : VerifyOrReturnLogError(mExchangeCtx, CHIP_ERROR_INCORRECT_STATE);
307 31 : return StatusResponse::Send(aStatus, mExchangeCtx.Get(), /* aExpectResponse = */ false);
308 : }
309 :
310 1953 : CHIP_ERROR ReadHandler::SendReportData(System::PacketBufferHandle && aPayload, bool aMoreChunks)
311 : {
312 1953 : VerifyOrReturnLogError(mState == HandlerState::CanStartReporting, CHIP_ERROR_INCORRECT_STATE);
313 1949 : VerifyOrDie(!IsAwaitingReportResponse()); // Should not be reportable!
314 1949 : if (IsPriming() || IsChunkedReport())
315 : {
316 1863 : mSessionHandle.Grab(mExchangeCtx->GetSessionHandle());
317 : }
318 : else
319 : {
320 86 : VerifyOrReturnLogError(!mExchangeCtx, CHIP_ERROR_INCORRECT_STATE);
321 86 : VerifyOrReturnLogError(mSessionHandle, CHIP_ERROR_INCORRECT_STATE);
322 : #if CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
323 : auto exchange = mExchangeMgr->NewContext(mSessionHandle.Get().Value(), this);
324 : #else // CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
325 : auto exchange =
326 86 : mManagementCallback.GetInteractionModelEngine()->GetExchangeManager()->NewContext(mSessionHandle.Get().Value(), this);
327 : #endif // CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
328 86 : VerifyOrReturnLogError(exchange != nullptr, CHIP_ERROR_INCORRECT_STATE);
329 84 : mExchangeCtx.Grab(exchange);
330 : }
331 :
332 1947 : VerifyOrReturnLogError(mExchangeCtx, CHIP_ERROR_INCORRECT_STATE);
333 :
334 1947 : if (!IsReporting())
335 : {
336 1135 : mCurrentReportsBeginGeneration =
337 1135 : mManagementCallback.GetInteractionModelEngine()->GetReportingEngine().GetDirtySetGeneration();
338 : }
339 1947 : SetStateFlag(ReadHandlerFlags::ChunkedReport, aMoreChunks);
340 1947 : bool responseExpected = IsType(InteractionType::Subscribe) || aMoreChunks;
341 :
342 1947 : mExchangeCtx->UseSuggestedResponseTimeout(app::kExpectedIMProcessingTime);
343 1947 : CHIP_ERROR err = mExchangeCtx->SendMessage(Protocols::InteractionModel::MsgType::ReportData, std::move(aPayload),
344 : responseExpected ? Messaging::SendMessageFlags::kExpectResponse
345 : : Messaging::SendMessageFlags::kNone);
346 3894 : if (err == CHIP_NO_ERROR)
347 : {
348 1945 : if (responseExpected)
349 : {
350 1241 : MoveToState(HandlerState::AwaitingReportResponse);
351 : }
352 : else
353 : {
354 : // Make sure we're not treated as an in-flight report waiting for a
355 : // response by the reporting engine.
356 704 : mManagementCallback.GetInteractionModelEngine()->GetReportingEngine().OnReportConfirm();
357 : }
358 :
359 : // If we just finished a non-priming subscription report, notify our observers.
360 : // Priming reports are handled when we send a SubscribeResponse.
361 1945 : if (IsType(InteractionType::Subscribe) && !IsPriming() && !IsChunkedReport())
362 : {
363 82 : mObserver->OnSubscriptionReportSent(this);
364 : }
365 : }
366 1947 : if (!aMoreChunks)
367 : {
368 1081 : mPreviousReportsBeginGeneration = mCurrentReportsBeginGeneration;
369 1081 : ClearForceDirtyFlag();
370 1081 : mManagementCallback.GetInteractionModelEngine()->ReleaseDataVersionFilterList(mpDataVersionFilterList);
371 : }
372 :
373 1947 : return err;
374 : }
375 :
376 1233 : CHIP_ERROR ReadHandler::OnMessageReceived(Messaging::ExchangeContext * apExchangeContext, const PayloadHeader & aPayloadHeader,
377 : System::PacketBufferHandle && aPayload)
378 : {
379 1233 : CHIP_ERROR err = CHIP_NO_ERROR;
380 1233 : bool sendStatusResponse = true;
381 1233 : if (aPayloadHeader.HasMessageType(Protocols::InteractionModel::MsgType::StatusResponse))
382 : {
383 1231 : err = OnStatusResponse(apExchangeContext, std::move(aPayload), sendStatusResponse);
384 : }
385 : else
386 : {
387 2 : ChipLogDetail(DataManagement, "ReadHandler:: Msg type %d not supported", aPayloadHeader.GetMessageType());
388 2 : err = CHIP_ERROR_INVALID_MESSAGE_TYPE;
389 : }
390 :
391 1233 : if (sendStatusResponse)
392 : {
393 4 : TEMPORARY_RETURN_IGNORED StatusResponse::Send(Status::InvalidAction, apExchangeContext, false /*aExpectResponse*/);
394 : }
395 :
396 2466 : if (err != CHIP_NO_ERROR)
397 : {
398 16 : Close();
399 : }
400 1233 : return err;
401 : }
402 :
403 10 : bool ReadHandler::IsFromSubscriber(Messaging::ExchangeContext & apExchangeContext) const
404 : {
405 10 : return (IsType(InteractionType::Subscribe) &&
406 30 : GetInitiatorNodeId() == apExchangeContext.GetSessionHandle()->AsSecureSession()->GetPeerNodeId() &&
407 20 : GetAccessingFabricIndex() == apExchangeContext.GetSessionHandle()->GetFabricIndex());
408 : }
409 :
410 8 : void ReadHandler::OnResponseTimeout(Messaging::ExchangeContext * apExchangeContext)
411 : {
412 8 : ChipLogError(DataManagement, "Time out! failed to receive status response from Exchange: " ChipLogFormatExchange,
413 : ChipLogValueExchange(apExchangeContext));
414 : #if CHIP_CONFIG_ENABLE_ICD_SERVER && CHIP_CONFIG_ENABLE_ICD_CIP && CHIP_CONFIG_ENABLE_ICD_CHECK_IN_ON_REPORT_TIMEOUT
415 : switch (mState)
416 : {
417 : case HandlerState::AwaitingReportResponse:
418 : if (IsType(InteractionType::Subscribe) && !IsPriming())
419 : {
420 : // Trigger check-in message when a non-priming subscription report times out.
421 : ChipLogError(DataManagement, "Trigger check-in message when non-priming subscription report times out");
422 : if (mSessionHandle)
423 : {
424 : ICDNotifier::GetInstance().NotifySendCheckIn(GetSubjectDescriptor());
425 : }
426 : else
427 : {
428 : ChipLogError(DataManagement, "Failed to get subject descriptor for sending check-in message on report timeout");
429 : }
430 : }
431 : break;
432 : case HandlerState::CanStartReporting:
433 : case HandlerState::Idle:
434 : default:
435 : break;
436 : }
437 : #endif // CHIP_CONFIG_ENABLE_ICD_CIP && CHIP_CONFIG_ENABLE_ICD_SERVER
438 :
439 : #if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
440 8 : Close(CloseOptions::kKeepPersistedSubscription);
441 : #else
442 : Close();
443 : #endif
444 8 : }
445 :
446 791 : CHIP_ERROR ReadHandler::ProcessReadRequest(System::PacketBufferHandle && aPayload)
447 : {
448 791 : CHIP_ERROR err = CHIP_NO_ERROR;
449 791 : System::PacketBufferTLVReader reader;
450 :
451 791 : ReadRequestMessage::Parser readRequestParser;
452 791 : EventPathIBs::Parser eventPathListParser;
453 791 : EventFilterIBs::Parser eventFilterIBsParser;
454 791 : AttributePathIBs::Parser attributePathListParser;
455 :
456 791 : reader.Init(std::move(aPayload));
457 :
458 791 : ReturnErrorOnFailure(readRequestParser.Init(reader));
459 :
460 : // No need to pretty-print here. We pretty-print read requests in the read
461 : // case of InteractionModelEngine::OnReadInitialRequest, so we do it even if
462 : // we reject a read request.
463 :
464 791 : err = readRequestParser.GetAttributeRequests(&attributePathListParser);
465 1582 : if (err == CHIP_END_OF_TLV)
466 : {
467 122 : err = CHIP_NO_ERROR;
468 : }
469 1338 : else if (err == CHIP_NO_ERROR)
470 : {
471 669 : ReturnErrorOnFailure(ProcessAttributePaths(attributePathListParser));
472 669 : DataVersionFilterIBs::Parser dataVersionFilterListParser;
473 669 : err = readRequestParser.GetDataVersionFilters(&dataVersionFilterListParser);
474 1338 : if (err == CHIP_END_OF_TLV)
475 : {
476 589 : err = CHIP_NO_ERROR;
477 : }
478 160 : else if (err == CHIP_NO_ERROR)
479 : {
480 80 : ReturnErrorOnFailure(ProcessDataVersionFilterList(dataVersionFilterListParser));
481 : }
482 : }
483 791 : ReturnErrorOnFailure(err);
484 791 : err = readRequestParser.GetEventRequests(&eventPathListParser);
485 1582 : if (err == CHIP_END_OF_TLV)
486 : {
487 473 : err = CHIP_NO_ERROR;
488 : }
489 636 : else if (err == CHIP_NO_ERROR)
490 : {
491 318 : ReturnErrorOnFailure(err);
492 318 : ReturnErrorOnFailure(ProcessEventPaths(eventPathListParser));
493 318 : err = readRequestParser.GetEventFilters(&eventFilterIBsParser);
494 636 : if (err == CHIP_END_OF_TLV)
495 : {
496 3 : err = CHIP_NO_ERROR;
497 : }
498 630 : else if (err == CHIP_NO_ERROR)
499 : {
500 315 : ReturnErrorOnFailure(ProcessEventFilters(eventFilterIBsParser));
501 : }
502 : }
503 791 : ReturnErrorOnFailure(err);
504 :
505 : bool isFabricFiltered;
506 791 : ReturnErrorOnFailure(readRequestParser.GetIsFabricFiltered(&isFabricFiltered));
507 787 : SetStateFlag(ReadHandlerFlags::FabricFiltered, isFabricFiltered);
508 787 : ReturnErrorOnFailure(readRequestParser.ExitContainer());
509 787 : MoveToState(HandlerState::CanStartReporting);
510 :
511 787 : mExchangeCtx->WillSendMessage();
512 :
513 : // There must be no code after the WillSendMessage() call that can cause
514 : // this method to return a failure.
515 :
516 787 : return CHIP_NO_ERROR;
517 791 : }
518 :
519 970 : CHIP_ERROR ReadHandler::ProcessAttributePaths(AttributePathIBs::Parser & aAttributePathListParser)
520 : {
521 970 : CHIP_ERROR err = CHIP_NO_ERROR;
522 970 : TLV::TLVReader reader;
523 970 : aAttributePathListParser.GetReader(&reader);
524 5022 : while (CHIP_NO_ERROR == (err = reader.Next()))
525 : {
526 1541 : VerifyOrReturnError(TLV::AnonymousTag() == reader.GetTag(), CHIP_ERROR_INVALID_TLV_TAG);
527 1541 : AttributePathParams attribute;
528 1541 : AttributePathIB::Parser path;
529 1541 : ReturnErrorOnFailure(path.Init(reader));
530 1541 : ReturnErrorOnFailure(path.ParsePath(attribute));
531 1541 : ReturnErrorOnFailure(
532 : mManagementCallback.GetInteractionModelEngine()->PushFrontAttributePathList(mpAttributePathList, attribute));
533 : }
534 : // if we have exhausted this container
535 1940 : if (CHIP_END_OF_TLV == err)
536 : {
537 970 : mManagementCallback.GetInteractionModelEngine()->RemoveDuplicateConcreteAttributePath(mpAttributePathList);
538 970 : mAttributePathExpandPosition = AttributePathExpandIterator::Position::StartIterating(mpAttributePathList);
539 970 : err = CHIP_NO_ERROR;
540 : }
541 970 : return err;
542 : }
543 :
544 145 : CHIP_ERROR ReadHandler::ProcessDataVersionFilterList(DataVersionFilterIBs::Parser & aDataVersionFilterListParser)
545 : {
546 145 : CHIP_ERROR err = CHIP_NO_ERROR;
547 145 : TLV::TLVReader reader;
548 :
549 145 : aDataVersionFilterListParser.GetReader(&reader);
550 5274 : while (CHIP_NO_ERROR == (err = reader.Next()))
551 : {
552 2492 : VerifyOrReturnError(TLV::AnonymousTag() == reader.GetTag(), CHIP_ERROR_INVALID_TLV_TAG);
553 2492 : DataVersionFilter versionFilter;
554 2492 : ClusterPathIB::Parser path;
555 2492 : DataVersionFilterIB::Parser filter;
556 2492 : ReturnErrorOnFailure(filter.Init(reader));
557 2492 : DataVersion version = 0;
558 2492 : ReturnErrorOnFailure(filter.GetDataVersion(&version));
559 2492 : versionFilter.mDataVersion.SetValue(version);
560 2492 : ReturnErrorOnFailure(filter.GetPath(&path));
561 2492 : ReturnErrorOnFailure(path.GetEndpoint(&(versionFilter.mEndpointId)));
562 2492 : ReturnErrorOnFailure(path.GetCluster(&(versionFilter.mClusterId)));
563 2492 : VerifyOrReturnError(versionFilter.IsValidDataVersionFilter(), CHIP_ERROR_IM_MALFORMED_DATA_VERSION_FILTER_IB);
564 2492 : ReturnErrorOnFailure(mManagementCallback.GetInteractionModelEngine()->PushFrontDataVersionFilterList(
565 : mpDataVersionFilterList, versionFilter));
566 : }
567 :
568 290 : if (CHIP_END_OF_TLV == err)
569 : {
570 145 : err = CHIP_NO_ERROR;
571 : }
572 145 : return err;
573 : }
574 :
575 336 : CHIP_ERROR ReadHandler::ProcessEventPaths(EventPathIBs::Parser & aEventPathsParser)
576 : {
577 336 : CHIP_ERROR err = CHIP_NO_ERROR;
578 336 : TLV::TLVReader reader;
579 336 : aEventPathsParser.GetReader(&reader);
580 1670 : while (CHIP_NO_ERROR == (err = reader.Next()))
581 : {
582 499 : VerifyOrReturnError(TLV::AnonymousTag() == reader.GetTag(), CHIP_ERROR_INVALID_TLV_TAG);
583 499 : EventPathParams event;
584 499 : EventPathIB::Parser path;
585 499 : ReturnErrorOnFailure(path.Init(reader));
586 499 : ReturnErrorOnFailure(path.ParsePath(event));
587 499 : ReturnErrorOnFailure(mManagementCallback.GetInteractionModelEngine()->PushFrontEventPathParamsList(mpEventPathList, event));
588 : }
589 :
590 : // if we have exhausted this container
591 672 : if (CHIP_END_OF_TLV == err)
592 : {
593 336 : err = CHIP_NO_ERROR;
594 : }
595 336 : return err;
596 : }
597 :
598 315 : CHIP_ERROR ReadHandler::ProcessEventFilters(EventFilterIBs::Parser & aEventFiltersParser)
599 : {
600 315 : CHIP_ERROR err = CHIP_NO_ERROR;
601 315 : TLV::TLVReader reader;
602 315 : aEventFiltersParser.GetReader(&reader);
603 :
604 1260 : while (CHIP_NO_ERROR == (err = reader.Next()))
605 : {
606 315 : VerifyOrReturnError(TLV::AnonymousTag() == reader.GetTag(), CHIP_ERROR_INVALID_TLV_TAG);
607 315 : EventFilterIB::Parser filter;
608 315 : ReturnErrorOnFailure(filter.Init(reader));
609 : // this is for current node, and would have only one event filter.
610 315 : ReturnErrorOnFailure(filter.GetEventMin(&(mEventMin)));
611 : }
612 630 : if (CHIP_END_OF_TLV == err)
613 : {
614 315 : err = CHIP_NO_ERROR;
615 : }
616 315 : return err;
617 : }
618 :
619 4428 : const char * ReadHandler::GetStateStr() const
620 : {
621 : #if CHIP_DETAIL_LOGGING
622 4428 : switch (mState)
623 : {
624 4 : case HandlerState::Idle:
625 4 : return "Idle";
626 868 : case HandlerState::AwaitingDestruction:
627 868 : return "AwaitingDestruction";
628 2315 : case HandlerState::CanStartReporting:
629 2315 : return "CanStartReporting";
630 :
631 1241 : case HandlerState::AwaitingReportResponse:
632 1241 : return "AwaitingReportResponse";
633 : }
634 : #endif // CHIP_DETAIL_LOGGING
635 0 : return "N/A";
636 : }
637 :
638 4428 : void ReadHandler::MoveToState(const HandlerState aTargetState)
639 : {
640 4428 : if (aTargetState == mState)
641 : {
642 0 : return;
643 : }
644 :
645 4428 : if (IsAwaitingReportResponse() && aTargetState != HandlerState::AwaitingReportResponse)
646 : {
647 1239 : mManagementCallback.GetInteractionModelEngine()->GetReportingEngine().OnReportConfirm();
648 : }
649 :
650 4428 : mState = aTargetState;
651 4428 : ChipLogDetail(DataManagement, "IM RH moving to [%s]", GetStateStr());
652 :
653 : //
654 : // If we just unblocked sending reports, let's go ahead and schedule the reporting
655 : // engine to run to kick that off.
656 : //
657 4428 : if (aTargetState == HandlerState::CanStartReporting)
658 : {
659 2315 : if (ShouldReportUnscheduled())
660 : {
661 1921 : TEMPORARY_RETURN_IGNORED mManagementCallback.GetInteractionModelEngine()->GetReportingEngine().ScheduleRun();
662 : }
663 : else
664 : {
665 : // If we became reportable, the scheduler will schedule a run as soon as allowed
666 394 : mObserver->OnBecameReportable(this);
667 : }
668 : }
669 : }
670 :
671 888 : bool ReadHandler::CheckEventClean(EventManagement & aEventManager)
672 : {
673 888 : if (mFlags.Has(ReadHandlerFlags::ChunkedReport))
674 : {
675 525 : if ((mLastScheduledEventNumber != 0) && (mEventMin <= mLastScheduledEventNumber))
676 : {
677 519 : return false;
678 : }
679 : }
680 : else
681 : {
682 363 : EventNumber lastEventNumber = aEventManager.GetLastEventNumber();
683 363 : if ((lastEventNumber != 0) && (mEventMin <= lastEventNumber))
684 : {
685 : // We have more events. snapshot last event number
686 345 : aEventManager.SetScheduledEventInfo(mLastScheduledEventNumber, mLastWrittenEventsBytes);
687 345 : return false;
688 : }
689 : }
690 24 : return true;
691 : }
692 :
693 284 : CHIP_ERROR ReadHandler::SendSubscribeResponse()
694 : {
695 284 : System::PacketBufferHandle packet = System::PacketBufferHandle::New(chip::app::kMaxSecureSduLengthBytes);
696 284 : VerifyOrReturnLogError(!packet.IsNull(), CHIP_ERROR_NO_MEMORY);
697 :
698 284 : System::PacketBufferTLVWriter writer;
699 284 : writer.Init(std::move(packet));
700 :
701 284 : SubscribeResponseMessage::Builder response;
702 284 : ReturnErrorOnFailure(response.Init(&writer));
703 284 : ReturnErrorOnFailure(response.SubscriptionId(mSubscriptionId).MaxInterval(mMaxInterval).EndOfSubscribeResponseMessage());
704 :
705 284 : ReturnErrorOnFailure(writer.Finalize(&packet));
706 284 : VerifyOrReturnLogError(mExchangeCtx, CHIP_ERROR_INCORRECT_STATE);
707 :
708 284 : ClearStateFlag(ReadHandlerFlags::PrimingReports);
709 284 : return mExchangeCtx->SendMessage(Protocols::InteractionModel::MsgType::SubscribeResponse, std::move(packet));
710 284 : }
711 :
712 307 : CHIP_ERROR ReadHandler::ProcessSubscribeRequest(System::PacketBufferHandle && aPayload)
713 : {
714 307 : System::PacketBufferTLVReader reader;
715 307 : reader.Init(std::move(aPayload));
716 :
717 307 : SubscribeRequestMessage::Parser subscribeRequestParser;
718 307 : ReturnErrorOnFailure(subscribeRequestParser.Init(reader));
719 :
720 : // No need to pretty-print here. We pretty-print subscribe requests in the
721 : // subscribe case of InteractionModelEngine::OnReadInitialRequest, so we do
722 : // it even if we reject a subscribe request.
723 :
724 307 : AttributePathIBs::Parser attributePathListParser;
725 307 : CHIP_ERROR err = subscribeRequestParser.GetAttributeRequests(&attributePathListParser);
726 614 : if (err == CHIP_END_OF_TLV)
727 : {
728 6 : err = CHIP_NO_ERROR;
729 : }
730 602 : else if (err == CHIP_NO_ERROR)
731 : {
732 301 : ReturnErrorOnFailure(ProcessAttributePaths(attributePathListParser));
733 301 : DataVersionFilterIBs::Parser dataVersionFilterListParser;
734 301 : err = subscribeRequestParser.GetDataVersionFilters(&dataVersionFilterListParser);
735 602 : if (err == CHIP_END_OF_TLV)
736 : {
737 236 : err = CHIP_NO_ERROR;
738 : }
739 130 : else if (err == CHIP_NO_ERROR)
740 : {
741 65 : ReturnErrorOnFailure(ProcessDataVersionFilterList(dataVersionFilterListParser));
742 : }
743 : }
744 307 : ReturnErrorOnFailure(err);
745 :
746 307 : EventPathIBs::Parser eventPathListParser;
747 307 : err = subscribeRequestParser.GetEventRequests(&eventPathListParser);
748 614 : if (err == CHIP_END_OF_TLV)
749 : {
750 289 : err = CHIP_NO_ERROR;
751 : }
752 36 : else if (err == CHIP_NO_ERROR)
753 : {
754 18 : ReturnErrorOnFailure(ProcessEventPaths(eventPathListParser));
755 18 : EventFilterIBs::Parser eventFilterIBsParser;
756 18 : err = subscribeRequestParser.GetEventFilters(&eventFilterIBsParser);
757 36 : if (err == CHIP_END_OF_TLV)
758 : {
759 18 : err = CHIP_NO_ERROR;
760 : }
761 0 : else if (err == CHIP_NO_ERROR)
762 : {
763 0 : ReturnErrorOnFailure(ProcessEventFilters(eventFilterIBsParser));
764 : }
765 : }
766 307 : ReturnErrorOnFailure(err);
767 :
768 307 : ReturnErrorOnFailure(subscribeRequestParser.GetMinIntervalFloorSeconds(&mMinIntervalFloorSeconds));
769 307 : ReturnErrorOnFailure(subscribeRequestParser.GetMaxIntervalCeilingSeconds(&mSubscriberRequestedMaxInterval));
770 307 : mMaxInterval = mSubscriberRequestedMaxInterval;
771 :
772 307 : VerifyOrReturnError(mMinIntervalFloorSeconds <= mMaxInterval, CHIP_ERROR_INVALID_ARGUMENT);
773 :
774 : #if CHIP_CONFIG_ENABLE_ICD_SERVER
775 :
776 : // To optimize ICD sleep/idle cycles, it is preferred to synchronize the subscription report interval
777 : // with the IdleModeDuration defined in the ICD Management Cluster.
778 : // We aim to use IdleModeDuration, but must respect the Min Interval Floor and Max Interval Ceiling.
779 : // Note: This behavior can be overridden using the OnSubscriptionRequested callback defined
780 : // in the application.
781 :
782 : // Per spec and static checks, GetIdleModeDuration max value fits a uint16_t.
783 : // The final selected interval must be a uint16_t but we use a uint32 here during calculation to prevent overflows.
784 : uint32_t preferredMaxInterval = ICDConfigurationData::GetInstance().GetIdleModeDuration().count();
785 : // Determine the max interval ceiling between GetPublisherSelectedIntervalLimit
786 : // and the subscriber-requested MaxInterval.
787 : uint16_t maxIntervalCeiling = std::max(GetPublisherSelectedIntervalLimit(), mMaxInterval);
788 :
789 : // Spec doesn't allow IdleModeDuration of 0 but make sure here to prevent div0
790 : if (preferredMaxInterval == 0)
791 : {
792 : preferredMaxInterval = maxIntervalCeiling;
793 : }
794 : else
795 : {
796 : // Must respect the minimal interval floor
797 : if (preferredMaxInterval < mMinIntervalFloorSeconds)
798 : {
799 : // Round up to the nearest multiple of IdleModeDuration that is >= mMinIntervalFloorSeconds.
800 : const uint32_t remainder = mMinIntervalFloorSeconds % preferredMaxInterval;
801 : preferredMaxInterval =
802 : remainder == 0 ? mMinIntervalFloorSeconds : (mMinIntervalFloorSeconds + (preferredMaxInterval - remainder));
803 : }
804 :
805 : // Use the smallest interval between preferredMaxInterval and maxIntervalCeiling.
806 : // This also ensure that no overflow occurs when casting to uint16_t below
807 : preferredMaxInterval = std::min<uint32_t>(preferredMaxInterval, maxIntervalCeiling);
808 : }
809 : mMaxInterval = static_cast<uint16_t>(preferredMaxInterval);
810 : #endif // CHIP_CONFIG_ENABLE_ICD_SERVER
811 :
812 : //
813 : // Notify the application (if requested) of the impending subscription and check whether we should still proceed to set it up.
814 : // This also provides the application an opportunity to modify the negotiated min/max intervals set above.
815 : //
816 307 : auto * appCallback = mManagementCallback.GetAppCallback();
817 307 : if (appCallback)
818 : {
819 494 : if (appCallback->OnSubscriptionRequested(*this, *mExchangeCtx->GetSessionHandle()->AsSecureSession()) != CHIP_NO_ERROR)
820 : {
821 6 : return CHIP_ERROR_TRANSACTION_CANCELED;
822 : }
823 : }
824 :
825 301 : ChipLogProgress(DataManagement, "Final negotiated min/max parameters: Min = %ds, Max = %ds", mMinIntervalFloorSeconds,
826 : mMaxInterval);
827 :
828 : bool isFabricFiltered;
829 301 : ReturnErrorOnFailure(subscribeRequestParser.GetIsFabricFiltered(&isFabricFiltered));
830 301 : SetStateFlag(ReadHandlerFlags::FabricFiltered, isFabricFiltered);
831 301 : ReturnErrorOnFailure(Crypto::DRBG_get_bytes(reinterpret_cast<uint8_t *>(&mSubscriptionId), sizeof(mSubscriptionId)));
832 301 : ReturnErrorOnFailure(subscribeRequestParser.ExitContainer());
833 301 : MoveToState(HandlerState::CanStartReporting);
834 :
835 301 : mExchangeCtx->WillSendMessage();
836 :
837 : #if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
838 301 : PersistSubscription();
839 : #endif // CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
840 :
841 301 : return CHIP_NO_ERROR;
842 307 : }
843 :
844 301 : void ReadHandler::PersistSubscription()
845 : {
846 301 : auto * subscriptionResumptionStorage = mManagementCallback.GetInteractionModelEngine()->GetSubscriptionResumptionStorage();
847 301 : VerifyOrReturn(subscriptionResumptionStorage != nullptr);
848 :
849 : // TODO(#31873): We need to store the CAT information to enable better interactions with ICDs
850 0 : SubscriptionResumptionStorage::SubscriptionInfo subscriptionInfo = { .mNodeId = GetInitiatorNodeId(),
851 0 : .mFabricIndex = GetAccessingFabricIndex(),
852 0 : .mSubscriptionId = mSubscriptionId,
853 0 : .mMinInterval = mMinIntervalFloorSeconds,
854 0 : .mMaxInterval = mMaxInterval,
855 0 : .mFabricFiltered = IsFabricFiltered() };
856 0 : VerifyOrReturn(subscriptionInfo.SetAttributePaths(mpAttributePathList) == CHIP_NO_ERROR);
857 0 : VerifyOrReturn(subscriptionInfo.SetEventPaths(mpEventPathList) == CHIP_NO_ERROR);
858 :
859 0 : CHIP_ERROR err = subscriptionResumptionStorage->Save(subscriptionInfo);
860 0 : if (err != CHIP_NO_ERROR)
861 : {
862 0 : ChipLogError(DataManagement, "Failed to save subscription info error: '%" CHIP_ERROR_FORMAT, err.Format());
863 : }
864 0 : }
865 :
866 1168 : void ReadHandler::ResetPathIterator()
867 : {
868 1168 : mAttributePathExpandPosition = AttributePathExpandIterator::Position::StartIterating(mpAttributePathList);
869 1168 : mAttributeEncoderState.Reset();
870 1168 : }
871 :
872 345 : void ReadHandler::AttributePathIsDirty(DataModel::Provider * apDataModel, const AttributePathParams & aAttributeChanged)
873 : {
874 345 : mDirtyGeneration = mManagementCallback.GetInteractionModelEngine()->GetReportingEngine().GetDirtySetGeneration();
875 :
876 : // We want to get the value, but not advance the iterator position.
877 345 : AttributePathExpandIterator::Position tempPosition = mAttributePathExpandPosition;
878 345 : ConcreteAttributePath path;
879 :
880 : // We won't reset the path iterator for every AttributePathIsDirty call to reduce the number of full data reports.
881 : // The iterator will be reset after finishing each report session.
882 : //
883 : // Here we just reset the iterator to the beginning of the current cluster, if the dirty path affects it.
884 : // This will ensure the reports are consistent within a single cluster generated from a single path in the request.
885 :
886 : // TODO (#16699): Currently we can only guarantee the reports generated from a single path in the request are consistent. The
887 : // data might be inconsistent if the user send a request with two paths from the same cluster. We need to clearify the behavior
888 : // or make it consistent.
889 611 : if (AttributePathExpandIterator(apDataModel, tempPosition).Next(path) &&
890 1138 : (aAttributeChanged.HasWildcardEndpointId() || aAttributeChanged.mEndpointId == path.mEndpointId) &&
891 527 : (aAttributeChanged.HasWildcardClusterId() || aAttributeChanged.mClusterId == path.mClusterId))
892 : {
893 264 : ChipLogDetail(DataManagement,
894 : "The dirty path intersects the cluster we are currently reporting; reset the iterator to the beginning of "
895 : "that cluster");
896 : // If we're currently in the middle of generating reports for a given cluster and that in turn is marked dirty, let's reset
897 : // our iterator to point back to the beginning of that cluster. This ensures that the receiver will get a coherent view of
898 : // the state of the cluster as present on the server
899 264 : mAttributePathExpandPosition.IterateFromTheStartOfTheCurrentClusterIfAttributeWildcard();
900 :
901 264 : mAttributeEncoderState.Reset();
902 : }
903 :
904 : // ReportScheduler will take care of verifying the reportability of the handler and schedule the run
905 345 : mObserver->OnBecameReportable(this);
906 345 : }
907 :
908 15249 : Transport::SecureSession * ReadHandler::GetSession() const
909 : {
910 15249 : if (!mSessionHandle)
911 : {
912 0 : return nullptr;
913 : }
914 15249 : return mSessionHandle->AsSecureSession();
915 : }
916 :
917 19 : void ReadHandler::ForceDirtyState()
918 : {
919 19 : SetStateFlag(ReadHandlerFlags::ForceDirty);
920 19 : }
921 :
922 6962 : void ReadHandler::SetStateFlag(ReadHandlerFlags aFlag, bool aValue)
923 : {
924 6962 : bool oldReportable = ShouldStartReporting();
925 6962 : mFlags.Set(aFlag, aValue);
926 :
927 : // If we became reportable, schedule a reporting run.
928 6962 : if (!oldReportable && ShouldStartReporting())
929 : {
930 : // If we became reportable, the scheduler will schedule a run as soon as allowed
931 13 : mObserver->OnBecameReportable(this);
932 : }
933 6962 : }
934 :
935 1382 : void ReadHandler::ClearStateFlag(ReadHandlerFlags aFlag)
936 : {
937 1382 : SetStateFlag(aFlag, false);
938 1382 : }
939 :
940 1980 : size_t ReadHandler::GetReportBufferMaxSize()
941 : {
942 1980 : Transport::SecureSession * session = GetSession();
943 1980 : if (session && session->AllowsLargePayload())
944 : {
945 0 : return kMaxLargeSecureSduLengthBytes;
946 : }
947 1980 : return kMaxSecureSduLengthBytes;
948 : }
949 :
950 : } // namespace app
951 : } // namespace chip
|