1 /******************************************************************************
2 *
3 * Copyright (C) 2014 Google, Inc.
4 * Copyright (C) 2018 The Linux Foundation
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 #define LOG_TAG "device_iot_config"
20
21 #include "device/include/device_iot_config.h"
22
23 #include <bluetooth/log.h>
24 #include <ctype.h>
25 #include <string.h>
26 #include <time.h>
27 #include <unistd.h>
28
29 #include <mutex>
30 #include <string>
31
32 #include "device_iot_config_int.h"
33 #include "internal_include/bt_target.h"
34 #include "osi/include/alarm.h"
35 #include "osi/include/allocator.h"
36 #include "osi/include/compat.h"
37 #include "osi/include/config.h"
38
39 enum ConfigSource device_iot_config_source = NOT_LOADED;
40
41 int device_iot_config_devices_loaded = -1;
42 char device_iot_config_time_created[TIME_STRING_LENGTH];
43
44 std::mutex config_lock; // protects operations on |config|.
45 std::unique_ptr<config_t> config;
46 alarm_t* config_timer;
47
48 using namespace bluetooth;
49
device_iot_config_has_section(const std::string & section)50 bool device_iot_config_has_section(const std::string& section) {
51 std::unique_lock<std::mutex> lock(config_lock);
52 log::assert_that(config != NULL, "assert failed: config != NULL");
53
54 return config_has_section(*config, section);
55 }
56
device_iot_config_exist(const std::string & section,const std::string & key)57 bool device_iot_config_exist(const std::string& section, const std::string& key) {
58 std::unique_lock<std::mutex> lock(config_lock);
59 log::assert_that(config != NULL, "assert failed: config != NULL");
60
61 return config_has_key(*config, section, key);
62 }
63
device_iot_config_get_int(const std::string & section,const std::string & key,int & value)64 bool device_iot_config_get_int(const std::string& section, const std::string& key, int& value) {
65 std::unique_lock<std::mutex> lock(config_lock);
66 log::assert_that(config != NULL, "assert failed: config != NULL");
67
68 bool ret = config_has_key(*config, section, key);
69 if (ret) {
70 value = config_get_int(*config, section, key, value);
71 }
72
73 return ret;
74 }
75
device_iot_config_set_int(const std::string & section,const std::string & key,int value)76 bool device_iot_config_set_int(const std::string& section, const std::string& key, int value) {
77 std::unique_lock<std::mutex> lock(config_lock);
78 log::assert_that(config != NULL, "assert failed: config != NULL");
79
80 char value_str[32] = {0};
81 snprintf(value_str, sizeof(value_str), "%d", value);
82 if (device_iot_config_has_key_value(section, key, value_str)) {
83 return true;
84 }
85
86 config_set_string(config.get(), section, key, value_str);
87 device_iot_config_save_async();
88
89 return true;
90 }
91
device_iot_config_int_add_one(const std::string & section,const std::string & key)92 bool device_iot_config_int_add_one(const std::string& section, const std::string& key) {
93 std::unique_lock<std::mutex> lock(config_lock);
94 log::assert_that(config != NULL, "assert failed: config != NULL");
95
96 int result = 0;
97 result = config_get_int(*config, section, key, result);
98 if (result >= 0) {
99 result += 1;
100 } else {
101 result = 0;
102 }
103 config_set_int(config.get(), section, key, result);
104 device_iot_config_save_async();
105
106 return true;
107 }
108
device_iot_config_get_hex(const std::string & section,const std::string & key,int & value)109 bool device_iot_config_get_hex(const std::string& section, const std::string& key, int& value) {
110 std::unique_lock<std::mutex> lock(config_lock);
111 log::assert_that(config != NULL, "assert failed: config != NULL");
112
113 const std::string* stored_value = config_get_string(*config, section, key, NULL);
114 if (!stored_value) {
115 return false;
116 }
117
118 errno = 0;
119 char* endptr = nullptr;
120 int result = strtoul(stored_value->c_str(), &endptr, 16);
121 if (stored_value->c_str() == endptr) {
122 return false;
123 }
124 if (endptr == nullptr || endptr[0] != '\0') {
125 return false;
126 }
127 if (errno) {
128 return false;
129 }
130
131 value = result;
132 return true;
133 }
134
device_iot_config_set_hex(const std::string & section,const std::string & key,int value,int byte_num)135 bool device_iot_config_set_hex(const std::string& section, const std::string& key, int value,
136 int byte_num) {
137 char value_str[32] = {0};
138 if (byte_num == 1) {
139 snprintf(value_str, sizeof(value_str), "%02x", value);
140 } else if (byte_num == 2) {
141 snprintf(value_str, sizeof(value_str), "%04x", value);
142 } else if (byte_num == 3) {
143 snprintf(value_str, sizeof(value_str), "%06x", value);
144 } else if (byte_num == 4) {
145 snprintf(value_str, sizeof(value_str), "%08x", value);
146 }
147
148 std::unique_lock<std::mutex> lock(config_lock);
149 log::assert_that(config != NULL, "assert failed: config != NULL");
150 if (device_iot_config_has_key_value(section, key, value_str)) {
151 return true;
152 }
153
154 config_set_string(config.get(), section, key, value_str);
155 device_iot_config_save_async();
156
157 return true;
158 }
159
device_iot_config_set_hex_if_greater(const std::string & section,const std::string & key,int value,int byte_num)160 bool device_iot_config_set_hex_if_greater(const std::string& section, const std::string& key,
161 int value, int byte_num) {
162 int stored_value = 0;
163 bool ret = device_iot_config_get_hex(section, key, stored_value);
164 if (ret && stored_value >= value) {
165 return true;
166 }
167
168 return device_iot_config_set_hex(section, key, value, byte_num);
169 }
170
device_iot_config_get_str(const std::string & section,const std::string & key,char * value,int * size_bytes)171 bool device_iot_config_get_str(const std::string& section, const std::string& key, char* value,
172 int* size_bytes) {
173 std::unique_lock<std::mutex> lock(config_lock);
174 log::assert_that(config != NULL, "assert failed: config != NULL");
175 log::assert_that(value != NULL, "assert failed: value != NULL");
176 log::assert_that(size_bytes != NULL, "assert failed: size_bytes != NULL");
177
178 const std::string* stored_value = config_get_string(*config, section, key, NULL);
179
180 if (!stored_value) {
181 return false;
182 }
183
184 osi_strlcpy(value, stored_value->c_str(), *size_bytes);
185 *size_bytes = strlen(value) + 1;
186
187 return true;
188 }
189
device_iot_config_set_str(const std::string & section,const std::string & key,const std::string & value)190 bool device_iot_config_set_str(const std::string& section, const std::string& key,
191 const std::string& value) {
192 std::unique_lock<std::mutex> lock(config_lock);
193 log::assert_that(config != NULL, "assert failed: config != NULL");
194
195 if (device_iot_config_has_key_value(section, key, value)) {
196 return true;
197 }
198
199 config_set_string(config.get(), section, key, value);
200 device_iot_config_save_async();
201
202 return true;
203 }
204
device_iot_config_get_bin(const std::string & section,const std::string & key,uint8_t * value,size_t * length)205 bool device_iot_config_get_bin(const std::string& section, const std::string& key, uint8_t* value,
206 size_t* length) {
207 std::unique_lock<std::mutex> lock(config_lock);
208 log::assert_that(config != NULL, "assert failed: config != NULL");
209 log::assert_that(value != NULL, "assert failed: value != NULL");
210 log::assert_that(length != NULL, "assert failed: length != NULL");
211
212 const std::string* value_string = config_get_string(*config, section, key, NULL);
213
214 if (!value_string) {
215 return false;
216 }
217
218 const char* value_str = value_string->c_str();
219
220 size_t value_len = strlen(value_str);
221 if ((value_len % 2) != 0 || *length < (value_len / 2)) {
222 return false;
223 }
224
225 for (size_t i = 0; i < value_len; ++i) {
226 if (!isxdigit(value_str[i])) {
227 return false;
228 }
229 }
230
231 for (*length = 0; *value_str; value_str += 2, *length += 1) {
232 errno = 0;
233 char* endptr = nullptr;
234 value[*length] = strtoul(value_str, &endptr, 16);
235 if (value_str == endptr) {
236 return false;
237 }
238 if (*endptr) {
239 return false;
240 }
241 if (errno) {
242 return false;
243 }
244 }
245
246 return true;
247 }
248
device_iot_config_get_bin_length(const std::string & section,const std::string & key)249 size_t device_iot_config_get_bin_length(const std::string& section, const std::string& key) {
250 std::unique_lock<std::mutex> lock(config_lock);
251 log::assert_that(config != NULL, "assert failed: config != NULL");
252
253 const std::string* value_str = config_get_string(*config, section, key, NULL);
254
255 if (!value_str) {
256 return 0;
257 }
258
259 size_t value_len = strlen(value_str->c_str());
260 return ((value_len % 2) != 0) ? 0 : (value_len / 2);
261 }
262
device_iot_config_set_bin(const std::string & section,const std::string & key,const uint8_t * value,size_t length)263 bool device_iot_config_set_bin(const std::string& section, const std::string& key,
264 const uint8_t* value, size_t length) {
265 const char* lookup = "0123456789abcdef";
266
267 log::verbose("Key = {}", key);
268 if (length > 0) {
269 log::assert_that(value != NULL, "assert failed: value != NULL");
270 }
271
272 char* str = (char*)osi_calloc(length * 2 + 1);
273 if (str == NULL) {
274 log::error("Unable to allocate a str.");
275 return false;
276 }
277
278 for (size_t i = 0; i < length; ++i) {
279 str[(i * 2) + 0] = lookup[(value[i] >> 4) & 0x0F];
280 str[(i * 2) + 1] = lookup[value[i] & 0x0F];
281 }
282
283 std::unique_lock<std::mutex> lock(config_lock);
284 log::assert_that(config != NULL, "assert failed: config != NULL");
285 if (device_iot_config_has_key_value(section, key, str)) {
286 osi_free(str);
287 return true;
288 }
289
290 config_set_string(config.get(), section, key, str);
291 device_iot_config_save_async();
292
293 osi_free(str);
294 return true;
295 }
296
device_iot_config_remove(const std::string & section,const std::string & key)297 bool device_iot_config_remove(const std::string& section, const std::string& key) {
298 std::unique_lock<std::mutex> lock(config_lock);
299 log::assert_that(config != NULL, "assert failed: config != NULL");
300
301 return config_remove_key(config.get(), section, key);
302 }
303
device_iot_config_flush(void)304 void device_iot_config_flush(void) {
305 log::assert_that(config != NULL, "assert failed: config != NULL");
306 log::assert_that(config_timer != NULL, "assert failed: config_timer != NULL");
307
308 int event =
309 alarm_is_scheduled(config_timer) ? IOT_CONFIG_SAVE_TIMER_FIRED_EVT : IOT_CONFIG_FLUSH_EVT;
310 log::verbose("evt={}", event);
311 alarm_cancel(config_timer);
312 device_iot_config_write(event, NULL);
313 }
314
device_iot_config_clear(void)315 bool device_iot_config_clear(void) {
316 log::assert_that(config != NULL, "assert failed: config != NULL");
317 log::assert_that(config_timer != NULL, "assert failed: config_timer != NULL");
318
319 log::info("");
320 alarm_cancel(config_timer);
321
322 std::unique_lock<std::mutex> lock(config_lock);
323 config.reset();
324
325 config = config_new_empty();
326 if (config == NULL) {
327 return false;
328 }
329
330 bool ret = config_save(*config, IOT_CONFIG_FILE_PATH);
331 device_iot_config_source = RESET;
332 return ret;
333 }
334
device_debug_iot_config_dump(int fd)335 void device_debug_iot_config_dump(int fd) {
336 dprintf(fd, "\nBluetooth Iot Config:\n");
337
338 dprintf(fd, " Config Source: ");
339 switch (device_iot_config_source) {
340 case NOT_LOADED:
341 dprintf(fd, "Not loaded\n");
342 break;
343 case ORIGINAL:
344 dprintf(fd, "Original file\n");
345 break;
346 case BACKUP:
347 dprintf(fd, "Backup file\n");
348 break;
349 case NEW_FILE:
350 dprintf(fd, "New file\n");
351 break;
352 case RESET:
353 dprintf(fd, "Reset file\n");
354 break;
355 }
356
357 dprintf(fd, " Devices loaded: %d\n", device_iot_config_devices_loaded);
358 dprintf(fd, " File created/tagged: %s\n", device_iot_config_time_created);
359 }
360