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