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