blob: 9b7d84fb965e279481503964eb6cdbac1c8e0ce3 [file] [log] [blame]
yunhanw-google08566242021-03-18 15:29:39 -07001/*
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
Marc Lepage24008842021-12-10 00:29:02 -050027#include <access/AccessControl.h>
Song GUObfdbd452021-12-06 15:53:34 +080028#include <app/AttributeAccessInterface.h>
Song GUO4efa5de2021-11-17 23:39:11 +080029#include <app/AttributePathExpandIterator.h>
yunhanw-googlef5821552021-04-28 05:43:51 -070030#include <app/ClusterInfo.h>
yunhanw-google8ddfb872021-05-07 18:13:15 -070031#include <app/EventManagement.h>
Jerry Johns12db26d2022-01-26 10:06:04 -080032#include <app/MessageDef/AttributePathIBs.h>
33#include <app/MessageDef/EventPathIBs.h>
Zang MingJie53dd5832021-09-03 03:05:16 +080034#include <lib/core/CHIPCore.h>
35#include <lib/core/CHIPTLVDebug.hpp>
36#include <lib/support/CodeUtils.h>
37#include <lib/support/DLLUtil.h>
38#include <lib/support/logging/CHIPLogging.h>
yunhanw-google08566242021-03-18 15:29:39 -070039#include <messaging/ExchangeContext.h>
40#include <messaging/ExchangeMgr.h>
41#include <messaging/Flags.h>
42#include <protocols/Protocols.h>
yunhanw-google08566242021-03-18 15:29:39 -070043#include <system/SystemPacketBuffer.h>
44
45namespace chip {
46namespace app {
Jerry Johns12db26d2022-01-26 10:06:04 -080047
48//
49// Forward declare the Engine (which is in a different namespace) to be able to use
50// it as a friend class below.
51//
52namespace reporting {
53class Engine;
54}
55
yunhanw-google08566242021-03-18 15:29:39 -070056/**
57 * @class ReadHandler
58 *
59 * @brief The read handler is responsible for processing a read request, asking the attribute/event store
60 * for the relevant data, and sending a reply.
61 *
62 */
yunhanw-google9c056ef2021-08-25 16:11:21 -070063class ReadHandler : public Messaging::ExchangeDelegate
yunhanw-google08566242021-03-18 15:29:39 -070064{
65public:
Marc Lepage24008842021-12-10 00:29:02 -050066 using SubjectDescriptor = Access::SubjectDescriptor;
67
yunhanw-googleec5f5dc2021-09-13 16:47:42 -070068 enum class InteractionType : uint8_t
69 {
70 Read,
71 Subscribe,
72 };
73
Jerry Johns12db26d2022-01-26 10:06:04 -080074 class Callback
75 {
76 public:
77 virtual ~Callback() = default;
78
79 /*
80 * Method that signals to a registered callback that this object
81 * has completed doing useful work and is now safe for release/destruction.
82 */
83 virtual void OnDone(ReadHandler & apReadHandlerObj) = 0;
84 };
yunhanw-google08566242021-03-18 15:29:39 -070085
86 /**
Jerry Johns12db26d2022-01-26 10:06:04 -080087 *
88 * Constructor.
89 *
90 * The callback passed in has to outlive this handler object.
yunhanw-google08566242021-03-18 15:29:39 -070091 *
92 */
Jerry Johns12db26d2022-01-26 10:06:04 -080093 ReadHandler(Callback & apCallback, Messaging::ExchangeContext * apExchangeContext, InteractionType aInteractionType);
94
95 /*
96 * Destructor - as part of destruction, it will abort the exchange context
97 * if a valid one still exists.
98 *
99 * See Abort() for details on when that might occur.
100 */
101 ~ReadHandler();
102
yunhanw-google08566242021-03-18 15:29:39 -0700103 /**
yunhanw-googleec5f5dc2021-09-13 16:47:42 -0700104 * Process a read/subscribe request. Parts of the processing may end up being asynchronous, but the ReadHandler
yunhanw-google3bbbc692021-08-31 20:47:36 -0700105 * guarantees that it will call Shutdown on itself when processing is done (including if OnReadInitialRequest
yunhanw-google08566242021-03-18 15:29:39 -0700106 * returns an error).
107 *
yunhanw-google08566242021-03-18 15:29:39 -0700108 * @retval #Others If fails to process read request
109 * @retval #CHIP_NO_ERROR On success.
110 *
111 */
Jerry Johns12db26d2022-01-26 10:06:04 -0800112 CHIP_ERROR OnInitialRequest(System::PacketBufferHandle && aPayload);
yunhanw-google08566242021-03-18 15:29:39 -0700113
114 /**
115 * Send ReportData to initiator
116 *
117 * @param[in] aPayload A payload that has read request data
Song GUO4efa5de2021-11-17 23:39:11 +0800118 * @param[in] aMoreChunks A flags indicating there will be more chunks expected to be sent for this read request
yunhanw-google08566242021-03-18 15:29:39 -0700119 *
120 * @retval #Others If fails to send report data
121 * @retval #CHIP_NO_ERROR On success.
122 *
123 */
Vivien Nicolas6fa8e4c2022-02-10 18:37:41 +0100124 CHIP_ERROR SendReportData(System::PacketBufferHandle && aPayload, bool aMoreChunks);
yunhanw-google08566242021-03-18 15:29:39 -0700125
Jerry Johns12db26d2022-01-26 10:06:04 -0800126 /**
127 * Returns whether this ReadHandler represents a subscription that was created by the other side of the provided exchange.
128 */
129 bool IsFromSubscriber(Messaging::ExchangeContext & apExchangeContext);
130
yunhanw-google2072f8e2021-12-01 12:56:34 -0800131 bool IsReportable() const { return mState == HandlerState::GeneratingReports && !mHoldReport && (mDirty || !mHoldSync); }
yunhanw-googleec5f5dc2021-09-13 16:47:42 -0700132 bool IsGeneratingReports() const { return mState == HandlerState::GeneratingReports; }
133 bool IsAwaitingReportResponse() const { return mState == HandlerState::AwaitingReportResponse; }
yunhanw-google08566242021-03-18 15:29:39 -0700134
yunhanw-google0edb9f92022-02-11 00:50:59 -0800135 CHIP_ERROR ProcessDataVersionFilterList(DataVersionFilterIBs::Parser & aDataVersionFilterListParser);
yunhanw-google8ddfb872021-05-07 18:13:15 -0700136 ClusterInfo * GetAttributeClusterInfolist() { return mpAttributeClusterInfoList; }
137 ClusterInfo * GetEventClusterInfolist() { return mpEventClusterInfoList; }
yunhanw-google0edb9f92022-02-11 00:50:59 -0800138 ClusterInfo * GetDataVersionFilterlist() const { return mpDataVersionFilterList; }
yunhanw-google9a74bae2021-12-15 13:33:05 -0800139 EventNumber & GetEventMin() { return mEventMin; }
yunhanw-google8ddfb872021-05-07 18:13:15 -0700140 PriorityLevel GetCurrentPriority() { return mCurrentPriority; }
141
142 // if current priority is in the middle, it has valid snapshoted last event number, it check cleaness via comparing
143 // with snapshotted last event number. if current priority is in the end, no valid
144 // sanpshotted last event, check with latest last event number, re-setup snapshoted checkpoint, and compare again.
145 bool CheckEventClean(EventManagement & aEventManager);
146
Jerry Johns12db26d2022-01-26 10:06:04 -0800147 bool IsType(InteractionType type) const { return (mInteractionType == type); }
Song GUO4efa5de2021-11-17 23:39:11 +0800148 bool IsChunkedReport() { return mIsChunkedReport; }
Jerry Johnsf58ad862021-11-22 09:34:07 -0800149 bool IsPriming() { return mIsPrimingReports; }
yunhanw-google6a9cd5f2021-10-12 17:44:25 -0700150 bool IsActiveSubscription() const { return mActiveSubscription; }
Song GUOe17d7672022-01-22 10:11:27 +0800151 bool IsFabricFiltered() const { return mIsFabricFiltered; }
yunhanw-googleec5f5dc2021-09-13 16:47:42 -0700152 CHIP_ERROR OnSubscribeRequest(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload);
153 void GetSubscriptionId(uint64_t & aSubscriptionId) { aSubscriptionId = mSubscriptionId; }
Song GUO4efa5de2021-11-17 23:39:11 +0800154 AttributePathExpandIterator * GetAttributePathExpandIterator() { return &mAttributePathExpandIterator; }
155 void SetDirty()
156 {
157 mDirty = true;
158 // If the contents of the global dirty set have changed, we need to reset the iterator since the paths
159 // we've sent up till now are no longer valid and need to be invalidated.
160 mAttributePathExpandIterator = AttributePathExpandIterator(mpAttributeClusterInfoList);
Song GUObfdbd452021-12-06 15:53:34 +0800161 mAttributeEncoderState = AttributeValueEncoder::AttributeEncodeState();
Song GUO4efa5de2021-11-17 23:39:11 +0800162 }
yunhanw-googleec5f5dc2021-09-13 16:47:42 -0700163 void ClearDirty() { mDirty = false; }
164 bool IsDirty() { return mDirty; }
yunhanw-google6a9cd5f2021-10-12 17:44:25 -0700165 NodeId GetInitiatorNodeId() const { return mInitiatorNodeId; }
Marc Lepage24008842021-12-10 00:29:02 -0500166 FabricIndex GetAccessingFabricIndex() const { return mSubjectDescriptor.fabricIndex; }
167
168 const SubjectDescriptor & GetSubjectDescriptor() const { return mSubjectDescriptor; }
yunhanw-googled7208a62021-08-27 13:45:14 -0700169
yunhanw-google07dbf822021-12-02 13:40:06 -0800170 void UnblockUrgentEventDelivery()
171 {
172 mHoldReport = false;
173 mDirty = true;
174 }
175
Song GUObfdbd452021-12-06 15:53:34 +0800176 const AttributeValueEncoder::AttributeEncodeState & GetAttributeEncodeState() const { return mAttributeEncoderState; }
177 void SetAttributeEncodeState(const AttributeValueEncoder::AttributeEncodeState & aState) { mAttributeEncoderState = aState; }
yunhanw-google41700bd2021-12-16 01:20:03 -0800178 uint32_t GetLastWrittenEventsBytes() { return mLastWrittenEventsBytes; }
yunhanw-googlea314baa2022-02-16 16:03:27 -0800179 CHIP_ERROR SendStatusReport(Protocols::InteractionModel::Status aStatus);
Song GUObfdbd452021-12-06 15:53:34 +0800180
yunhanw-google08566242021-03-18 15:29:39 -0700181private:
yunhanw-googleec5f5dc2021-09-13 16:47:42 -0700182 friend class TestReadInteraction;
Jerry Johns12db26d2022-01-26 10:06:04 -0800183
184 //
185 // The engine needs to be able to Abort/Close a ReadHandler instance upon completion of work for a given read/subscribe
186 // interaction. We do not want to make these methods public just to give an adjacent class in the IM access, since public
187 // should really be taking application usage considerations as well. Hence, make it a friend.
188 //
189 friend class chip::app::reporting::Engine;
190
yunhanw-google08566242021-03-18 15:29:39 -0700191 enum class HandlerState
192 {
Jerry Johns12db26d2022-01-26 10:06:04 -0800193 Idle, ///< The handler has been initialized and is ready
yunhanw-googleec5f5dc2021-09-13 16:47:42 -0700194 GeneratingReports, ///< The handler has received either a Read or Subscribe request and is the process of generating a
195 ///< report.
196 AwaitingReportResponse, ///< The handler has sent the report to the client and is awaiting a status response.
Jerry Johns12db26d2022-01-26 10:06:04 -0800197 AwaitingDestruction, ///< The object has completed its work and is awaiting destruction by the application.
yunhanw-google08566242021-03-18 15:29:39 -0700198 };
199
Jerry Johns12db26d2022-01-26 10:06:04 -0800200 /*
201 * This forcibly closes the exchange context if a valid one is pointed to. Such a situation does
202 * not arise during normal message processing flows that all normally call Close() above.
203 *
204 * This will eventually call Close() to drive the process of eventually releasing this object (unless called from the
205 * destructor).
206 *
207 * This is only called by a very narrow set of external objects as needed.
208 */
209 void Abort(bool aCalledFromDestructor = false);
210
211 /**
212 * Called internally to signal the completion of all work on this object, gracefully close the
213 * exchange and finally, signal to a registerd callback that it's
214 * safe to release this object.
215 */
216 void Close();
217
yunhanw-googledb8fbfb2021-11-22 19:25:28 -0800218 static void OnUnblockHoldReportCallback(System::Layer * apSystemLayer, void * apAppState);
yunhanw-googleec5f5dc2021-09-13 16:47:42 -0700219 static void OnRefreshSubscribeTimerSyncCallback(System::Layer * apSystemLayer, void * apAppState);
220 CHIP_ERROR RefreshSubscribeSyncTimer();
221 CHIP_ERROR SendSubscribeResponse();
222 CHIP_ERROR ProcessSubscribeRequest(System::PacketBufferHandle && aPayload);
Zang MingJie860a2042021-05-19 00:54:16 +0800223 CHIP_ERROR ProcessReadRequest(System::PacketBufferHandle && aPayload);
yunhanw-googleb717b362021-11-08 13:34:19 -0800224 CHIP_ERROR ProcessAttributePathList(AttributePathIBs::Parser & aAttributePathListParser);
yunhanw-googlef1117272021-12-02 19:59:44 -0800225 CHIP_ERROR ProcessEventPaths(EventPathIBs::Parser & aEventPathsParser);
yunhanw-google9a74bae2021-12-15 13:33:05 -0800226 CHIP_ERROR ProcessEventFilters(EventFilterIBs::Parser & aEventFiltersParser);
yunhanw-google1516dfd2021-09-16 10:46:55 -0700227 CHIP_ERROR OnStatusResponse(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload);
Zang MingJie2b2622f2021-09-10 20:59:20 +0800228 CHIP_ERROR OnMessageReceived(Messaging::ExchangeContext * apExchangeContext, const PayloadHeader & aPayloadHeader,
229 System::PacketBufferHandle && aPayload) override;
yunhanw-google9c056ef2021-08-25 16:11:21 -0700230 void OnResponseTimeout(Messaging::ExchangeContext * apExchangeContext) override;
Zang MingJie2b2622f2021-09-10 20:59:20 +0800231 CHIP_ERROR OnUnknownMsgType(Messaging::ExchangeContext * apExchangeContext, const PayloadHeader & aPayloadHeader,
232 System::PacketBufferHandle && aPayload);
yunhanw-google08566242021-03-18 15:29:39 -0700233 void MoveToState(const HandlerState aTargetState);
234
235 const char * GetStateStr() const;
yunhanw-google08566242021-03-18 15:29:39 -0700236
237 Messaging::ExchangeContext * mpExchangeCtx = nullptr;
yunhanw-google08566242021-03-18 15:29:39 -0700238
239 // Don't need the response for report data if true
yunhanw-google8ddfb872021-05-07 18:13:15 -0700240 bool mSuppressResponse = false;
yunhanw-google08566242021-03-18 15:29:39 -0700241
242 // Current Handler state
Jerry Johns12db26d2022-01-26 10:06:04 -0800243 HandlerState mState = HandlerState::Idle;
yunhanw-google8ddfb872021-05-07 18:13:15 -0700244 ClusterInfo * mpAttributeClusterInfoList = nullptr;
245 ClusterInfo * mpEventClusterInfoList = nullptr;
yunhanw-google0edb9f92022-02-11 00:50:59 -0800246 ClusterInfo * mpDataVersionFilterList = nullptr;
yunhanw-google8ddfb872021-05-07 18:13:15 -0700247
248 PriorityLevel mCurrentPriority = PriorityLevel::Invalid;
249
yunhanw-google9a74bae2021-12-15 13:33:05 -0800250 EventNumber mEventMin = 0;
yunhanw-google8ddfb872021-05-07 18:13:15 -0700251
252 // The last schedule event number snapshoted in the beginning when preparing to fill new events to reports
yunhanw-google9a74bae2021-12-15 13:33:05 -0800253 EventNumber mLastScheduledEventNumber = 0;
254 Messaging::ExchangeManager * mpExchangeMgr = nullptr;
Jerry Johns12db26d2022-01-26 10:06:04 -0800255 Callback & mCallback;
Jerry Johnsf58ad862021-11-22 09:34:07 -0800256
257 // Tracks whether we're in the initial phase of receiving priming
258 // reports, which is always true for reads and true for subscriptions
259 // prior to receiving a subscribe response.
Jerry Johns12db26d2022-01-26 10:06:04 -0800260 bool mIsPrimingReports = true;
Jerry Johnsf58ad862021-11-22 09:34:07 -0800261 InteractionType mInteractionType = InteractionType::Read;
262 uint64_t mSubscriptionId = 0;
263 uint16_t mMinIntervalFloorSeconds = 0;
264 uint16_t mMaxIntervalCeilingSeconds = 0;
Zang MingJie7a4028d2022-01-08 03:00:35 +0800265 SessionHolder mSessionHandle;
yunhanw-googlea11413e2022-01-14 13:48:18 -0800266 // mHoldReport is used to prevent subscription data delivery while we are
267 // waiting for the min reporting interval to elapse. If we have to send a
268 // report immediately due to an urgent event being queued,
269 // UnblockUrgentEventDelivery can be used to force mHoldReport to false.
yunhanw-google6a9cd5f2021-10-12 17:44:25 -0700270 bool mHoldReport = false;
271 bool mDirty = false;
272 bool mActiveSubscription = false;
Song GUO4efa5de2021-11-17 23:39:11 +0800273 // The flag indicating we are in the middle of a series of chunked report messages, this flag will be cleared during sending
274 // last chunked message.
275 bool mIsChunkedReport = false;
276 NodeId mInitiatorNodeId = kUndefinedNodeId;
Song GUO4efa5de2021-11-17 23:39:11 +0800277 AttributePathExpandIterator mAttributePathExpandIterator = AttributePathExpandIterator(nullptr);
yunhanw-google494fb9b2021-11-17 12:01:02 -0800278 bool mIsFabricFiltered = false;
yunhanw-googlea11413e2022-01-14 13:48:18 -0800279 // mHoldSync is used to prevent subscription empty report delivery while we
280 // are waiting for the max reporting interval to elaps. When mHoldSync
281 // becomes false, we are allowed to send an empty report to keep the
282 // subscription alive on the client.
283 bool mHoldSync = false;
284 uint32_t mLastWrittenEventsBytes = 0;
Marc Lepage24008842021-12-10 00:29:02 -0500285 SubjectDescriptor mSubjectDescriptor;
Song GUObfdbd452021-12-06 15:53:34 +0800286 // The detailed encoding state for a single attribute, used by list chunking feature.
287 AttributeValueEncoder::AttributeEncodeState mAttributeEncoderState;
yunhanw-google08566242021-03-18 15:29:39 -0700288};
289} // namespace app
290} // namespace chip