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 :
19 : /**
20 : * @file
21 : * This file defines read handler for a CHIP Interaction Data model
22 : *
23 : */
24 :
25 : #pragma once
26 :
27 : #include <access/AccessControl.h>
28 : #include <app/AttributePathExpandIterator.h>
29 : #include <app/AttributePathParams.h>
30 : #include <app/AttributeValueEncoder.h>
31 : #include <app/CASESessionManager.h>
32 : #include <app/DataVersionFilter.h>
33 : #include <app/EventManagement.h>
34 : #include <app/EventPathParams.h>
35 : #include <app/MessageDef/AttributePathIBs.h>
36 : #include <app/MessageDef/DataVersionFilterIBs.h>
37 : #include <app/MessageDef/EventFilterIBs.h>
38 : #include <app/MessageDef/EventPathIBs.h>
39 : #include <app/OperationalSessionSetup.h>
40 : #include <app/SubscriptionResumptionSessionEstablisher.h>
41 : #include <app/SubscriptionResumptionStorage.h>
42 : #include <app/reporting/Generations.h>
43 : #include <lib/core/CHIPCallback.h>
44 : #include <lib/core/CHIPCore.h>
45 : #include <lib/core/TLVDebug.h>
46 : #include <lib/support/CodeUtils.h>
47 : #include <lib/support/DLLUtil.h>
48 : #include <lib/support/LinkedList.h>
49 : #include <lib/support/logging/CHIPLogging.h>
50 : #include <messaging/ExchangeHolder.h>
51 : #include <messaging/ExchangeMgr.h>
52 : #include <messaging/Flags.h>
53 : #include <protocols/Protocols.h>
54 : #include <system/SystemPacketBuffer.h>
55 :
56 : // https://github.com/CHIP-Specifications/connectedhomeip-spec/blob/61a9d19e6af12fdfb0872bcff26d19de6c680a1a/src/Ch02_Architecture.adoc#1122-subscribe-interaction-limits
57 : inline constexpr uint16_t kSubscriptionMaxIntervalPublisherLimit = 3600; // seconds (60 minutes)
58 :
59 : namespace chip {
60 : namespace app {
61 :
62 : //
63 : // Forward declare the Engine (which is in a different namespace) to be able to use
64 : // it as a friend class below.
65 : //
66 : namespace reporting {
67 : class Engine;
68 : class TestReportingEngine;
69 : class ReportScheduler;
70 : class TestReportScheduler;
71 : } // namespace reporting
72 :
73 : class InteractionModelEngine;
74 : class TestInteractionModelEngine;
75 :
76 : /**
77 : * @class ReadHandler
78 : *
79 : * @brief The read handler is responsible for processing a read request, asking the attribute/event store
80 : * for the relevant data, and sending a reply.
81 : *
82 : */
83 : class ReadHandler : public Messaging::ExchangeDelegate
84 : {
85 : public:
86 : using SubjectDescriptor = Access::SubjectDescriptor;
87 :
88 : enum class InteractionType : uint8_t
89 : {
90 : Read,
91 : Subscribe,
92 : };
93 :
94 : /*
95 : * A callback used to interact with the application.
96 : */
97 : class ApplicationCallback
98 : {
99 : public:
100 46 : virtual ~ApplicationCallback() = default;
101 :
102 : /*
103 : * Called right after a SubscribeRequest has been parsed and processed. This notifies an interested application
104 : * of a subscription that is about to be established. It also provides an avenue for altering the parameters of the
105 : * subscription (specifically, the min/max negotiated intervals) or even outright rejecting the subscription for
106 : * application-specific reasons.
107 : *
108 : * TODO: Need a new IM status code to convey application-rejected subscribes. Currently, a Failure IM status code is sent
109 : * back to the subscriber, which isn't sufficient.
110 : *
111 : * To reject the subscription, a CHIP_ERROR code that is not equivalent to CHIP_NO_ERROR should be returned.
112 : *
113 : * More information about the set of paths associated with this subscription can be retrieved by calling the appropriate
114 : * Get* methods below.
115 : *
116 : * aReadHandler: Reference to the ReadHandler associated with the subscription.
117 : * aSecureSession: A reference to the underlying secure session associated with the subscription.
118 : *
119 : */
120 0 : virtual CHIP_ERROR OnSubscriptionRequested(ReadHandler & aReadHandler, Transport::SecureSession & aSecureSession)
121 : {
122 0 : return CHIP_NO_ERROR;
123 : }
124 :
125 : /*
126 : * Called after a subscription has been fully established.
127 : */
128 0 : virtual void OnSubscriptionEstablished(ReadHandler & aReadHandler){};
129 :
130 : /*
131 : * Called right before a subscription is about to get terminated. This is only called on subscriptions that were terminated
132 : * after they had been fully established (and therefore had called OnSubscriptionEstablished).
133 : * OnSubscriptionEstablishment().
134 : */
135 0 : virtual void OnSubscriptionTerminated(ReadHandler & aReadHandler){};
136 : };
137 :
138 : /*
139 : * A callback used to manage the lifetime of the ReadHandler object.
140 : */
141 : class ManagementCallback
142 : {
143 : public:
144 113 : virtual ~ManagementCallback() = default;
145 :
146 : /*
147 : * Method that signals to a registered callback that this object
148 : * has completed doing useful work and is now safe for release/destruction.
149 : */
150 : virtual void OnDone(ReadHandler & apReadHandlerObj) = 0;
151 :
152 : /*
153 : * Retrieve the ApplicationCallback (if a valid one exists) from our management entity. This avoids
154 : * storing multiple references to the application provided callback and having to subsequently manage lifetime
155 : * issues w.r.t the ReadHandler itself.
156 : */
157 : virtual ApplicationCallback * GetAppCallback() = 0;
158 :
159 : /*
160 : * Retrieve the InteractionalModelEngine that holds this ReadHandler.
161 : */
162 : virtual InteractionModelEngine * GetInteractionModelEngine() = 0;
163 : };
164 :
165 : // TODO (#27675) : Merge existing callback and observer into one class and have an observer pool in the Readhandler to notify
166 : // every
167 : /*
168 : * Observer class for ReadHandler, meant to allow multiple objects to observe the ReadHandler. Currently only one observer is
169 : * supported but all above callbacks should be merged into observer type and an observer pool should be added to allow multiple
170 : * objects to observe ReadHandler
171 : */
172 : class Observer
173 : {
174 : public:
175 70 : virtual ~Observer() = default;
176 :
177 : /// @brief Callback invoked to notify a subscription was successfully established for the ReadHandler
178 : /// @param[in] apReadHandler ReadHandler that completed its subscription
179 : virtual void OnSubscriptionEstablished(ReadHandler * apReadHandler) = 0;
180 :
181 : /// @brief Callback invoked when a ReadHandler went from a non reportable state to a reportable state. Indicates to the
182 : /// observer that a report should be emitted when the min interval allows it.
183 : ///
184 : /// This will only be invoked for subscribe-type ReadHandler objects, and only after
185 : /// OnSubscriptionEstablished has been called.
186 : ///
187 : /// @param[in] apReadHandler ReadHandler that became dirty and in HandlerState::CanStartReporting state
188 : virtual void OnBecameReportable(ReadHandler * apReadHandler) = 0;
189 :
190 : /// @brief Callback invoked when the read handler needs to make sure to send a message to the subscriber within the next
191 : /// maxInterval time period.
192 : /// @param[in] apReadHandler ReadHandler that has generated a report
193 : virtual void OnSubscriptionReportSent(ReadHandler * apReadHandler) = 0;
194 :
195 : /// @brief Callback invoked when a ReadHandler is getting removed so it can be unregistered
196 : /// @param[in] apReadHandler ReadHandler getting destroyed
197 : virtual void OnReadHandlerDestroyed(ReadHandler * apReadHandler) = 0;
198 : };
199 :
200 : /*
201 : * Destructor - as part of destruction, it will abort the exchange context
202 : * if a valid one still exists.
203 : *
204 : * See Abort() for details on when that might occur.
205 : */
206 : ~ReadHandler() override;
207 :
208 : /**
209 : *
210 : * Constructor.
211 : *
212 : * The callback passed in has to outlive this handler object.
213 : *
214 : */
215 : ReadHandler(ManagementCallback & apCallback, Messaging::ExchangeContext * apExchangeContext, InteractionType aInteractionType,
216 : Observer * observer);
217 :
218 : #if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
219 : /**
220 : *
221 : * Constructor in preparation for resuming a persisted subscription
222 : *
223 : * The callback passed in has to outlive this handler object.
224 : *
225 : */
226 : ReadHandler(ManagementCallback & apCallback, Observer * observer);
227 : #endif
228 :
229 477 : const SingleLinkedListNode<AttributePathParams> * GetAttributePathList() const { return mpAttributePathList; }
230 2884 : const SingleLinkedListNode<EventPathParams> * GetEventPathList() const { return mpEventPathList; }
231 4722 : const SingleLinkedListNode<DataVersionFilter> * GetDataVersionFilterList() const { return mpDataVersionFilterList; }
232 :
233 : /**
234 : * @brief Returns the reporting intervals that will used by the ReadHandler for the subscription being requested.
235 : * After the subscription is established, these will be the set reporting intervals and cannot be changed.
236 : *
237 : * @param[out] aMinInterval minimum time delta between two reports for the subscription
238 : * @param[in] aMaxInterval maximum time delta between two reports for the subscription
239 : */
240 449 : void GetReportingIntervals(uint16_t & aMinInterval, uint16_t & aMaxInterval) const
241 : {
242 449 : aMinInterval = mMinIntervalFloorSeconds;
243 449 : aMaxInterval = mMaxInterval;
244 449 : }
245 :
246 : /**
247 : * @brief Returns the maximum reporting interval that was initially requested by the subscriber
248 : * This is the same value as the mMaxInterval member if the max interval is not changed by the publisher.
249 : *
250 : * @note If the device is an ICD, the MaxInterval of a subscription is automatically set to a multiple of the IdleModeDuration.
251 : * This function is the only way to get the requested max interval once the OnSubscriptionRequested application callback
252 : * is called.
253 : *
254 : * @return uint16_t subscriber requested maximum reporting interval
255 : */
256 10 : inline uint16_t GetSubscriberRequestedMaxInterval() const { return mSubscriberRequestedMaxInterval; }
257 :
258 10 : CHIP_ERROR SetMinReportingIntervalForTests(uint16_t aMinInterval)
259 : {
260 10 : VerifyOrReturnError(IsIdle(), CHIP_ERROR_INCORRECT_STATE);
261 10 : VerifyOrReturnError(aMinInterval <= mMaxInterval, CHIP_ERROR_INVALID_ARGUMENT);
262 : // Ensures the new min interval is higher than the subscriber established one.
263 10 : mMinIntervalFloorSeconds = std::max(mMinIntervalFloorSeconds, aMinInterval);
264 10 : return CHIP_NO_ERROR;
265 : }
266 :
267 : /*
268 : * Set the maximum reporting interval for the subscription. This SHALL only be called
269 : * from the OnSubscriptionRequested callback above. The restriction is as below
270 : * MinIntervalFloor ≤ MaxInterval ≤ MAX(SUBSCRIPTION_MAX_INTERVAL_PUBLISHER_LIMIT, MaxIntervalCeiling)
271 : * Where SUBSCRIPTION_MAX_INTERVAL_PUBLISHER_LIMIT is set to 60m in the spec.
272 : * For ICD publishers, this is set to the IdleModeDuration defined in the ICD Management Cluster.
273 : * If the new max interval is less than the idle mode duration for an ICD device, the function will return
274 : * CHIP_ERROR_INVALID_ARGUMENT.
275 : */
276 31 : CHIP_ERROR SetMaxReportingInterval(uint16_t aMaxInterval)
277 : {
278 : #if CHIP_CONFIG_ENABLE_ICD_SERVER
279 : if (aMaxInterval < mMaxInterval)
280 : {
281 : ChipLogProgress(DataManagement,
282 : "Fail to set MaxReportingInterval to %d as it is less than the current MaxInterval %d for ICD device",
283 : aMaxInterval, mMaxInterval);
284 : return CHIP_ERROR_INVALID_ARGUMENT;
285 : }
286 : #endif // CHIP_CONFIG_ENABLE_ICD_SERVER
287 31 : VerifyOrReturnError(IsIdle(), CHIP_ERROR_INCORRECT_STATE);
288 29 : VerifyOrReturnError(mMinIntervalFloorSeconds <= aMaxInterval, CHIP_ERROR_INVALID_ARGUMENT);
289 27 : VerifyOrReturnError(aMaxInterval <= std::max(GetPublisherSelectedIntervalLimit(), mSubscriberRequestedMaxInterval),
290 : CHIP_ERROR_INVALID_ARGUMENT);
291 21 : mMaxInterval = aMaxInterval;
292 21 : return CHIP_NO_ERROR;
293 : }
294 :
295 : #if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
296 : /**
297 : *
298 : * @brief Initialize a ReadHandler for a resumed subsciption
299 : *
300 : * Used after the SubscriptionResumptionSessionEstablisher establishs the CASE session
301 : */
302 : void OnSubscriptionResumed(const SessionHandle & sessionHandle, SubscriptionResumptionSessionEstablisher & sessionEstablisher);
303 : #endif
304 :
305 : private:
306 : PriorityLevel GetCurrentPriority() const { return mCurrentPriority; }
307 1980 : EventNumber & GetEventMin() { return mEventMin; }
308 :
309 : /**
310 : * Returns SUBSCRIPTION_MAX_INTERVAL_PUBLISHER_LIMIT
311 : * For an ICD publisher, this SHALL be set to the idle mode duration.
312 : * Otherwise, this SHALL be set to 60 minutes.
313 : */
314 : uint16_t GetPublisherSelectedIntervalLimit();
315 :
316 : enum class ReadHandlerFlags : uint8_t
317 : {
318 : // The flag indicating we are in the middle of a series of chunked report messages, this flag will be cleared during
319 : // sending last chunked message.
320 : ChunkedReport = (1 << 0),
321 :
322 : // Tracks whether we're in the initial phase of receiving priming
323 : // reports, which is always true for reads and true for subscriptions
324 : // prior to receiving a subscribe response.
325 : PrimingReports = (1 << 1),
326 : ActiveSubscription = (1 << 2),
327 : FabricFiltered = (1 << 3),
328 : // For subscriptions, we record the dirty set generation when we started to generate the last report.
329 : // The mCurrentReportsBeginGeneration records the generation at the start of the current report. This only/
330 : // has a meaningful value while IsReporting() is true.
331 : //
332 : // mPreviousReportsBeginGeneration will be set to mCurrentReportsBeginGeneration after we send the last
333 : // chunk of the current report. Anything that was dirty with a generation earlier than
334 : // mPreviousReportsBeginGeneration has had its value sent to the client.
335 : // when receiving initial request, it needs mark current handler as dirty.
336 : // when there is urgent event, it needs mark current handler as dirty.
337 : ForceDirty = (1 << 4),
338 :
339 : // Don't need the response for report data if true
340 : SuppressResponse = (1 << 5),
341 : };
342 :
343 : /**
344 : * Process a read/subscribe request. Parts of the processing may end up being asynchronous, but the ReadHandler
345 : * guarantees that it will call Shutdown on itself when processing is done (including if OnReadInitialRequest
346 : * returns an error).
347 : *
348 : * @retval #Others If fails to process read request
349 : * @retval #CHIP_NO_ERROR On success.
350 : *
351 : */
352 : void OnInitialRequest(System::PacketBufferHandle && aPayload);
353 :
354 : /**
355 : * Send ReportData to initiator
356 : *
357 : * @param[in] aPayload A payload that has read request data
358 : * @param[in] aMoreChunks A flags indicating there will be more chunks expected to be sent for this read request
359 : *
360 : * @retval #Others If fails to send report data
361 : * @retval #CHIP_NO_ERROR On success.
362 : *
363 : * If an error is returned, the ReadHandler guarantees that it is not in
364 : * a state where it's waiting for a response.
365 : */
366 : CHIP_ERROR SendReportData(System::PacketBufferHandle && aPayload, bool aMoreChunks);
367 :
368 : /*
369 : * Get the appropriate size of a packet buffer to allocate for encoding a Report message.
370 : * This size might depend on the underlying session used by the ReadHandler.
371 : *
372 : * The size returned here is the size not including the various prepended headers
373 : * (what System::PacketBuffer calls the "available size").
374 : */
375 : size_t GetReportBufferMaxSize();
376 :
377 : /**
378 : * Returns whether this ReadHandler represents a subscription that was created by the other side of the provided exchange.
379 : */
380 : bool IsFromSubscriber(Messaging::ExchangeContext & apExchangeContext) const;
381 :
382 41 : bool IsIdle() const { return mState == HandlerState::Idle; }
383 :
384 : /// @brief Returns whether the ReadHandler is in a state where it can send a report and there is data to report.
385 10806 : bool ShouldStartReporting() const
386 : {
387 : // Important: Anything that changes ShouldStartReporting() from false to true
388 : // (which can only happen for subscriptions) must call
389 : // mObserver->OnBecameReportable(this).
390 10806 : return CanStartReporting() && (ShouldReportUnscheduled() || IsDirty());
391 : }
392 : /// @brief CanStartReporting() is true if the ReadHandler is in a state where it could generate
393 : /// a (possibly empty) report if someone asked it to.
394 21307 : bool CanStartReporting() const { return mState == HandlerState::CanStartReporting; }
395 : /// @brief ShouldReportUnscheduled() is true if the ReadHandler should be asked to generate reports
396 : /// without consulting the report scheduler.
397 8828 : bool ShouldReportUnscheduled() const
398 : {
399 8828 : return CanStartReporting() && (IsType(ReadHandler::InteractionType::Read) || IsPriming());
400 : }
401 7791 : bool IsAwaitingReportResponse() const { return mState == HandlerState::AwaitingReportResponse; }
402 :
403 : // Resets the path iterator to the beginning of the whole report for generating a series of new reports.
404 : void ResetPathIterator();
405 :
406 : CHIP_ERROR ProcessDataVersionFilterList(DataVersionFilterIBs::Parser & aDataVersionFilterListParser);
407 :
408 : // if current priority is in the middle, it has valid snapshoted last event number, it check cleaness via comparing
409 : // with snapshotted last event number. if current priority is in the end, no valid
410 : // sanpshotted last event, check with latest last event number, re-setup snapshoted checkpoint, and compare again.
411 : bool CheckEventClean(EventManagement & aEventManager);
412 :
413 27924 : bool IsType(InteractionType type) const { return (mInteractionType == type); }
414 1513 : bool IsChunkedReport() const { return mFlags.Has(ReadHandlerFlags::ChunkedReport); }
415 : // Is reporting indicates whether we are in the middle of a series chunks. As we will set mIsChunkedReport on the first chunk
416 : // and clear that flag on the last chunk, we can use mIsChunkedReport to indicate this state.
417 3927 : bool IsReporting() const { return mFlags.Has(ReadHandlerFlags::ChunkedReport); }
418 10852 : bool IsPriming() const { return mFlags.Has(ReadHandlerFlags::PrimingReports); }
419 42 : bool IsActiveSubscription() const { return mFlags.Has(ReadHandlerFlags::ActiveSubscription); }
420 4925 : bool IsFabricFiltered() const { return mFlags.Has(ReadHandlerFlags::FabricFiltered); }
421 : CHIP_ERROR OnSubscribeRequest(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload);
422 441 : void GetSubscriptionId(SubscriptionId & aSubscriptionId) const { aSubscriptionId = mSubscriptionId; }
423 1980 : AttributePathExpandIterator::Position & AttributeIterationPosition() { return mAttributePathExpandPosition; }
424 :
425 : /// @brief Notifies the read handler that a set of attribute paths has been marked dirty. This will schedule a reporting engine
426 : /// run if the change to the attribute path makes the ReadHandler reportable.
427 : /// @param aAttributeChanged Path to the attribute that was changed.
428 : void AttributePathIsDirty(DataModel::Provider * apDataModel, const AttributePathParams & aAttributeChanged);
429 4497 : bool IsDirty() const
430 : {
431 4497 : return mDirtyGeneration.After(mPreviousReportsBeginGeneration) || mFlags.Has(ReadHandlerFlags::ForceDirty);
432 : }
433 1088 : void ClearForceDirtyFlag() { ClearStateFlag(ReadHandlerFlags::ForceDirty); }
434 144 : NodeId GetInitiatorNodeId() const
435 : {
436 144 : auto session = GetSession();
437 144 : return session == nullptr ? kUndefinedNodeId : session->GetPeerNodeId();
438 : }
439 :
440 300 : FabricIndex GetAccessingFabricIndex() const
441 : {
442 300 : auto session = GetSession();
443 300 : return session == nullptr ? kUndefinedFabricIndex : session->GetFabricIndex();
444 : }
445 :
446 : Transport::SecureSession * GetSession() const;
447 5916 : SubjectDescriptor GetSubjectDescriptor() const { return GetSession()->GetSubjectDescriptor(); }
448 4925 : bool AllowsLargePayload() const { return GetSession()->AllowsLargePayload(); }
449 :
450 82 : auto GetTransactionStartGeneration() const { return mTransactionStartGeneration; }
451 :
452 : /// @brief Forces the read handler into a dirty state, regardless of what's going on with attributes.
453 : /// This can lead to scheduling of a reporting run immediately, if the min interval has been reached,
454 : /// or after the min interval is reached if it has not yet been reached.
455 : void ForceDirtyState();
456 :
457 4925 : const AttributeEncodeState & GetAttributeEncodeState() const { return mAttributeEncoderState; }
458 4927 : void SetAttributeEncodeState(const AttributeEncodeState & aState) { mAttributeEncoderState = aState; }
459 20 : uint32_t GetLastWrittenEventsBytes() const { return mLastWrittenEventsBytes; }
460 :
461 : // Returns the number of interested paths, including wildcard and concrete paths.
462 6593 : size_t GetAttributePathCount() const { return mpAttributePathList == nullptr ? 0 : mpAttributePathList->Count(); };
463 6593 : size_t GetEventPathCount() const { return mpEventPathList == nullptr ? 0 : mpEventPathList->Count(); };
464 : size_t GetDataVersionFilterCount() const { return mpDataVersionFilterList == nullptr ? 0 : mpDataVersionFilterList->Count(); };
465 :
466 : CHIP_ERROR SendStatusReport(Protocols::InteractionModel::Status aStatus);
467 :
468 : friend class TestReadInteraction;
469 : friend class chip::app::reporting::TestReportingEngine;
470 : friend class chip::app::reporting::TestReportScheduler;
471 :
472 : //
473 : // The engine needs to be able to Abort/Close a ReadHandler instance upon completion of work for a given read/subscribe
474 : // interaction. We do not want to make these methods public just to give an adjacent class in the IM access, since public
475 : // should really be taking application usage considerations as well. Hence, make it a friend.
476 : //
477 : friend class chip::app::reporting::Engine;
478 : friend class chip::app::InteractionModelEngine;
479 : friend class TestInteractionModelEngine;
480 :
481 : // The report scheduler needs to be able to access StateFlag private functions ShouldStartReporting(), CanStartReporting(),
482 : // ForceDirtyState() and IsDirty() to know when to schedule a run so it is declared as a friend class.
483 : friend class chip::app::reporting::ReportScheduler;
484 :
485 : enum class HandlerState : uint8_t
486 : {
487 : Idle, ///< The handler has been initialized and is ready
488 : CanStartReporting, ///< The handler has is now capable of generating reports and may generate one immediately
489 : ///< or later when other criteria are satisfied (e.g hold-off for min reporting interval).
490 : AwaitingReportResponse, ///< The handler has sent the report to the client and is awaiting a status response.
491 : AwaitingDestruction, ///< The object has completed its work and is awaiting destruction by the application.
492 : };
493 :
494 : enum class CloseOptions
495 : {
496 : kDropPersistedSubscription,
497 : kKeepPersistedSubscription
498 : };
499 : /**
500 : * Called internally to signal the completion of all work on this objecta and signal to a registered callback that it's
501 : * safe to release this object.
502 : *
503 : * @param options This specifies whether to drop or keep the subscription
504 : *
505 : */
506 : void Close(CloseOptions options = CloseOptions::kDropPersistedSubscription);
507 :
508 : CHIP_ERROR SendSubscribeResponse();
509 : CHIP_ERROR ProcessSubscribeRequest(System::PacketBufferHandle && aPayload);
510 : CHIP_ERROR ProcessReadRequest(System::PacketBufferHandle && aPayload);
511 : CHIP_ERROR ProcessAttributePaths(AttributePathIBs::Parser & aAttributePathListParser);
512 : CHIP_ERROR ProcessEventPaths(EventPathIBs::Parser & aEventPathsParser);
513 : CHIP_ERROR ProcessEventFilters(EventFilterIBs::Parser & aEventFiltersParser);
514 : CHIP_ERROR OnStatusResponse(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload,
515 : bool & aSendStatusResponse);
516 : CHIP_ERROR OnMessageReceived(Messaging::ExchangeContext * apExchangeContext, const PayloadHeader & aPayloadHeader,
517 : System::PacketBufferHandle && aPayload) override;
518 : void OnResponseTimeout(Messaging::ExchangeContext * apExchangeContext) override;
519 : void MoveToState(const HandlerState aTargetState);
520 :
521 : const char * GetStateStr() const;
522 :
523 : void PersistSubscription();
524 :
525 : /// @brief Modifies a state flag in the read handler. If the read handler went from a
526 : /// non-reportable state to a reportable state, schedules a reporting engine run.
527 : /// @param aFlag Flag to set
528 : /// @param aValue Flag new value
529 : void SetStateFlag(ReadHandlerFlags aFlag, bool aValue = true);
530 :
531 : /// @brief This function call SetStateFlag with the flag value set to false, thus possibly emitting a report
532 : /// generation.
533 : /// @param aFlag Flag to clear
534 : void ClearStateFlag(ReadHandlerFlags aFlag);
535 :
536 : SubscriptionId mSubscriptionId = 0;
537 :
538 : // The current generation of the reporting engine dirty set the last time we were notified that a path we're interested in was
539 : // marked dirty.
540 : //
541 : // This allows us to detemine whether any paths we care about might have
542 : // been marked dirty after we had already sent reports for them, which would
543 : // mean we should report those paths again, by comparing this generation to the
544 : // current generation when we started sending the last set reports that we completed.
545 : //
546 : // This allows us to reset the iterator to the beginning of the current
547 : // cluster instead of the beginning of the whole report in AttributePathIsDirty, without
548 : // permanently missing dirty any paths.
549 : reporting::AttributeGeneration mDirtyGeneration{ 0 };
550 :
551 : // For subscriptions, we record the timestamp when we started to generate the last report.
552 : // The mCurrentReportsBeginGeneration records the timestamp for the current report, which won;t be used for checking if this
553 : // ReadHandler is dirty.
554 : // mPreviousReportsBeginGeneration will be set to mCurrentReportsBeginGeneration after we sent the last chunk of the current
555 : // report.
556 : reporting::AttributeGeneration mPreviousReportsBeginGeneration{ 0 };
557 : reporting::AttributeGeneration mCurrentReportsBeginGeneration{ 0 };
558 : /*
559 : * (mDirtyGeneration = b > a, this is a dirty read handler)
560 : * +- Start Report -> mCurrentReportsBeginGeneration = c
561 : * | +- AttributePathIsDirty (Attribute Y) -> mDirtyGeneration = d
562 : * | | +- Last Chunk -> mPreviousReportsBeginGeneration = mCurrentReportsBeginGeneration = c
563 : * | | | +- (mDirtyGeneration = d) > (mPreviousReportsBeginGeneration = c), this is a dirty read handler
564 : * | | | | Attribute X has a dirty generation less than c, Attribute Y has a dirty generation larger than c
565 : * | | | | So Y will be included in the report but X will not be inclued in this report.
566 : * -a--b--c------d-----e---f---> Generation
567 : * | |
568 : * | +- AttributePathIsDirty (Attribute X) (mDirtyGeneration = b)
569 : * +- mPreviousReportsBeginGeneration
570 : * For read handler, if mDirtyGeneration > mPreviousReportsBeginGeneration, then we regard it as a dirty read handler, and it
571 : * should generate report on timeout reached.
572 : */
573 :
574 : // When we don't have enough resources for a new subscription, the oldest subscription might be evicted by interaction model
575 : // engine, the "oldest" subscription is the subscription with the smallest generation.
576 : reporting::AttributeGeneration mTransactionStartGeneration{ 0 };
577 :
578 : EventNumber mEventMin = 0;
579 :
580 : // The last schedule event number snapshoted in the beginning when preparing to fill new events to reports
581 : EventNumber mLastScheduledEventNumber = 0;
582 :
583 : /// Iterator position state for any ongoing path expansion for handling wildcard reads/subscriptions.
584 : AttributePathExpandIterator::Position mAttributePathExpandPosition;
585 :
586 : Messaging::ExchangeHolder mExchangeCtx;
587 : #if CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
588 : // TODO: this should be replaced by a pointer to the InteractionModelEngine that created the ReadHandler
589 : // once InteractionModelEngine is no longer a singleton (see issue 23625)
590 : Messaging::ExchangeManager * mExchangeMgr = nullptr;
591 : #endif // CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
592 :
593 : SingleLinkedListNode<AttributePathParams> * mpAttributePathList = nullptr;
594 : SingleLinkedListNode<EventPathParams> * mpEventPathList = nullptr;
595 : SingleLinkedListNode<DataVersionFilter> * mpDataVersionFilterList = nullptr;
596 :
597 : ManagementCallback & mManagementCallback;
598 :
599 : // TODO (#27675): Merge all observers into one and that one will dispatch the callbacks to the right place.
600 : Observer * mObserver = nullptr;
601 :
602 : uint32_t mLastWrittenEventsBytes = 0;
603 :
604 : // The detailed encoding state for a single attribute, used by list chunking feature.
605 : // The size of AttributeEncoderState is 2 bytes for now.
606 : AttributeEncodeState mAttributeEncoderState;
607 :
608 : uint16_t mMinIntervalFloorSeconds = 0;
609 : uint16_t mMaxInterval = 0;
610 : uint16_t mSubscriberRequestedMaxInterval = 0;
611 :
612 : // Current Handler state
613 : HandlerState mState = HandlerState::Idle;
614 : PriorityLevel mCurrentPriority = PriorityLevel::Invalid;
615 : BitFlags<ReadHandlerFlags> mFlags;
616 : InteractionType mInteractionType = InteractionType::Read;
617 :
618 : SessionHolder mSessionHandle;
619 : };
620 :
621 : } // namespace app
622 : } // namespace chip
|