forked from project-chip/connectedhomeip
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCommandResponseSender.h
194 lines (166 loc) · 7.54 KB
/
CommandResponseSender.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
/*
* Copyright (c) 2024 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/CommandHandlerExchangeInterface.h>
#include <app/CommandHandlerImpl.h>
#include <app/StatusResponse.h>
#include <messaging/ExchangeHolder.h>
#include <system/SystemPacketBuffer.h>
namespace chip {
namespace app {
// TODO(#30453): Rename CommandResponseSender to CommandResponder in follow up PR
/**
* Manages the process of sending InvokeResponseMessage(s) to the requester.
*
* Implements the CommandHandlerExchangeInterface. Uses a CommandHandler member to process
* InvokeCommandRequest. The CommandHandler is provided a reference to this
* CommandHandlerExchangeInterface implementation to enable sending InvokeResponseMessage(s).
*/
class CommandResponseSender : public Messaging::ExchangeDelegate,
public CommandHandlerImpl::Callback,
public CommandHandlerExchangeInterface
{
public:
class Callback
{
public:
virtual ~Callback() = default;
/*
* Signals registered callback that this object has finished its work and can now be
* safely destroyed/released.
*/
virtual void OnDone(CommandResponseSender & apResponderObj) = 0;
};
CommandResponseSender(Callback * apCallback, CommandHandlerImpl::Callback * apDispatchCallback) :
mpCallback(apCallback), mpCommandHandlerCallback(apDispatchCallback), mCommandHandler(this), mExchangeCtx(*this)
{}
CHIP_ERROR OnMessageReceived(Messaging::ExchangeContext * ec, const PayloadHeader & payloadHeader,
System::PacketBufferHandle && payload) override;
void OnResponseTimeout(Messaging::ExchangeContext * ec) override;
void OnDone(CommandHandlerImpl & apCommandObj) override;
void DispatchCommand(CommandHandlerImpl & apCommandObj, const ConcreteCommandPath & aCommandPath,
TLV::TLVReader & apPayload) override;
Protocols::InteractionModel::Status CommandExists(const ConcreteCommandPath & aCommandPath) override;
/**
* Gets the inner exchange context object, without ownership.
*
* WARNING: This is dangerous, since it is directly interacting with the
* exchange being managed automatically by mExchangeCtx and
* if not done carefully, may end up with use-after-free errors.
*
* @return The inner exchange context, might be nullptr if no
* exchange context has been assigned or the context
* has been released.
*/
Messaging::ExchangeContext * GetExchangeContext() const override { return mExchangeCtx.Get(); }
/**
* Gets subject descriptor of the exchange.
*
* WARNING: This method should only be called when the caller is certain the
* session has not been evicted.
*/
Access::SubjectDescriptor GetSubjectDescriptor() const override
{
VerifyOrDie(mExchangeCtx);
return mExchangeCtx->GetSessionHandle()->GetSubjectDescriptor();
}
FabricIndex GetAccessingFabricIndex() const override
{
VerifyOrDie(mExchangeCtx);
return mExchangeCtx->GetSessionHandle()->GetFabricIndex();
}
Optional<GroupId> GetGroupId() const override
{
VerifyOrDie(mExchangeCtx);
auto sessionHandle = mExchangeCtx->GetSessionHandle();
if (sessionHandle->GetSessionType() != Transport::Session::SessionType::kGroupIncoming)
{
return NullOptional;
}
return MakeOptional(sessionHandle->AsIncomingGroupSession()->GetGroupId());
}
void HandlingSlowCommand() override
{
VerifyOrReturn(mExchangeCtx);
auto * msgContext = mExchangeCtx->GetReliableMessageContext();
VerifyOrReturn(msgContext != nullptr);
msgContext->FlushAcks();
}
void AddInvokeResponseToSend(System::PacketBufferHandle && aPacket) override
{
VerifyOrDie(mState == State::ReadyForInvokeResponses);
mChunks.AddToEnd(std::move(aPacket));
}
void ResponseDropped() override { mReportResponseDropped = true; }
/*
* Main entrypoint for this class to handle an invoke request.
*
* isTimedInvoke is true if and only if this is part of a Timed Invoke
* transaction (i.e. was preceded by a Timed Request). If we reach here,
* the timer verification has already been done.
*/
void OnInvokeCommandRequest(Messaging::ExchangeContext * ec, System::PacketBufferHandle && payload, bool isTimedInvoke);
#if CHIP_WITH_NLFAULTINJECTION
/**
* @brief Sends InvokeResponseMessages with injected faults for certification testing.
*
* The Test Harness (TH) uses this to simulate various server response behaviors,
* ensuring the Device Under Test (DUT) handles responses per specification.
*
* This function strictly validates the DUT's InvokeRequestMessage against the test plan.
* If deviations occur, the TH terminates with a detailed error message.
*
* @param ec Exchange context for sending InvokeResponseMessages to the client.
* @param payload Payload of the incoming InvokeRequestMessage from the client.
* @param isTimedInvoke Indicates whether the interaction is timed.
* @param faultType The specific type of fault to inject into the response.
*/
void TestOnlyInvokeCommandRequestWithFaultsInjected(Messaging::ExchangeContext * ec, System::PacketBufferHandle && payload,
bool isTimedInvoke, CommandHandlerImpl::NlFaultInjectionType faultType);
#endif // CHIP_WITH_NLFAULTINJECTION
private:
enum class State : uint8_t
{
ReadyForInvokeResponses, ///< Accepting InvokeResponses to send back to requester.
AwaitingStatusResponse, ///< Awaiting status response from requester, after sending InvokeResponse.
AllInvokeResponsesSent, ///< All InvokeResponses have been sent out.
ErrorSentDelayCloseUntilOnDone ///< We have sent an early error response, but still need to clean up.
};
void MoveToState(const State aTargetState);
const char * GetStateStr() const;
/**
* @brief Initiates the sending of InvokeResponses previously queued using AddInvokeResponseToSend.
*/
void StartSendingCommandResponses();
void SendStatusResponse(Protocols::InteractionModel::Status aStatus)
{
StatusResponse::Send(aStatus, mExchangeCtx.Get(), /*aExpectResponse = */ false);
}
CHIP_ERROR SendCommandResponse();
bool HasMoreToSend() { return !mChunks.IsNull() || mReportResponseDropped; }
void Close();
// A list of InvokeResponseMessages to be sent out by CommandResponseSender.
System::PacketBufferHandle mChunks;
Callback * mpCallback;
CommandHandlerImpl::Callback * mpCommandHandlerCallback;
CommandHandlerImpl mCommandHandler;
Messaging::ExchangeHolder mExchangeCtx;
State mState = State::ReadyForInvokeResponses;
bool mReportResponseDropped = false;
};
} // namespace app
} // namespace chip