forked from project-chip/connectedhomeip
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathReadClient.h
680 lines (608 loc) · 33.1 KB
/
ReadClient.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
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
/*
*
* Copyright (c) 2021 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 client for a CHIP Interaction Data model
*
*/
#pragma once
#include "system/SystemClock.h"
#include <app/AppConfig.h>
#include <app/AttributePathParams.h>
#include <app/ConcreteAttributePath.h>
#include <app/EventHeader.h>
#include <app/EventPathParams.h>
#include <app/MessageDef/ReadRequestMessage.h>
#include <app/MessageDef/StatusIB.h>
#include <app/MessageDef/StatusResponseMessage.h>
#include <app/MessageDef/SubscribeRequestMessage.h>
#include <app/MessageDef/SubscribeResponseMessage.h>
#include <app/OperationalSessionSetup.h>
#include <app/ReadPrepareParams.h>
#include <app/data-model/Decode.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/logging/CHIPLogging.h>
#include <messaging/ExchangeContext.h>
#include <messaging/ExchangeHolder.h>
#include <messaging/ExchangeMgr.h>
#include <messaging/Flags.h>
#include <protocols/Protocols.h>
#include <system/SystemPacketBuffer.h>
#if CHIP_CONFIG_ENABLE_READ_CLIENT
namespace chip {
namespace app {
class InteractionModelEngine;
/**
* @class ReadClient
*
* @brief The read client represents the initiator side of a Read Or Subscribe Interaction (depending on the APIs invoked).
*
* When used to manage subscriptions, the client provides functionality to automatically re-subscribe as needed,
* including re-establishing CASE under certain conditions (see Callback::OnResubscriptionNeeded for more info).
* This is the default behavior. A consumer can completely opt-out of this behavior by over-riding
* Callback::OnResubscriptionNeeded and providing an alternative implementation.
*
*/
class ReadClient : public Messaging::ExchangeDelegate
{
public:
class Callback
{
public:
Callback() = default;
// Callbacks are not expected to be copyable or movable.
Callback(const Callback &) = delete;
Callback(Callback &&) = delete;
Callback & operator=(const Callback &) = delete;
Callback & operator=(Callback &&) = delete;
virtual ~Callback() = default;
/**
* Used to notify a (maybe empty) report data is received from peer and the subscription and the peer is alive.
*
* This object MUST continue to exist after this call is completed. The application shall wait until it
* receives an OnDone call to destroy the object.
*
*/
virtual void NotifySubscriptionStillActive(const ReadClient & apReadClient) {}
/**
* Used to signal the commencement of processing of the first attribute or event report received in a given exchange.
*
* This object MUST continue to exist after this call is completed. The application shall wait until it
* receives an OnDone call to destroy the object.
*
* Once OnReportBegin has been called, either OnReportEnd or OnError will be called before OnDone.
*
*/
virtual void OnReportBegin() {}
/**
* Used to signal the completion of processing of the last attribute or event report in a given exchange.
*
* This object MUST continue to exist after this call is completed. The application shall wait until it
* receives an OnDone call to destroy the object.
*
*/
virtual void OnReportEnd() {}
/**
* Used to deliver event data received through the Read and Subscribe interactions
*
* Only one of the apData and apStatus can be non-null.
*
* This object MUST continue to exist after this call is completed. The application shall wait until it
* receives an OnDone call to destroy the object.
*
* @param[in] aEventHeader The event header in report response.
* @param[in] apData A TLVReader positioned right on the payload of the event.
* @param[in] apStatus Event-specific status, containing an InteractionModel::Status code as well as an optional
* cluster-specific status code.
*/
virtual void OnEventData(const EventHeader & aEventHeader, TLV::TLVReader * apData, const StatusIB * apStatus) {}
/**
* Used to deliver attribute data received through the Read and Subscribe interactions.
*
* This callback will be called when:
* - Receiving attribute data as response of Read interactions
* - Receiving attribute data as reports of subscriptions
* - Receiving attribute data as initial reports of subscriptions
*
* This object MUST continue to exist after this call is completed. The application shall wait until it
* receives an OnDone call to destroy the object.
*
* @param[in] aPath The attribute path field in report response.
* @param[in] apData The attribute data of the given path, will be a nullptr if status is not Success.
* @param[in] aStatus Attribute-specific status, containing an InteractionModel::Status code as well as an
* optional cluster-specific status code.
*/
virtual void OnAttributeData(const ConcreteDataAttributePath & aPath, TLV::TLVReader * apData, const StatusIB & aStatus) {}
/**
* OnSubscriptionEstablished will be called when a subscription is established for the given subscription transaction.
* If using auto resubscription, OnSubscriptionEstablished will be called whenever resubscription is established.
*
* This object MUST continue to exist after this call is completed. The application shall wait until it
* receives an OnDone call to destroy the object.
*
* @param[in] aSubscriptionId The identifier of the subscription that was established.
*/
virtual void OnSubscriptionEstablished(SubscriptionId aSubscriptionId) {}
/**
* OnResubscriptionNeeded will be called when a subscription that was started with SendAutoResubscribeRequest has terminated
* and re-subscription is needed. The termination cause is provided to help inform subsequent re-subscription logic.
*
* The base implementation automatically re-subscribes at appropriate intervals taking the termination cause into account
* (see ReadClient::DefaultResubscribePolicy for more details). If the default implementation doesn't suffice, the logic of
* ReadClient::DefaultResubscribePolicy is broken down into its constituent methods that are publicly available for
* applications to call and sequence.
*
* If the peer is LIT ICD, and the timeout is reached, `aTerminationCause` will be
* `CHIP_ERROR_LIT_SUBSCRIBE_INACTIVE_TIMEOUT`. In this case, returning `CHIP_NO_ERROR` will still trigger a resubscribe
* attempt, while returning `CHIP_ERROR_LIT_SUBSCRIBE_INACTIVE_TIMEOUT` will put the subscription in the
* `InactiveICDSubscription` state. In the latter case, OnResubscriptionNeeded will be called again when
* `OnActiveModeNotification` is called.
*
* If the method is over-ridden, it's the application's responsibility to take the appropriate steps needed to eventually
* call-back into the ReadClient object to schedule a re-subscription (by invoking ReadClient::ScheduleResubscription).
*
* If the application DOES NOT want re-subscription to happen on a particular invocation of this method, returning anything
* other than CHIP_NO_ERROR will terminate the interaction and result in OnError, OnDeallocatePaths and OnDone being called
* in that sequence.
*
* This object MUST continue to exist after this call is completed. The
* application shall wait until it receives an OnDone call to destroy the object.
*
* @param[in] aTerminationCause The cause of failure of the subscription that just terminated.
*/
virtual CHIP_ERROR OnResubscriptionNeeded(ReadClient * apReadClient, CHIP_ERROR aTerminationCause)
{
return apReadClient->DefaultResubscribePolicy(aTerminationCause);
}
/**
* OnError will be called when an error occurs *after* a successful call to SendRequest(). The following
* errors will be delivered through this call in the aError field:
*
* - CHIP_ERROR_TIMEOUT: A response was not received within the expected response timeout.
* - CHIP_ERROR_*TLV*: A malformed, non-compliant response was received from the server.
* - CHIP_ERROR encapsulating a StatusIB: If we got a non-path-specific
* status response from the server. In that case,
* StatusIB::InitFromChipError can be used to extract the status.
* - CHIP_ERROR*: All other cases.
*
* This object MUST continue to exist after this call is completed. The application shall wait until it
* receives an OnDone call to destroy the object.
*
* @param[in] aError A system error code that conveys the overall error code.
*/
virtual void OnError(CHIP_ERROR aError) {}
/**
* OnDone will be called when ReadClient has finished all work and it is
* safe to destroy and free the allocated ReadClient object and any
* other objects associated with the Read or Subscribe interaction.
*
* This function will:
* - Always be called exactly *once* for a given ReadClient instance.
* - Be called even in error circumstances.
* - Only be called after a successful call to SendRequest has been
* made, when the read completes or the subscription is shut down.
*
* @param[in] apReadClient the ReadClient for the completed interaction.
*/
virtual void OnDone(ReadClient * apReadClient) = 0;
/**
* This function is invoked when using SendAutoResubscribeRequest, where the ReadClient was configured to auto re-subscribe
* and the ReadPrepareParams was moved into this client for management. This will have to be free'ed appropriately by the
* application. If SendAutoResubscribeRequest fails, this function will be called before it returns the failure. If
* SendAutoResubscribeRequest succeeds, this function will be called immediately before calling OnDone, or
* when the ReadClient is destroyed, if that happens before OnDone. If SendAutoResubscribeRequest is not called,
* this function will not be called.
*/
virtual void OnDeallocatePaths(ReadPrepareParams && aReadPrepareParams) {}
/**
* This function is invoked when constructing a read/subscribeRequest that does not have data
* version filters specified, to give the callback a chance to provide some.
*
* This function is expected to encode as many complete data version filters as will fit into
* the buffer, rolling back any partially-encoded filters if it runs out of space, and set the
* aEncodedDataVersionList boolean to true if it has successfully encoded at least one data version filter.
*
* Otherwise aEncodedDataVersionList will be set to false.
*/
virtual CHIP_ERROR OnUpdateDataVersionFilterList(DataVersionFilterIBs::Builder & aDataVersionFilterIBsBuilder,
const Span<AttributePathParams> & aAttributePaths,
bool & aEncodedDataVersionList)
{
aEncodedDataVersionList = false;
return CHIP_NO_ERROR;
}
/*
* Get highest received event number.
* If the application does not want to filter events by event number, it should call ClearValue() on aEventNumber
* and return CHIP_NO_ERROR. An error return from this function will fail the entire read client interaction.
*/
virtual CHIP_ERROR GetHighestReceivedEventNumber(Optional<EventNumber> & aEventNumber)
{
aEventNumber.ClearValue();
return CHIP_NO_ERROR;
}
/**
* OnUnsolicitedMessageFromPublisher will be called for a subscription
* ReadClient when any incoming message is received from a matching
* node on the fabric.
*
* This callback will be called:
* - When receiving any unsolicited communication from the node
* - Even for disconnected subscriptions.
*
* Callee MUST not synchronously destroy ReadClients in this callback.
*
* @param[in] apReadClient the ReadClient for the subscription.
*/
virtual void OnUnsolicitedMessageFromPublisher(ReadClient * apReadClient) {}
/**
* OnCASESessionEstablished will be called for a subscription ReadClient when
* it finishes setting up a CASE session, as part of either automatic
* re-subscription or doing an initial subscribe based on ScopedNodeId.
*
* The callee is allowed to modify the ReadPrepareParams (e.g. to change
* things like min/max intervals based on the session parameters).
*/
virtual void OnCASESessionEstablished(const SessionHandle & aSession, ReadPrepareParams & aSubscriptionParams) {}
};
enum class InteractionType : uint8_t
{
Read,
Subscribe,
};
enum class PeerType : uint8_t
{
kNormal,
kLITICD,
};
/**
*
* Constructor.
*
* The callback passed in has to outlive this ReadClient object.
*
* This object can outlive the InteractionModelEngine passed in. However, upon shutdown of the engine,
* this object will cease to function correctly since it depends on the engine for a number of critical functions.
*
* @param[in] apImEngine A valid pointer to the IM engine.
* @param[in] apExchangeMgr A pointer to the ExchangeManager object. Allowed to be null
* if the version of SendAutoResubscribeRequest that takes a
* ScopedNodeId is used.
* @param[in] apCallback Callback set by application.
* @param[in] aInteractionType Type of interaction (read or subscribe)
*
* @retval #CHIP_ERROR_INCORRECT_STATE incorrect state if it is already initialized
* @retval #CHIP_NO_ERROR On success.
*
*/
ReadClient(InteractionModelEngine * apImEngine, Messaging::ExchangeManager * apExchangeMgr, Callback & apCallback,
InteractionType aInteractionType);
/**
* Destructor.
*
* Will abort the exchange context if a valid one still exists. It will also cancel any
* liveness timers that may be active.
*
* OnDone() will not be called.
*/
~ReadClient() override;
/**
* Send a request. There can be one request outstanding on a given ReadClient.
* If SendRequest returns success, no more SendRequest calls can happen on this ReadClient
* until the corresponding OnDone call has happened.
*
* This will send either a Read Request or a Subscribe Request depending on
* the InteractionType this read client was initialized with.
*
* @retval #others fail to send read request
* @retval #CHIP_NO_ERROR On success.
*/
CHIP_ERROR SendRequest(ReadPrepareParams & aReadPrepareParams);
/**
* Re-activate an inactive subscription.
*
* When subscribing to LIT-ICD and liveness timeout reached and OnResubscriptionNeeded returns
* CHIP_ERROR_LIT_SUBSCRIBE_INACTIVE_TIMEOUT, the read client will move to the InactiveICDSubscription state and
* resubscription can be triggered via OnActiveModeNotification().
*
* If the subscription is not in the `InactiveICDSubscription` state, this function will do nothing. So it is always safe to
* call this function when a check-in message is received.
*/
void OnActiveModeNotification();
void OnUnsolicitedReportData(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload);
void OnUnsolicitedMessageFromPublisher()
{
TriggerResubscribeIfScheduled("unsolicited message");
// Then notify callbacks
mpCallback.OnUnsolicitedMessageFromPublisher(this);
}
auto GetSubscriptionId() const
{
using returnType = Optional<decltype(mSubscriptionId)>;
return mInteractionType == InteractionType::Subscribe ? returnType(mSubscriptionId) : returnType::Missing();
}
FabricIndex GetFabricIndex() const { return mPeer.GetFabricIndex(); }
NodeId GetPeerNodeId() const { return mPeer.GetNodeId(); }
bool IsReadType() { return mInteractionType == InteractionType::Read; }
bool IsSubscriptionType() const { return mInteractionType == InteractionType::Subscribe; };
/*
* Retrieve the reporting intervals associated with an active subscription. This should only be called if we're of subscription
* interaction type and after a subscription has been established.
*/
CHIP_ERROR GetReportingIntervals(uint16_t & aMinIntervalFloorSeconds, uint16_t & aMaxIntervalCeilingSeconds) const
{
VerifyOrReturnError(IsSubscriptionType(), CHIP_ERROR_INCORRECT_STATE);
VerifyOrReturnError(IsSubscriptionActive(), CHIP_ERROR_INCORRECT_STATE);
aMinIntervalFloorSeconds = mMinIntervalFloorSeconds;
aMaxIntervalCeilingSeconds = mMaxInterval;
return CHIP_NO_ERROR;
}
ReadClient * GetNextClient() { return mpNext; }
void SetNextClient(ReadClient * apClient) { mpNext = apClient; }
/**
* Like SendSubscribeRequest, but the ReadClient will automatically attempt to re-establish the subscription if
* we decide that the subscription has dropped. The exact behavior of the re-establishment can be controlled
* by setting mResubscribePolicy in the ReadPrepareParams. If not set, a default behavior with exponential backoff will be
* used.
*
* The application has to know to
* a) allocate a ReadPrepareParams object that will have fields mpEventPathParamsList and mpAttributePathParamsList and
* mpDataVersionFilterList with lifetimes as long as the ReadClient itself and b) free those up later in the call to
* OnDeallocatePaths. Note: At a given time in the system, you can either have a single subscription with re-sub enabled that
* has mKeepSubscriptions = false, OR, multiple subs with re-sub enabled with mKeepSubscriptions = true. You shall not
* have a mix of both simultaneously. If SendAutoResubscribeRequest is called at all, it guarantees that it will call
* OnDeallocatePaths (either befor returning error, or when OnDone is called). SendAutoResubscribeRequest is the only case
* that calls OnDeallocatePaths, since that's the only case when the consumer moved a ReadParams into the client.
*
*/
CHIP_ERROR SendAutoResubscribeRequest(ReadPrepareParams && aReadPrepareParams);
/**
* Like SendAutoResubscribeRequest above, but without a session being
* available in the ReadPrepareParams. When this is used, the ReadClient is
* responsible for setting up the CASE session itself.
*
* When using this version of SendAutoResubscribeRequest, any session to
* which ReadPrepareParams has a reference will be ignored.
*/
CHIP_ERROR SendAutoResubscribeRequest(const ScopedNodeId & aPublisherId, ReadPrepareParams && aReadPrepareParams);
/**
* This provides a standard re-subscription policy implementation that given a termination cause, does the following:
* - Calculates the time till next subscription with fibonacci back-off (implemented by ComputeTimeTillNextSubscription()).
* - Schedules the next subscription attempt at the computed interval from the previous step. Operational discovery and
* CASE establishment will be attempted if aTerminationCause was CHIP_ERROR_TIMEOUT. In all other cases, it will attempt
* to re-use a previously established session.
*/
CHIP_ERROR DefaultResubscribePolicy(CHIP_ERROR aTerminationCause);
/**
* Computes the time, in milliseconds, until the next re-subscription over
* an ever increasing window following a fibonacci sequence with the current retry count
* used as input to the fibonacci algorithm.
*
* CHIP_RESUBSCRIBE_MAX_FIBONACCI_STEP_INDEX is the maximum value the retry count can tick up to.
*
*/
uint32_t ComputeTimeTillNextSubscription();
/**
* Schedules a re-subscription aTimeTillNextResubscriptionMs into the future.
*
* If an application wants to set up CASE on their own, they should call ComputeTimeTillNextSubscription() to compute the next
* interval at which they should attempt CASE and attempt CASE at that time. On successful CASE establishment, this method
* should be called with the new SessionHandle provided through 'aNewSessionHandle', 'aTimeTillNextResubscriptionMs' set to 0
* (i.e async, but as soon as possible) and 'aReestablishCASE' set to false.
*
* Otherwise, if aReestablishCASE is true, operational discovery and CASE will be attempted at that time before
* the actual IM interaction is initiated.
*
* aReestablishCASE SHALL NOT be set to true if a valid SessionHandle is provided through newSessionHandle.
*/
CHIP_ERROR ScheduleResubscription(uint32_t aTimeTillNextResubscriptionMs, Optional<SessionHandle> aNewSessionHandle,
bool aReestablishCASE);
// Like SendSubscribeRequest, but allows sending certain forms of invalid
// subscribe requests that servers are expected to reject, for testing
// purposes. Should only be called from tests.
#if CONFIG_BUILD_FOR_HOST_UNIT_TEST
CHIP_ERROR SendSubscribeRequestWithoutValidation(const ReadPrepareParams & aReadPrepareParams)
{
return SendSubscribeRequestImpl(aReadPrepareParams);
}
#endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST
/**
* Override the interval at which liveness of the subscription is assessed.
* By default, this is set set to the max interval of the subscription + ACK timeout of the underlying session.
*
* This can be only be called once a subscription has been established and is active. Once called, this will cancel any existing
* liveness timers and schedule a new one.
*
* This can be called from the Callback::OnSubscriptionEstablished callback.
*
*/
void OverrideLivenessTimeout(System::Clock::Timeout aLivenessTimeout);
/**
* If the ReadClient currently has a resubscription attempt scheduled,
* trigger that attempt right now. This is generally useful when a consumer
* has some sort of indication that the server side is currently up and
* communicating, so right now is a good time to try to resubscribe.
*
* The reason string is used for logging if a resubscribe is triggered.
*/
void TriggerResubscribeIfScheduled(const char * reason);
/**
* Returns the timeout after which we consider the subscription to have
* dropped, if we have received no messages within that amount of time.
*
* Returns NullOptional if a subscription has not yet been established (and
* hence the MaxInterval is not yet known), or if the subscription session
* is gone and hence the relevant MRP parameters can no longer be determined.
*/
Optional<System::Clock::Timeout> GetSubscriptionTimeout();
private:
friend class TestReadInteraction;
friend class InteractionModelEngine;
enum class ClientState : uint8_t
{
Idle, ///< The client has been initialized and is ready for a SendRequest
AwaitingInitialReport, ///< The client is waiting for initial report
AwaitingSubscribeResponse, ///< The client is waiting for subscribe response
SubscriptionActive, ///< The client is maintaining subscription
InactiveICDSubscription, ///< The client is waiting to resubscribe for LIT device
};
enum class ReportType
{
// kUnsolicited reports are the first message in an exchange.
kUnsolicited,
// kContinuingTransaction reports are responses to a message we sent.
kContinuingTransaction
};
bool IsMatchingSubscriptionId(SubscriptionId aSubscriptionId)
{
return aSubscriptionId == mSubscriptionId && mInteractionType == InteractionType::Subscribe;
}
CHIP_ERROR OnMessageReceived(Messaging::ExchangeContext * apExchangeContext, const PayloadHeader & aPayloadHeader,
System::PacketBufferHandle && aPayload) override;
void OnResponseTimeout(Messaging::ExchangeContext * apExchangeContext) override;
/**
* Updates the type (LIT ICD or not) of the peer.
*
* When the subscription is active, this function will just set the flag. When the subscription is an InactiveICDSubscription,
* setting the peer type to SIT or normal devices will also trigger a resubscription attempt.
*
*/
void OnPeerTypeChange(PeerType aType);
/**
* Check if current read client is being used
*
*/
bool IsIdle() const { return mState == ClientState::Idle; }
bool IsInactiveICDSubscription() const { return mState == ClientState::InactiveICDSubscription; }
bool IsSubscriptionActive() const { return mState == ClientState::SubscriptionActive; }
bool IsAwaitingInitialReport() const { return mState == ClientState::AwaitingInitialReport; }
bool IsAwaitingSubscribeResponse() const { return mState == ClientState::AwaitingSubscribeResponse; }
CHIP_ERROR GenerateEventPaths(EventPathIBs::Builder & aEventPathsBuilder, const Span<EventPathParams> & aEventPaths);
CHIP_ERROR GenerateAttributePaths(AttributePathIBs::Builder & aAttributePathIBsBuilder,
const Span<AttributePathParams> & aAttributePaths);
CHIP_ERROR GenerateDataVersionFilterList(DataVersionFilterIBs::Builder & aDataVersionFilterIBsBuilder,
const Span<AttributePathParams> & aAttributePaths,
const Span<DataVersionFilter> & aDataVersionFilters, bool & aEncodedDataVersionList);
CHIP_ERROR BuildDataVersionFilterList(DataVersionFilterIBs::Builder & aDataVersionFilterIBsBuilder,
const Span<AttributePathParams> & aAttributePaths,
const Span<DataVersionFilter> & aDataVersionFilters, bool & aEncodedDataVersionList);
CHIP_ERROR ReadICDOperatingModeFromAttributeDataIB(TLV::TLVReader && aReader, PeerType & aType);
CHIP_ERROR ProcessAttributeReportIBs(TLV::TLVReader & aAttributeDataIBsReader);
CHIP_ERROR ProcessEventReportIBs(TLV::TLVReader & aEventReportIBsReader);
static void OnLivenessTimeoutCallback(System::Layer * apSystemLayer, void * apAppState);
CHIP_ERROR ProcessSubscribeResponse(System::PacketBufferHandle && aPayload);
CHIP_ERROR RefreshLivenessCheckTimer();
CHIP_ERROR ComputeLivenessCheckTimerTimeout(System::Clock::Timeout * aTimeout);
void CancelLivenessCheckTimer();
void CancelResubscribeTimer();
void TriggerResubscriptionForLivenessTimeout(CHIP_ERROR aReason);
void MoveToState(const ClientState aTargetState);
CHIP_ERROR ProcessAttributePath(AttributePathIB::Parser & aAttributePath, ConcreteDataAttributePath & aClusterInfo);
CHIP_ERROR ProcessReportData(System::PacketBufferHandle && aPayload, ReportType aReportType);
const char * GetStateStr() const;
/*
* Checks if we should re-subscribe based on the specified re-subscription policy. If we should, re-subscription is scheduled
* aNextResubscribeIntervalMsec is updated accordingly, and true is returned.
*
* If we should not resubscribe, false is returned.
*
* @param[out] aNextResubscribeIntervalMsec How long we will wait before trying to auto-resubscribe.
*/
bool ResubscribeIfNeeded(uint32_t & aNextResubscribeIntervalMsec);
// Specialized request-sending functions.
CHIP_ERROR SendReadRequest(ReadPrepareParams & aReadPrepareParams);
// SendSubscribeRequest performs som validation on aSubscribePrepareParams
// and then calls SendSubscribeRequestImpl.
CHIP_ERROR SendSubscribeRequest(const ReadPrepareParams & aSubscribePrepareParams);
CHIP_ERROR SendSubscribeRequestImpl(const ReadPrepareParams & aSubscribePrepareParams);
void UpdateDataVersionFilters(const ConcreteDataAttributePath & aPath);
static void OnResubscribeTimerCallback(System::Layer * apSystemLayer, void * apAppState);
// Called to ensure OnReportBegin is called before calling OnEventData or OnAttributeData
void NoteReportingData();
/*
* Called internally to signal the completion of all work on this object, gracefully close the
* exchange and finally, signal to the application that it's
* safe to release this object.
*
* If aError != CHIP_NO_ERROR, this will trigger re-subscriptions if allowResubscription is true
* AND if this ReadClient instance is tracking a subscription AND the applications decides to do so
* in their implementation of Callback::OnResubscriptionNeeded().
*/
void Close(CHIP_ERROR aError, bool allowResubscription = true);
void StopResubscription();
void ClearActiveSubscriptionState();
static void HandleDeviceConnected(void * context, Messaging::ExchangeManager & exchangeMgr,
const SessionHandle & sessionHandle);
static void HandleDeviceConnectionFailure(void * context, const OperationalSessionSetup::ConnnectionFailureInfo & failureInfo);
CHIP_ERROR GetMinEventNumber(const ReadPrepareParams & aReadPrepareParams, Optional<EventNumber> & aEventMin);
/**
* Start setting up a CASE session to our peer, if we can locate a
* CASESessionManager. Returns error if we did not even manage to kick off
* a CASE attempt.
*/
CHIP_ERROR EstablishSessionToPeer();
Messaging::ExchangeManager * mpExchangeMgr = nullptr;
Messaging::ExchangeHolder mExchange;
Callback & mpCallback;
ClientState mState = ClientState::Idle;
bool mIsReporting = false;
bool mIsInitialReport = true;
// boolean to check if client is waiting for the first priming report
bool mWaitingForFirstPrimingReport = true;
bool mPendingMoreChunks = false;
uint16_t mMinIntervalFloorSeconds = 0;
uint16_t mMaxInterval = 0;
SubscriptionId mSubscriptionId = 0;
ScopedNodeId mPeer;
InteractionType mInteractionType = InteractionType::Read;
Timestamp mEventTimestamp;
bool mForceCaseOnNextResub = true;
bool mIsResubscriptionScheduled = false;
// mMinimalResubscribeDelay is used to store the delay returned with a BUSY
// response to a Sigma1 message.
System::Clock::Milliseconds16 mMinimalResubscribeDelay = System::Clock::kZero;
chip::Callback::Callback<OnDeviceConnected> mOnConnectedCallback;
chip::Callback::Callback<OperationalSessionSetup::OnSetupFailure> mOnConnectionFailureCallback;
ReadClient * mpNext = nullptr;
InteractionModelEngine * mpImEngine = nullptr;
//
// This stores the params associated with the interaction in a specific set of cases:
// 1. Stores all parameters when used with subscriptions initiated using SendAutoResubscribeRequest.
// 2. Stores just the SessionHolder when used with any subscriptions.
//
ReadPrepareParams mReadPrepareParams;
uint32_t mNumRetries = 0;
System::Clock::Timeout mLivenessTimeoutOverride = System::Clock::kZero;
bool mIsPeerLIT = false;
// End Of Container (0x18) uses one byte.
static constexpr uint16_t kReservedSizeForEndOfContainer = 1;
// Reserved size for the uint8_t InteractionModelRevision flag, which takes up 1 byte for the control tag and 1 byte for the
// context tag, 1 byte for value
static constexpr uint16_t kReservedSizeForIMRevision = 1 + 1 + 1;
// Reserved buffer for TLV level overhead (the overhead for data version filter IBs EndOfContainer, IM reversion end
// of RequestMessage (another end of container)).
static constexpr uint16_t kReservedSizeForTLVEncodingOverhead =
kReservedSizeForEndOfContainer + kReservedSizeForIMRevision + kReservedSizeForEndOfContainer;
};
}; // namespace app
}; // namespace chip
#endif // CHIP_CONFIG_ENABLE_READ_CLIENT