Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / app / CommandSender.cpp
1 /*
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 objects for a CHIP IM Invoke Command Sender
22  *
23  */
24
25 #include "CommandSender.h"
26 #include "Command.h"
27 #include "CommandHandler.h"
28 #include "InteractionModelEngine.h"
29
30 #include <protocols/secure_channel/Constants.h>
31
32 using GeneralStatusCode = chip::Protocols::SecureChannel::GeneralStatusCode;
33
34 namespace chip {
35 namespace app {
36
37 CHIP_ERROR CommandSender::SendCommandRequest(NodeId aNodeId, Transport::AdminId aAdminId)
38 {
39     CHIP_ERROR err = CHIP_NO_ERROR;
40
41     err = FinalizeCommandsMessage();
42     SuccessOrExit(err);
43
44     ClearExistingExchangeContext();
45
46     // Create a new exchange context.
47     // TODO: temprary create a SecureSessionHandle from node id, will be fix in PR 3602
48     // TODO: Hard code keyID to 0 to unblock IM end-to-end test. Complete solution is tracked in issue:4451
49     mpExchangeCtx = mpExchangeMgr->NewContext({ aNodeId, 0, aAdminId }, this);
50     VerifyOrExit(mpExchangeCtx != nullptr, err = CHIP_ERROR_NO_MEMORY);
51     mpExchangeCtx->SetResponseTimeout(kImMessageTimeoutMsec);
52
53     err = mpExchangeCtx->SendMessage(Protocols::InteractionModel::MsgType::InvokeCommandRequest, std::move(mCommandMessageBuf),
54                                      Messaging::SendFlags(Messaging::SendMessageFlags::kExpectResponse));
55     SuccessOrExit(err);
56     MoveToState(CommandState::Sending);
57
58 exit:
59     if (err != CHIP_NO_ERROR)
60     {
61         ClearExistingExchangeContext();
62     }
63     ChipLogFunctError(err);
64
65     return err;
66 }
67
68 void CommandSender::OnMessageReceived(Messaging::ExchangeContext * apExchangeContext, const PacketHeader & aPacketHeader,
69                                       const PayloadHeader & aPayloadHeader, System::PacketBufferHandle aPayload)
70 {
71     CHIP_ERROR err = CHIP_NO_ERROR;
72     // Assert that the exchange context matches the client's current context.
73     // This should never fail because even if SendCommandRequest is called
74     // back-to-back, the second call will call Close() on the first exchange,
75     // which clears the OnMessageReceived callback.
76
77     VerifyOrDie(apExchangeContext == mpExchangeCtx);
78
79     // Verify that the message is an Invoke Command Response.
80     // If not, close the exchange and free the payload.
81     if (!aPayloadHeader.HasMessageType(Protocols::InteractionModel::MsgType::InvokeCommandResponse))
82     {
83         apExchangeContext->Close();
84         mpExchangeCtx = nullptr;
85         goto exit;
86     }
87
88     // Remove the EC from the app state now. OnMessageReceived can call
89     // SendCommandRequest and install a new one. We abort rather than close
90     // because we no longer care whether the echo request message has been
91     // acknowledged at the transport layer.
92     ClearExistingExchangeContext();
93
94     err = ProcessCommandMessage(std::move(aPayload), CommandRoleId::SenderId);
95     SuccessOrExit(err);
96
97 exit:
98     Reset();
99 }
100
101 void CommandSender::OnResponseTimeout(Messaging::ExchangeContext * apExchangeContext)
102 {
103     ChipLogProgress(DataManagement, "Time out! failed to receive invoke command response from Exchange: %d",
104                     apExchangeContext->GetExchangeId());
105     Reset();
106
107     if (mpDelegate != nullptr)
108     {
109         mpDelegate->CommandResponseTimeout(this);
110     }
111 }
112
113 CHIP_ERROR CommandSender::ProcessCommandDataElement(CommandDataElement::Parser & aCommandElement)
114 {
115     CHIP_ERROR err = CHIP_NO_ERROR;
116     CommandPath::Parser commandPath;
117     chip::TLV::TLVReader commandDataReader;
118     chip::ClusterId clusterId;
119     chip::CommandId commandId;
120     chip::EndpointId endpointId;
121     Protocols::SecureChannel::GeneralStatusCode generalCode = Protocols::SecureChannel::GeneralStatusCode::kSuccess;
122     uint32_t protocolId                                     = 0;
123     uint16_t protocolCode                                   = 0;
124     StatusElement::Parser statusElementParser;
125
126     mCommandIndex++;
127
128     err = aCommandElement.GetCommandPath(&commandPath);
129     SuccessOrExit(err);
130
131     err = commandPath.GetClusterId(&clusterId);
132     SuccessOrExit(err);
133
134     err = commandPath.GetCommandId(&commandId);
135     SuccessOrExit(err);
136
137     err = commandPath.GetEndpointId(&endpointId);
138     SuccessOrExit(err);
139
140     err = aCommandElement.GetStatusElement(&statusElementParser);
141     if (CHIP_NO_ERROR == err)
142     {
143         // Response has status element since either there is error in command response or it is empty response
144         err = statusElementParser.CheckSchemaValidity();
145         SuccessOrExit(err);
146
147         err = statusElementParser.DecodeStatusElement(&generalCode, &protocolId, &protocolCode);
148         SuccessOrExit(err);
149         if (mpDelegate != nullptr)
150         {
151             mpDelegate->CommandResponseStatus(this, generalCode, protocolId, protocolCode, endpointId, clusterId, commandId,
152                                               mCommandIndex);
153         }
154     }
155     else if (CHIP_END_OF_TLV == err)
156     {
157         err = aCommandElement.GetData(&commandDataReader);
158         SuccessOrExit(err);
159         // TODO(#4503): Should call callbacks of cluster that sends the command.
160         DispatchSingleClusterCommand(clusterId, commandId, endpointId, commandDataReader, this);
161     }
162
163 exit:
164     ChipLogFunctError(err);
165     if (err != CHIP_NO_ERROR && mpDelegate != nullptr)
166     {
167         mpDelegate->CommandResponseProtocolError(this, mCommandIndex);
168     }
169     return err;
170 }
171
172 } // namespace app
173 } // namespace chip