forked from project-chip/connectedhomeip
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathWriteHandler.h
210 lines (180 loc) · 9.24 KB
/
WriteHandler.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
/*
*
* 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.
*/
#pragma once
#include <app/AttributeAccessToken.h>
#include <app/AttributePathParams.h>
#include <app/InteractionModelDelegatePointers.h>
#include <app/MessageDef/WriteResponseMessage.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/ExchangeHolder.h>
#include <messaging/ExchangeMgr.h>
#include <messaging/Flags.h>
#include <protocols/Protocols.h>
#include <protocols/interaction_model/Constants.h>
#include <protocols/interaction_model/StatusCode.h>
#include <system/SystemPacketBuffer.h>
#include <system/TLVPacketBufferBackingStore.h>
namespace chip {
namespace app {
class WriteHandler;
class WriteHandlerDelegate
{
public:
virtual ~WriteHandlerDelegate() = default;
/**
* Returns whether the write operation to the given path is in conflict with another write operation.
* (i.e. another write transaction is in the middle of processing a chunked write to the given path.)
*/
virtual bool HasConflictWriteRequests(const WriteHandler * apWriteHandler, const ConcreteAttributePath & aPath) = 0;
};
/**
* @brief The write handler is responsible for processing a write request and sending a write reply.
*/
class WriteHandler : public Messaging::ExchangeDelegate
{
public:
WriteHandler() : mExchangeCtx(*this) {}
/**
* Initialize the WriteHandler. Within the lifetime
* of this instance, this method is invoked once after object
* construction until a call to Close is made to terminate the
* instance.
*
* @param[in] apWriteHandlerDelegate A Valid pointer to the WriteHandlerDelegate.
*
* @retval #CHIP_ERROR_INCORRECT_STATE If the state is not equal to
* kState_NotInitialized.
* @retval #CHIP_NO_ERROR On success.
*/
CHIP_ERROR Init(WriteHandlerDelegate * apWriteHandlerDelegate);
/**
* Process a write request. Parts of the processing may end up being asynchronous, but the WriteHandler
* guarantees that it will call Close on itself when processing is done (including if OnWriteRequest
* returns an error).
*
* @param[in] apExchangeContext A pointer to the ExchangeContext.
* @param[in] aPayload A payload that has read request data
* @param[in] aIsTimedWrite Whether write is part of a timed interaction.
*
* @retval Status. Callers are expected to send a status response if the
* return status is not Status::Success.
*/
Protocols::InteractionModel::Status OnWriteRequest(Messaging::ExchangeContext * apExchangeContext,
System::PacketBufferHandle && aPayload, bool aIsTimedWrite);
/**
* Clean up state when we are done sending the write response.
*/
void Close();
bool IsFree() const { return mState == State::Uninitialized; }
~WriteHandler() override = default;
CHIP_ERROR ProcessAttributeDataIBs(TLV::TLVReader & aAttributeDataIBsReader);
CHIP_ERROR ProcessGroupAttributeDataIBs(TLV::TLVReader & aAttributeDataIBsReader);
CHIP_ERROR AddStatus(const ConcreteDataAttributePath & aPath, const Protocols::InteractionModel::ClusterStatusCode & aStatus);
CHIP_ERROR AddStatus(const ConcreteDataAttributePath & aPath, const Protocols::InteractionModel::Status aStatus)
{
return AddStatus(aPath, Protocols::InteractionModel::ClusterStatusCode{ aStatus });
}
CHIP_ERROR AddClusterSpecificSuccess(const ConcreteDataAttributePath & aAttributePathParams, ClusterStatus aClusterStatus);
CHIP_ERROR AddClusterSpecificFailure(const ConcreteDataAttributePath & aAttributePathParams, ClusterStatus aClusterStatus);
FabricIndex GetAccessingFabricIndex() const;
/**
* Check whether the WriteRequest we are handling is a timed write.
*/
bool IsTimedWrite() const { return mIsTimedRequest; }
bool MatchesExchangeContext(Messaging::ExchangeContext * apExchangeContext) const
{
return !IsFree() && mExchangeCtx.Get() == apExchangeContext;
}
void CacheACLCheckResult(const AttributeAccessToken & aToken) { mACLCheckCache.SetValue(aToken); }
bool ACLCheckCacheHit(const AttributeAccessToken & aToken)
{
return mACLCheckCache.HasValue() && mACLCheckCache.Value() == aToken;
}
bool IsCurrentlyProcessingWritePath(const ConcreteAttributePath & aPath)
{
return mProcessingAttributePath.HasValue() && mProcessingAttributePath.Value() == aPath;
}
private:
friend class TestWriteInteraction;
enum class State
{
Uninitialized = 0, // The handler has not been initialized
Initialized, // The handler has been initialized and is ready
AddStatus, // The handler has added status code
Sending, // The handler has sent out the write response
};
using Status = Protocols::InteractionModel::Status;
Status ProcessWriteRequest(System::PacketBufferHandle && aPayload, bool aIsTimedWrite);
Status HandleWriteRequestMessage(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload,
bool aIsTimedWrite);
CHIP_ERROR FinalizeMessage(System::PacketBufferTLVWriter && aMessageWriter, System::PacketBufferHandle & packet);
CHIP_ERROR SendWriteResponse(System::PacketBufferTLVWriter && aMessageWriter);
void MoveToState(const State aTargetState);
const char * GetStateStr() const;
void DeliverListWriteBegin(const ConcreteAttributePath & aPath);
void DeliverListWriteEnd(const ConcreteAttributePath & aPath, bool writeWasSuccessful);
// Deliver the signal that we have delivered all list entries to the AttributeAccessInterface. This function will be called
// after handling the last chunk of a series of write requests. Or the write handler was shutdown (usually due to transport
// timeout).
// This function will become no-op on group writes, since DeliverFinalListWriteEndForGroupWrite will clear the
// mProcessingAttributePath after processing the AttributeDataIBs from the request.
void DeliverFinalListWriteEnd(bool writeWasSuccessful);
// Deliver the signal that we have delivered all list entries to the AttributeAccessInterface. This function will be called
// after handling the last attribute in a group write request (since group writes will never be chunked writes). Or we failed to
// process the group write request (usually due to malformed messages). This function should only be called by
// ProcessGroupAttributeDataIBs.
CHIP_ERROR DeliverFinalListWriteEndForGroupWrite(bool writeWasSuccessful);
CHIP_ERROR AddStatusInternal(const ConcreteDataAttributePath & aPath, const StatusIB & aStatus);
private:
// ExchangeDelegate
CHIP_ERROR OnMessageReceived(Messaging::ExchangeContext * apExchangeContext, const PayloadHeader & aPayloadHeader,
System::PacketBufferHandle && aPayload) override;
void OnResponseTimeout(Messaging::ExchangeContext * apExchangeContext) override;
Messaging::ExchangeHolder mExchangeCtx;
WriteResponseMessage::Builder mWriteResponseBuilder;
State mState = State::Uninitialized;
bool mIsTimedRequest = false;
bool mSuppressResponse = false;
bool mHasMoreChunks = false;
Optional<ConcreteAttributePath> mProcessingAttributePath;
bool mProcessingAttributeIsList = false;
// We record the Status when AddStatus is called to determine whether all data of a list write is accepted.
// This value will be used by DeliverListWriteEnd and DeliverFinalListWriteEnd but it won't be used by group writes based on the
// fact that the errors that won't be delivered to AttributeAccessInterface are:
// (1) Attribute not found
// (2) Access control failed
// (3) Write request to a read-only attribute
// (4) Data version mismatch
// (5) Not using timed write.
// Where (1)-(3) will be consistent among the whole list write request, while (4) and (5) are not appliable to group writes.
bool mAttributeWriteSuccessful = false;
Optional<AttributeAccessToken> mACLCheckCache = NullOptional;
// This may be a "fake" pointer or a real delegate pointer, depending
// on CHIP_CONFIG_STATIC_GLOBAL_INTERACTION_MODEL_ENGINE setting.
//
// When this is not a real pointer, it checks that the value is always
// set to the global InteractionModelEngine and the size of this
// member is 1 byte.
InteractionModelDelegatePointer<WriteHandlerDelegate> mDelegate;
};
} // namespace app
} // namespace chip