1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "json_payload.h"
17 #include <securec.h>
18
19 #include "cJSON.h"
20 #ifndef DFINDER_USE_MINI_NSTACKX
21 #include "coap_client.h"
22 #endif /* END OF DFINDER_USE_MINI_NSTACKX */
23 #include "nstackx_dfinder_log.h"
24 #include "nstackx_dfinder_mgt_msg_log.h"
25 #include "nstackx_error.h"
26 #include "nstackx_device.h"
27 #include "nstackx_statistics.h"
28
29 #define TAG "nStackXCoAP"
30
AddDeviceJsonData(cJSON * data,const DeviceInfo * deviceInfo)31 static int32_t AddDeviceJsonData(cJSON *data, const DeviceInfo *deviceInfo)
32 {
33 cJSON *item;
34
35 item = cJSON_CreateString(deviceInfo->deviceId);
36 if (item == NULL || !cJSON_AddItemToObject(data, JSON_DEVICE_ID, item)) {
37 cJSON_Delete(item);
38 return NSTACKX_EFAILED;
39 }
40
41 item = cJSON_CreateString(deviceInfo->deviceName);
42 if (item == NULL || !cJSON_AddItemToObject(data, JSON_DEVICE_NAME, item)) {
43 cJSON_Delete(item);
44 return NSTACKX_EFAILED;
45 }
46
47 item = cJSON_CreateNumber(deviceInfo->deviceType);
48 if (item == NULL || !cJSON_AddItemToObject(data, JSON_DEVICE_TYPE, item)) {
49 cJSON_Delete(item);
50 return NSTACKX_EFAILED;
51 }
52
53 item = cJSON_CreateString(deviceInfo->version);
54 if (item == NULL || !cJSON_AddItemToObject(data, JSON_HICOM_VERSION, item)) {
55 cJSON_Delete(item);
56 return NSTACKX_EFAILED;
57 }
58
59 item = cJSON_CreateNumber(deviceInfo->mode);
60 if (item == NULL || !cJSON_AddItemToObject(data, JSON_REQUEST_MODE, item)) {
61 cJSON_Delete(item);
62 return NSTACKX_EFAILED;
63 }
64
65 item = cJSON_CreateString(deviceInfo->deviceHash);
66 if (item == NULL || !cJSON_AddItemToObject(data, JSON_DEVICE_HASH, item)) {
67 cJSON_Delete(item);
68 return NSTACKX_EFAILED;
69 }
70
71 item = cJSON_CreateString(deviceInfo->serviceData);
72 if (item == NULL || !cJSON_AddItemToObject(data, JSON_SERVICE_DATA, item)) {
73 cJSON_Delete(item);
74 DFINDER_LOGE(TAG, "cJSON_CreateString for serviceData failed");
75 return NSTACKX_EFAILED;
76 }
77
78 #ifndef DFINDER_USE_MINI_NSTACKX
79 item = cJSON_CreateString(deviceInfo->extendServiceData);
80 if (item == NULL || !cJSON_AddItemToObject(data, JSON_EXTEND_SERVICE_DATA, item)) {
81 cJSON_Delete(item);
82 DFINDER_LOGE(TAG, "cJSON_CreateString for extendServiceData failed");
83 return NSTACKX_EFAILED;
84 }
85 #endif /* END OF DFINDER_USE_MINI_NSTACKX */
86
87 return NSTACKX_EOK;
88 }
89
90 #ifdef DFINDER_SUPPORT_MULTI_NIF
AddApJsonDataWithIdx(cJSON * data,uint8_t idx)91 static int32_t AddApJsonDataWithIdx(cJSON *data, uint8_t idx)
92 {
93 cJSON *item = NULL;
94 char ipString[INET_ADDRSTRLEN] = {0};
95
96 if (GetLocalIpStringWithIdx(ipString, sizeof(ipString), idx) != NSTACKX_EOK) {
97 DFINDER_LOGE(TAG, "get local ip string failed with idx-%hhu", idx);
98 return NSTACKX_EFAILED;
99 }
100
101 item = cJSON_CreateString(ipString);
102 if (item == NULL || !cJSON_AddItemToObject(data, JSON_DEVICE_WLAN_IP, item)) {
103 DFINDER_LOGE(TAG, "cjson create ip string failed");
104 cJSON_Delete(item);
105 return NSTACKX_EFAILED;
106 }
107
108 return NSTACKX_EOK;
109 }
110 #else
AddWifiApJsonData(cJSON * data)111 static int32_t AddWifiApJsonData(cJSON *data)
112 {
113 cJSON *item = NULL;
114 char ipString[INET_ADDRSTRLEN] = {0};
115
116 if (GetLocalIpString(ipString, sizeof(ipString)) != NSTACKX_EOK) {
117 return NSTACKX_EFAILED;
118 }
119
120 item = cJSON_CreateString(ipString);
121 if (item == NULL || !cJSON_AddItemToObject(data, JSON_DEVICE_WLAN_IP, item)) {
122 cJSON_Delete(item);
123 return NSTACKX_EFAILED;
124 }
125
126 return NSTACKX_EOK;
127 }
128 #endif
129
AddCapabilityBitmap(cJSON * data,const DeviceInfo * deviceInfo)130 static int32_t AddCapabilityBitmap(cJSON *data, const DeviceInfo *deviceInfo)
131 {
132 cJSON *capabilityArray = NULL;
133 cJSON *capability = NULL;
134 uint32_t i;
135
136 if (deviceInfo->capabilityBitmapNum == 0) {
137 return NSTACKX_EOK;
138 }
139
140 capabilityArray = cJSON_CreateArray();
141 if (capabilityArray == NULL) {
142 goto L_END_JSON;
143 }
144
145 for (i = 0; i < deviceInfo->capabilityBitmapNum; i++) {
146 capability = cJSON_CreateNumber(deviceInfo->capabilityBitmap[i]);
147 if (capability == NULL || !cJSON_AddItemToArray(capabilityArray, capability)) {
148 cJSON_Delete(capability);
149 goto L_END_JSON;
150 }
151 }
152 if (!cJSON_AddItemToObject(data, JSON_CAPABILITY_BITMAP, capabilityArray)) {
153 goto L_END_JSON;
154 }
155
156 return NSTACKX_EOK;
157
158 L_END_JSON:
159 cJSON_Delete(capabilityArray);
160 return NSTACKX_EFAILED;
161 }
162
AddBusinessJsonData(cJSON * data,const DeviceInfo * deviceInfo,uint8_t isBroadcast)163 static int32_t AddBusinessJsonData(cJSON *data, const DeviceInfo *deviceInfo, uint8_t isBroadcast)
164 {
165 cJSON *item = NULL;
166
167 item = cJSON_CreateNumber(deviceInfo->businessType);
168 if (item == NULL || !cJSON_AddItemToObject(data, JSON_BUSINESS_TYPE, item)) {
169 cJSON_Delete(item);
170 DFINDER_LOGE(TAG, "cJSON_CreateString for businessType failed");
171 return NSTACKX_EFAILED;
172 }
173 if (isBroadcast) {
174 item = cJSON_CreateString(deviceInfo->businessData.businessDataBroadcast);
175 } else {
176 item = cJSON_CreateString(deviceInfo->businessData.businessDataUnicast);
177 }
178 if (item == NULL || !cJSON_AddItemToObject(data, JSON_BUSINESS_DATA, item)) {
179 cJSON_Delete(item);
180 DFINDER_LOGE(TAG, "cJSON_CreateString for businessData failed");
181 return NSTACKX_EFAILED;
182 }
183
184 return NSTACKX_EOK;
185 }
186
ParseDeviceJsonData(const cJSON * data,DeviceInfo * dev)187 static int32_t ParseDeviceJsonData(const cJSON *data, DeviceInfo *dev)
188 {
189 cJSON *item = NULL;
190
191 item = cJSON_GetObjectItemCaseSensitive(data, JSON_DEVICE_ID);
192 if (!cJSON_IsString(item) || !strlen(item->valuestring)) {
193 DFINDER_LOGE(TAG, "Cannot find device ID or invalid device ID");
194 return NSTACKX_EINVAL;
195 }
196 if (strcpy_s(dev->deviceId, sizeof(dev->deviceId), item->valuestring) != EOK) {
197 return NSTACKX_EFAILED;
198 }
199
200 item = cJSON_GetObjectItemCaseSensitive(data, JSON_DEVICE_NAME);
201 if (!cJSON_IsString(item) || !strlen(item->valuestring)) {
202 DFINDER_LOGE(TAG, "Cannot find device name or invalid device name");
203 return NSTACKX_EINVAL;
204 }
205 if (strcpy_s(dev->deviceName, sizeof(dev->deviceName), item->valuestring) != EOK) {
206 return NSTACKX_EFAILED;
207 }
208
209 item = cJSON_GetObjectItemCaseSensitive(data, JSON_DEVICE_TYPE);
210 if (!cJSON_IsNumber(item) || (item->valuedouble < 0) || (item->valuedouble > 0xFF)) {
211 DFINDER_LOGE(TAG, "Cannot find device type or invalid device type");
212 return NSTACKX_EINVAL;
213 }
214 dev->deviceType = (uint8_t)item->valuedouble;
215
216 item = cJSON_GetObjectItemCaseSensitive(data, JSON_HICOM_VERSION);
217 if (!cJSON_IsString(item) || !strlen(item->valuestring)) {
218 DFINDER_LOGW(TAG, "Can't find hicom version");
219 return NSTACKX_EOK;
220 }
221 if (strcpy_s(dev->version, sizeof(dev->version), item->valuestring) != EOK) {
222 return NSTACKX_EFAILED;
223 }
224
225 return NSTACKX_EOK;
226 }
227
ParseWifiApJsonData(const cJSON * data,DeviceInfo * dev)228 static void ParseWifiApJsonData(const cJSON *data, DeviceInfo *dev)
229 {
230 cJSON *item = NULL;
231
232 item = cJSON_GetObjectItemCaseSensitive(data, JSON_DEVICE_WLAN_IP);
233 if (cJSON_IsString(item)) {
234 if (inet_pton(AF_INET, item->valuestring, &(dev->netChannelInfo.wifiApInfo.ip)) != 1) {
235 DFINDER_LOGW(TAG, "Invalid ip address");
236 } else {
237 dev->netChannelInfo.wifiApInfo.state = NET_CHANNEL_STATE_CONNETED;
238 }
239 }
240 }
241
ParseModeJsonData(const cJSON * data,DeviceInfo * dev)242 static void ParseModeJsonData(const cJSON *data, DeviceInfo *dev)
243 {
244 cJSON *item = NULL;
245 item = cJSON_GetObjectItemCaseSensitive(data, JSON_REQUEST_MODE);
246 if (item == NULL) {
247 DFINDER_LOGE(TAG, "Cannot get mode json");
248 return;
249 }
250 if (!cJSON_IsNumber(item) || (item->valuedouble < 0)) {
251 DFINDER_LOGE(TAG, "Cannot find mode or invalid mode");
252 } else {
253 if (dev == NULL) {
254 DFINDER_LOGE(TAG, "device info is null");
255 return;
256 }
257 dev->mode = (uint8_t)item->valuedouble;
258 }
259 }
260
ParseDeviceHashData(const cJSON * data,DeviceInfo * dev)261 static void ParseDeviceHashData(const cJSON *data, DeviceInfo *dev)
262 {
263 cJSON *item = NULL;
264 item = cJSON_GetObjectItemCaseSensitive(data, JSON_DEVICE_HASH);
265 if (item == NULL) {
266 DFINDER_LOGD(TAG, "Cannot get hash json");
267 return;
268 }
269 if (item->valuestring == NULL) {
270 DFINDER_LOGD(TAG, "Cannot get valuestring");
271 return;
272 }
273 if (!cJSON_IsString(item) || !strlen(item->valuestring)) {
274 DFINDER_LOGD(TAG, "Cannot find device hash or invalid hash");
275 return;
276 }
277 if (strcpy_s(dev->deviceHash, sizeof(dev->deviceHash), item->valuestring) != EOK) {
278 DFINDER_LOGE(TAG, "parse device hash data error");
279 return;
280 }
281 }
282
ParseServiceDataJsonData(const cJSON * data,DeviceInfo * dev)283 static void ParseServiceDataJsonData(const cJSON *data, DeviceInfo *dev)
284 {
285 cJSON *item = NULL;
286 item = cJSON_GetObjectItemCaseSensitive(data, JSON_SERVICE_DATA);
287 if (item == NULL) {
288 DFINDER_LOGE(TAG, "Cannot get service data");
289 return;
290 }
291 if (!cJSON_IsString(item)) {
292 DFINDER_LOGE(TAG, "Cannot find serviceData");
293 return;
294 }
295 if (item->valuestring == NULL) {
296 DFINDER_LOGE(TAG, "item->valuestring is null");
297 return;
298 }
299 if (strcpy_s(dev->serviceData, sizeof(dev->serviceData), item->valuestring)) {
300 DFINDER_LOGE(TAG, "parse device serviceData error");
301 return;
302 }
303 }
304
305 #ifndef DFINDER_USE_MINI_NSTACKX
ParseExtendServiceDataJsonData(const cJSON * data,DeviceInfo * dev)306 static void ParseExtendServiceDataJsonData(const cJSON *data, DeviceInfo *dev)
307 {
308 cJSON *item = NULL;
309 item = cJSON_GetObjectItemCaseSensitive(data, JSON_EXTEND_SERVICE_DATA);
310 if (item == NULL) {
311 DFINDER_LOGE(TAG, "Cannot get service data");
312 return;
313 }
314 if (!cJSON_IsString(item)) {
315 DFINDER_LOGE(TAG, "Cannot find extendServiceData");
316 return;
317 }
318 if (item->valuestring == NULL) {
319 DFINDER_LOGE(TAG, "item->valuestring is null");
320 return;
321 }
322 if (strcpy_s(dev->extendServiceData, sizeof(dev->extendServiceData), item->valuestring)) {
323 DFINDER_LOGE(TAG, "parse device extendServiceData error");
324 return;
325 }
326 }
327 #endif /* END OF DFINDER_USE_MINI_NSTACKX */
328
ParseCapabilityBitmap(const cJSON * data,DeviceInfo * deviceInfo)329 static void ParseCapabilityBitmap(const cJSON *data, DeviceInfo *deviceInfo)
330 {
331 cJSON *capability = NULL;
332 cJSON *item = NULL;
333 uint32_t capabilityBitmapNum = 0;
334
335 item = cJSON_GetObjectItemCaseSensitive(data, JSON_CAPABILITY_BITMAP);
336 if (cJSON_IsArray(item)) {
337 cJSON_ArrayForEach(capability, item) {
338 if (capabilityBitmapNum >= NSTACKX_MAX_CAPABILITY_NUM) {
339 break;
340 }
341
342 if (!cJSON_IsNumber(capability) ||
343 capability->valuedouble < 0 ||
344 capability->valuedouble > 0xFFFFFFFF) {
345 /* skip invalid capability */
346 continue;
347 }
348 deviceInfo->capabilityBitmap[capabilityBitmapNum++] = (uint32_t)capability->valuedouble;
349 }
350 }
351 deviceInfo->capabilityBitmapNum = capabilityBitmapNum;
352 }
353
ParseBusinessType(const cJSON * data,DeviceInfo * dev)354 static void ParseBusinessType(const cJSON *data, DeviceInfo *dev)
355 {
356 cJSON *item = NULL;
357 item = cJSON_GetObjectItemCaseSensitive(data, JSON_BUSINESS_TYPE);
358 if (item == NULL) {
359 dev->businessType = NSTACKX_BUSINESS_TYPE_NULL;
360 DFINDER_LOGW(TAG, "Cannot get businessType json");
361 return;
362 }
363 if (!cJSON_IsNumber(item) || (item->valuedouble < 0)) {
364 dev->businessType = NSTACKX_BUSINESS_TYPE_NULL;
365 DFINDER_LOGE(TAG, "Cannot find businessType or invalid Type");
366 } else {
367 dev->businessType = (uint8_t)item->valuedouble;
368 }
369 }
370
ParseBusinessDataJsonData(const cJSON * data,DeviceInfo * dev,uint8_t isBroadcast)371 static void ParseBusinessDataJsonData(const cJSON *data, DeviceInfo *dev, uint8_t isBroadcast)
372 {
373 cJSON *item = NULL;
374 item = cJSON_GetObjectItemCaseSensitive(data, JSON_BUSINESS_DATA);
375 if (item == NULL) {
376 DFINDER_LOGE(TAG, "Cannot get businessData json");
377 return;
378 }
379 if (!cJSON_IsString(item)) {
380 DFINDER_LOGE(TAG, "Cannot find businessData");
381 return;
382 }
383 if (isBroadcast == NSTACKX_TRUE) {
384 if (strcpy_s(dev->businessData.businessDataBroadcast,
385 sizeof(dev->businessData.businessDataBroadcast), item->valuestring)) {
386 DFINDER_LOGE(TAG, "parse device businessData error");
387 return;
388 }
389 } else {
390 if (strcpy_s(dev->businessData.businessDataUnicast,
391 sizeof(dev->businessData.businessDataUnicast), item->valuestring)) {
392 DFINDER_LOGE(TAG, "parse device businessData error");
393 return;
394 }
395 }
396 }
397
398 /*
399 * Service Discover JSON format
400 * {
401 * "deviceId":[device ID, string],
402 * "deviceName":[device name, string],
403 * "type": [device type, number],
404 * "version":[hicom version, string],
405 * "wlanIp":[WLAN IP address, string],
406 * "capabilityBitmap":[bitmap, bitmap, bitmap, ...]
407 * "coapUri":[coap uri for discover, string] <-- optional. When present, means it's broadcast request.
408 * }
409 */
410 #ifdef DFINDER_SUPPORT_MULTI_NIF
PrepareServiceDiscoverWithIdxEx(uint8_t isBroadcast,uint32_t idx)411 static char *PrepareServiceDiscoverWithIdxEx(uint8_t isBroadcast, uint32_t idx)
412 #else
413 static char *PrepareServiceDiscoverEx(uint8_t isBroadcast)
414 #endif /* #ifdef DFINDER_SUPPORT_MULTI_NIF */
415 {
416 char coapUriBuffer[NSTACKX_MAX_URI_BUFFER_LENGTH] = {0};
417 char host[NSTACKX_MAX_IP_STRING_LEN] = {0};
418 char *formatString = NULL;
419 const DeviceInfo *deviceInfo = GetLocalDeviceInfoPtr();
420 cJSON *data = NULL;
421 cJSON *localCoapString = NULL;
422
423 data = cJSON_CreateObject();
424 if (data == NULL) {
425 goto L_END_JSON;
426 }
427
428 /* Prepare local device info */
429 if ((AddDeviceJsonData(data, deviceInfo) != NSTACKX_EOK) ||
430 #ifdef DFINDER_SUPPORT_MULTI_NIF
431 (AddApJsonDataWithIdx(data, idx) != NSTACKX_EOK) ||
432 #else
433 (AddWifiApJsonData(data) != NSTACKX_EOK) ||
434 #endif
435 (AddCapabilityBitmap(data, deviceInfo) != NSTACKX_EOK) ||
436 (AddBusinessJsonData(data, deviceInfo, isBroadcast) != NSTACKX_EOK)) {
437 DFINDER_LOGE(TAG, "Add json data failed");
438 goto L_END_JSON;
439 }
440
441 if (isBroadcast) {
442 #ifdef DFINDER_SUPPORT_MULTI_NIF
443 if (GetLocalIpStringWithIdx(host, sizeof(host), idx) != NSTACKX_EOK) {
444 #else
445 if (GetLocalIpString(host, sizeof(host)) != NSTACKX_EOK) {
446 #endif
447 DFINDER_LOGE(TAG, "GetLocalIpStringWithIdx failed");
448 goto L_END_JSON;
449 }
450 if (sprintf_s(coapUriBuffer, sizeof(coapUriBuffer), "coap://%s/" COAP_DEVICE_DISCOVER_URI, host) < 0) {
451 DFINDER_LOGE(TAG, "deal coap url failed");
452 goto L_END_JSON;
453 }
454 localCoapString = cJSON_CreateString(coapUriBuffer);
455 if (localCoapString == NULL || !cJSON_AddItemToObject(data, JSON_COAP_URI, localCoapString)) {
456 cJSON_Delete(localCoapString);
457 DFINDER_LOGE(TAG, "local coap string failed");
458 goto L_END_JSON;
459 }
460 }
461
462 formatString = cJSON_PrintUnformatted(data);
463 if (formatString == NULL) {
464 DFINDER_LOGE(TAG, "cJSON_PrintUnformatted failed");
465 }
466
467 L_END_JSON:
468 cJSON_Delete(data);
469 return formatString;
470 }
471
472 #ifdef DFINDER_SUPPORT_MULTI_NIF
473 char *PrepareServiceDiscoverWithIdx(uint8_t isBroadcast, uint32_t idx)
474 {
475 char *str = PrepareServiceDiscoverWithIdxEx(isBroadcast, idx);
476 if (str == NULL) {
477 IncStatistics(STATS_PREPARE_SD_MSG_FAILED);
478 }
479 return str;
480 }
481 #else
482 char *PrepareServiceDiscover(uint8_t isBroadcast)
483 {
484 char *str = PrepareServiceDiscoverEx(isBroadcast);
485 if (str == NULL) {
486 IncStatistics(STATS_PREPARE_SD_MSG_FAILED);
487 }
488 return str;
489 }
490 #endif
491
492 static int32_t ParseServiceDiscoverEx(const uint8_t *buf, DeviceInfo *deviceInfo, char **remoteUrlPtr)
493 {
494 char *remoteUrl = NULL;
495 cJSON *data = NULL;
496 cJSON *item = NULL;
497 uint8_t isBroadcast = NSTACKX_FALSE;
498
499 if (buf == NULL || deviceInfo == NULL || remoteUrlPtr == NULL) {
500 return NSTACKX_EINVAL;
501 }
502
503 data = cJSON_Parse((char *)buf);
504 if (data == NULL) {
505 return NSTACKX_EINVAL;
506 }
507
508 if (ParseDeviceJsonData(data, deviceInfo) != NSTACKX_EOK) {
509 cJSON_Delete(data);
510 return NSTACKX_EINVAL;
511 }
512
513 ParseWifiApJsonData(data, deviceInfo);
514 ParseCapabilityBitmap(data, deviceInfo);
515 ParseModeJsonData(data, deviceInfo);
516 ParseDeviceHashData(data, deviceInfo);
517 ParseServiceDataJsonData(data, deviceInfo);
518 #ifndef DFINDER_USE_MINI_NSTACKX
519 ParseExtendServiceDataJsonData(data, deviceInfo);
520 #endif /* END OF DFINDER_USE_MINI_NSTACKX */
521 ParseBusinessType(data, deviceInfo);
522
523 item = cJSON_GetObjectItemCaseSensitive(data, JSON_COAP_URI);
524 if (item != NULL) {
525 isBroadcast = NSTACKX_TRUE;
526 if (cJSON_IsString(item)) {
527 DFINDER_LOGD(TAG, "new device join");
528 remoteUrl = strdup(item->valuestring);
529 if (remoteUrl == NULL) {
530 DFINDER_LOGE(TAG, "remoteUrl strdup fail");
531 cJSON_Delete(data);
532 return NSTACKX_ENOMEM;
533 }
534 }
535 }
536 ParseBusinessDataJsonData(data, deviceInfo, isBroadcast);
537 deviceInfo->businessData.isBroadcast = isBroadcast;
538 *remoteUrlPtr = remoteUrl;
539 cJSON_Delete(data);
540 DFINDER_MGT_UNPACK_LOG(deviceInfo);
541 return NSTACKX_EOK;
542 }
543
544 int32_t ParseServiceDiscover(const uint8_t *buf, DeviceInfo *deviceInfo, char **remoteUrlPtr)
545 {
546 int32_t ret = ParseServiceDiscoverEx(buf, deviceInfo, remoteUrlPtr);
547 if (ret != NSTACKX_EOK) {
548 IncStatistics(STATS_PARSE_SD_MSG_FAILED);
549 }
550 return ret;
551 }
552