Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / examples / chip-tool / commands / common / Command.cpp
1 /*
2  *   Copyright (c) 2020 Project CHIP Authors
3  *   All rights reserved.
4  *
5  *   Licensed under the Apache License, Version 2.0 (the "License");
6  *   you may not use this file except in compliance with the License.
7  *   You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *   Unless required by applicable law or agreed to in writing, software
12  *   distributed under the License is distributed on an "AS IS" BASIS,
13  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *   See the License for the specific language governing permissions and
15  *   limitations under the License.
16  *
17  */
18
19 #include "Command.h"
20
21 #include <netdb.h>
22 #include <sstream>
23 #include <sys/socket.h>
24 #include <sys/types.h>
25
26 #include <support/SafeInt.h>
27 #include <support/logging/CHIPLogging.h>
28
29 bool Command::InitArguments(int argc, char ** argv)
30 {
31     bool isValidCommand = false;
32     size_t argsCount    = mArgs.size();
33
34     VerifyOrExit(argsCount == (size_t)(argc),
35                  ChipLogError(chipTool, "InitArgs: Wrong arguments number: %zu instead of %zu", argc, argsCount));
36
37     for (size_t i = 0; i < argsCount; i++)
38     {
39         if (!InitArgument(i, argv[i]))
40         {
41             ExitNow();
42         }
43     }
44
45     isValidCommand = true;
46
47 exit:
48     return isValidCommand;
49 }
50
51 static bool ParseAddressWithInterface(const char * addressString, Command::AddressWithInterface * address)
52 {
53     struct addrinfo hints;
54     struct addrinfo * result;
55     int ret;
56
57     memset(&hints, 0, sizeof(hints));
58     hints.ai_family   = AF_UNSPEC;
59     hints.ai_socktype = SOCK_DGRAM;
60     ret               = getaddrinfo(addressString, nullptr, &hints, &result);
61     if (ret < 0)
62     {
63         ChipLogError(chipTool, "Invalid address: %s", addressString);
64         return false;
65     }
66
67     address->address = ::chip::Inet::IPAddress::FromSockAddr(*result->ai_addr);
68     if (result->ai_family == AF_INET6)
69     {
70         struct sockaddr_in6 * addr = reinterpret_cast<struct sockaddr_in6 *>(result->ai_addr);
71         address->interfaceId       = addr->sin6_scope_id;
72     }
73     else
74     {
75         address->interfaceId = INET_NULL_INTERFACEID;
76     }
77
78     return true;
79 }
80
81 bool Command::InitArgument(size_t argIndex, const char * argValue)
82 {
83     bool isValidArgument = false;
84
85     Argument arg = mArgs.at(argIndex);
86     switch (arg.type)
87     {
88     case ArgumentType::Attribute: {
89         char * value    = reinterpret_cast<char *>(arg.value);
90         isValidArgument = (strcmp(argValue, value) == 0);
91         break;
92     }
93
94     case ArgumentType::String: {
95         const char ** value = reinterpret_cast<const char **>(arg.value);
96         *value              = const_cast<char *>(argValue);
97         isValidArgument     = (strcmp(argValue, *value) == 0);
98         break;
99     }
100
101     case ArgumentType::Number_uint8: {
102         uint8_t * value = reinterpret_cast<uint8_t *>(arg.value);
103
104         // stringstream treats uint8_t as char, which is not what we want here.
105         uint16_t tmpValue;
106         std::stringstream ss(argValue);
107         ss >> tmpValue;
108         if (chip::CanCastTo<uint8_t>(tmpValue))
109         {
110             *value = static_cast<uint8_t>(tmpValue);
111
112             uint64_t min    = chip::CanCastTo<uint64_t>(arg.min) ? static_cast<uint64_t>(arg.min) : 0;
113             uint64_t max    = arg.max;
114             isValidArgument = (!ss.fail() && ss.eof() && *value >= min && *value <= max);
115         }
116         else
117         {
118             isValidArgument = false;
119         }
120         break;
121     }
122
123     case ArgumentType::Number_uint16: {
124         uint16_t * value = reinterpret_cast<uint16_t *>(arg.value);
125         std::stringstream ss(argValue);
126         ss >> *value;
127
128         uint64_t min    = chip::CanCastTo<uint64_t>(arg.min) ? static_cast<uint64_t>(arg.min) : 0;
129         uint64_t max    = arg.max;
130         isValidArgument = (!ss.fail() && ss.eof() && *value >= min && *value <= max);
131         break;
132     }
133
134     case ArgumentType::Number_uint32: {
135         uint32_t * value = reinterpret_cast<uint32_t *>(arg.value);
136         std::stringstream ss(argValue);
137         ss >> *value;
138
139         uint64_t min    = chip::CanCastTo<uint64_t>(arg.min) ? static_cast<uint64_t>(arg.min) : 0;
140         uint64_t max    = arg.max;
141         isValidArgument = (!ss.fail() && ss.eof() && *value >= min && *value <= max);
142         break;
143     }
144
145     case ArgumentType::Number_uint64: {
146         uint64_t * value = reinterpret_cast<uint64_t *>(arg.value);
147         std::stringstream ss(argValue);
148         ss >> *value;
149
150         uint64_t min    = chip::CanCastTo<uint64_t>(arg.min) ? static_cast<uint64_t>(arg.min) : 0;
151         uint64_t max    = arg.max;
152         isValidArgument = (!ss.fail() && ss.eof() && *value >= min && *value <= max);
153         break;
154     }
155
156     case ArgumentType::Number_int8: {
157         int8_t * value = reinterpret_cast<int8_t *>(arg.value);
158
159         // stringstream treats int8_t as char, which is not what we want here.
160         int16_t tmpValue;
161         std::stringstream ss(argValue);
162         ss >> tmpValue;
163         if (chip::CanCastTo<int8_t>(tmpValue))
164         {
165             *value = static_cast<int8_t>(tmpValue);
166
167             int64_t min     = arg.min;
168             int64_t max     = chip::CanCastTo<int64_t>(arg.max) ? static_cast<int64_t>(arg.max) : INT64_MAX;
169             isValidArgument = (!ss.fail() && ss.eof() && *value >= min && *value <= max);
170         }
171         else
172         {
173             isValidArgument = false;
174         }
175         break;
176     }
177
178     case ArgumentType::Number_int16: {
179         int16_t * value = reinterpret_cast<int16_t *>(arg.value);
180         std::stringstream ss(argValue);
181         ss >> *value;
182
183         int64_t min     = arg.min;
184         int64_t max     = chip::CanCastTo<int64_t>(arg.max) ? static_cast<int64_t>(arg.max) : INT64_MAX;
185         isValidArgument = (!ss.fail() && ss.eof() && *value >= min && *value <= max);
186         break;
187     }
188
189     case ArgumentType::Number_int32: {
190         int32_t * value = reinterpret_cast<int32_t *>(arg.value);
191         std::stringstream ss(argValue);
192         ss >> *value;
193
194         int64_t min     = arg.min;
195         int64_t max     = chip::CanCastTo<int64_t>(arg.max) ? static_cast<int64_t>(arg.max) : INT64_MAX;
196         isValidArgument = (!ss.fail() && ss.eof() && *value >= min && *value <= max);
197         break;
198     }
199
200     case ArgumentType::Number_int64: {
201         int64_t * value = reinterpret_cast<int64_t *>(arg.value);
202         std::stringstream ss(argValue);
203         ss >> *value;
204
205         int64_t min     = arg.min;
206         int64_t max     = chip::CanCastTo<int64_t>(arg.max) ? static_cast<int64_t>(arg.max) : INT64_MAX;
207         isValidArgument = (!ss.fail() && ss.eof() && *value >= min && *value <= max);
208         break;
209     }
210
211     case ArgumentType::Address: {
212         AddressWithInterface * value = reinterpret_cast<AddressWithInterface *>(arg.value);
213         isValidArgument              = ParseAddressWithInterface(argValue, value);
214         break;
215     }
216     }
217
218     if (!isValidArgument)
219     {
220         ChipLogError(chipTool, "InitArgs: Invalid argument %s: %s", arg.name, argValue);
221     }
222
223     return isValidArgument;
224 }
225
226 size_t Command::AddArgument(const char * name, const char * value)
227 {
228     Argument arg;
229     arg.type  = ArgumentType::Attribute;
230     arg.name  = name;
231     arg.value = const_cast<void *>(reinterpret_cast<const void *>(value));
232
233     mArgs.emplace_back(arg);
234     return mArgs.size();
235 }
236
237 size_t Command::AddArgument(const char * name, char ** value)
238 {
239     Argument arg;
240     arg.type  = ArgumentType::String;
241     arg.name  = name;
242     arg.value = reinterpret_cast<void *>(value);
243
244     mArgs.emplace_back(arg);
245     return mArgs.size();
246 }
247
248 size_t Command::AddArgument(const char * name, AddressWithInterface * out)
249 {
250     Argument arg;
251     arg.type  = ArgumentType::Address;
252     arg.name  = name;
253     arg.value = reinterpret_cast<void *>(out);
254
255     mArgs.emplace_back(arg);
256     return mArgs.size();
257 }
258
259 size_t Command::AddArgument(const char * name, int64_t min, uint64_t max, void * out, ArgumentType type)
260 {
261     Argument arg;
262     arg.type  = type;
263     arg.name  = name;
264     arg.value = out;
265     arg.min   = min;
266     arg.max   = max;
267
268     mArgs.emplace_back(arg);
269     return mArgs.size();
270 }
271
272 size_t Command::AddArgument(const char * name, int64_t min, uint64_t max, void * out)
273 {
274     Argument arg;
275     arg.type  = ArgumentType::Number_uint8;
276     arg.name  = name;
277     arg.value = out;
278     arg.min   = min;
279     arg.max   = max;
280
281     mArgs.emplace_back(arg);
282     return mArgs.size();
283 }
284
285 const char * Command::GetArgumentName(size_t index) const
286 {
287     if (index < mArgs.size())
288     {
289         return mArgs.at(index).name;
290     }
291
292     return nullptr;
293 }
294
295 const char * Command::GetAttribute(void) const
296 {
297     size_t argsCount = mArgs.size();
298     for (size_t i = 0; i < argsCount; i++)
299     {
300         Argument arg = mArgs.at(i);
301         if (arg.type == ArgumentType::Attribute)
302         {
303             return reinterpret_cast<const char *>(arg.value);
304         }
305     }
306
307     return nullptr;
308 }
309
310 void Command::UpdateWaitForResponse(bool value)
311 {
312     {
313         std::lock_guard<std::mutex> lk(cvWaitingForResponseMutex);
314         mWaitingForResponse = value;
315     }
316     cvWaitingForResponse.notify_all();
317 }
318
319 void Command::WaitForResponse(uint16_t duration)
320 {
321     std::chrono::seconds waitingForResponseTimeout(duration);
322     std::unique_lock<std::mutex> lk(cvWaitingForResponseMutex);
323     auto waitingUntil = std::chrono::system_clock::now() + waitingForResponseTimeout;
324     if (!cvWaitingForResponse.wait_until(lk, waitingUntil, [this]() { return !this->mWaitingForResponse; }))
325     {
326         ChipLogError(chipTool, "No response from device");
327     }
328 }