2 * Copyright (c) 2020 Project CHIP Authors
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 #include <sys/socket.h>
24 #include <sys/types.h>
26 #include <support/SafeInt.h>
27 #include <support/logging/CHIPLogging.h>
29 bool Command::InitArguments(int argc, char ** argv)
31 bool isValidCommand = false;
32 size_t argsCount = mArgs.size();
34 VerifyOrExit(argsCount == (size_t)(argc),
35 ChipLogError(chipTool, "InitArgs: Wrong arguments number: %zu instead of %zu", argc, argsCount));
37 for (size_t i = 0; i < argsCount; i++)
39 if (!InitArgument(i, argv[i]))
45 isValidCommand = true;
48 return isValidCommand;
51 static bool ParseAddressWithInterface(const char * addressString, Command::AddressWithInterface * address)
53 struct addrinfo hints;
54 struct addrinfo * result;
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);
63 ChipLogError(chipTool, "Invalid address: %s", addressString);
67 address->address = ::chip::Inet::IPAddress::FromSockAddr(*result->ai_addr);
68 if (result->ai_family == AF_INET6)
70 struct sockaddr_in6 * addr = reinterpret_cast<struct sockaddr_in6 *>(result->ai_addr);
71 address->interfaceId = addr->sin6_scope_id;
75 address->interfaceId = INET_NULL_INTERFACEID;
81 bool Command::InitArgument(size_t argIndex, const char * argValue)
83 bool isValidArgument = false;
85 Argument arg = mArgs.at(argIndex);
88 case ArgumentType::Attribute: {
89 char * value = reinterpret_cast<char *>(arg.value);
90 isValidArgument = (strcmp(argValue, value) == 0);
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);
101 case ArgumentType::Number_uint8: {
102 uint8_t * value = reinterpret_cast<uint8_t *>(arg.value);
104 // stringstream treats uint8_t as char, which is not what we want here.
106 std::stringstream ss(argValue);
108 if (chip::CanCastTo<uint8_t>(tmpValue))
110 *value = static_cast<uint8_t>(tmpValue);
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);
118 isValidArgument = false;
123 case ArgumentType::Number_uint16: {
124 uint16_t * value = reinterpret_cast<uint16_t *>(arg.value);
125 std::stringstream ss(argValue);
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);
134 case ArgumentType::Number_uint32: {
135 uint32_t * value = reinterpret_cast<uint32_t *>(arg.value);
136 std::stringstream ss(argValue);
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);
145 case ArgumentType::Number_uint64: {
146 uint64_t * value = reinterpret_cast<uint64_t *>(arg.value);
147 std::stringstream ss(argValue);
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);
156 case ArgumentType::Number_int8: {
157 int8_t * value = reinterpret_cast<int8_t *>(arg.value);
159 // stringstream treats int8_t as char, which is not what we want here.
161 std::stringstream ss(argValue);
163 if (chip::CanCastTo<int8_t>(tmpValue))
165 *value = static_cast<int8_t>(tmpValue);
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);
173 isValidArgument = false;
178 case ArgumentType::Number_int16: {
179 int16_t * value = reinterpret_cast<int16_t *>(arg.value);
180 std::stringstream ss(argValue);
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);
189 case ArgumentType::Number_int32: {
190 int32_t * value = reinterpret_cast<int32_t *>(arg.value);
191 std::stringstream ss(argValue);
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);
200 case ArgumentType::Number_int64: {
201 int64_t * value = reinterpret_cast<int64_t *>(arg.value);
202 std::stringstream ss(argValue);
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);
211 case ArgumentType::Address: {
212 AddressWithInterface * value = reinterpret_cast<AddressWithInterface *>(arg.value);
213 isValidArgument = ParseAddressWithInterface(argValue, value);
218 if (!isValidArgument)
220 ChipLogError(chipTool, "InitArgs: Invalid argument %s: %s", arg.name, argValue);
223 return isValidArgument;
226 size_t Command::AddArgument(const char * name, const char * value)
229 arg.type = ArgumentType::Attribute;
231 arg.value = const_cast<void *>(reinterpret_cast<const void *>(value));
233 mArgs.emplace_back(arg);
237 size_t Command::AddArgument(const char * name, char ** value)
240 arg.type = ArgumentType::String;
242 arg.value = reinterpret_cast<void *>(value);
244 mArgs.emplace_back(arg);
248 size_t Command::AddArgument(const char * name, AddressWithInterface * out)
251 arg.type = ArgumentType::Address;
253 arg.value = reinterpret_cast<void *>(out);
255 mArgs.emplace_back(arg);
259 size_t Command::AddArgument(const char * name, int64_t min, uint64_t max, void * out, ArgumentType type)
268 mArgs.emplace_back(arg);
272 size_t Command::AddArgument(const char * name, int64_t min, uint64_t max, void * out)
275 arg.type = ArgumentType::Number_uint8;
281 mArgs.emplace_back(arg);
285 const char * Command::GetArgumentName(size_t index) const
287 if (index < mArgs.size())
289 return mArgs.at(index).name;
295 const char * Command::GetAttribute(void) const
297 size_t argsCount = mArgs.size();
298 for (size_t i = 0; i < argsCount; i++)
300 Argument arg = mArgs.at(i);
301 if (arg.type == ArgumentType::Attribute)
303 return reinterpret_cast<const char *>(arg.value);
310 void Command::UpdateWaitForResponse(bool value)
313 std::lock_guard<std::mutex> lk(cvWaitingForResponseMutex);
314 mWaitingForResponse = value;
316 cvWaitingForResponse.notify_all();
319 void Command::WaitForResponse(uint16_t duration)
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; }))
326 ChipLogError(chipTool, "No response from device");