1 /*
2 * Copyright (C) 2015-2021 Alibaba Group Holding Limited
3 */
4
5 #include <string.h>
6 #include <cJSON.h>
7 #include <stdlib.h>
8 #include "ota_log.h"
9 #include "ota_hal.h"
10 #include "ota_import.h"
11 #include "ota_hal_os.h"
12 #include "ota_hal_trans.h"
13 #include "ota_agent.h"
14 #include "aiot_mqtt_api.h"
15 /**
16 * ota_sevice_parse_msg OTA parse download info from cloud
17 *
18 * @param[in] ota_service_t *ctx service manager.
19 * char *json transport message from Cloud.
20 *
21 * @return OTA_TRANSPORT_FAIL transport errno.
22 */
ota_sevice_parse_msg(ota_service_t * ctx,const char * json)23 int ota_sevice_parse_msg(ota_service_t *ctx, const char *json)
24 {
25 int ret = 0;
26 int is_get_module = 0;
27 cJSON *root = NULL;
28 ota_boot_param_t ota_param = {0};
29 root = cJSON_Parse(json);
30 if (NULL == root || NULL == ctx) {
31 ret = OTA_TRANSPORT_PAR_FAIL;
32 OTA_LOG_E("parse msg param is null");
33 return ret;
34 } else {
35 /* recover the process type */
36 cJSON *cmd = cJSON_GetObjectItem(root, "cmd");
37 if (NULL == cmd) {
38 ctx->ota_process = OTA_PROCESS_NORMAL;
39 }
40 cJSON *message = cJSON_GetObjectItem(root, "message");
41 if (NULL == message) {
42 ret = OTA_MESSAGE_PAR_FAIL;
43 goto EXIT;
44 }
45 if ((strncmp(message->valuestring, "success", strlen("success")))) {
46 ret = OTA_SUCCESS_PAR_FAIL;
47 goto EXIT;
48 }
49 cJSON *json_obj = cJSON_GetObjectItem(root, "data");
50 if (NULL == json_obj) {
51 ret = OTA_DATA_PAR_FAIL;
52 goto EXIT;
53 }
54 cJSON *url = cJSON_GetObjectItem(json_obj, "url");
55 if (NULL == url) {
56 ret = OTA_URL_PAR_FAIL;
57 goto EXIT;
58 }
59 strncpy(ota_param.url, url->valuestring, OTA_URL_LEN - 1);
60 ota_param.url[sizeof(ota_param.url) - 1] = 0;
61 cJSON *submodule = cJSON_GetObjectItem(json_obj, "module");
62 if (NULL != submodule) {
63 is_get_module = 1;
64 strncpy(ctx->module_name, submodule->valuestring, sizeof(ctx->module_name) - 1);
65 OTA_LOG_I("submode = %s\r\n", submodule->valuestring);
66 }
67 cJSON *version = cJSON_GetObjectItem(json_obj, "version");
68 if (NULL == version) {
69 ret = OTA_VER_PAR_FAIL;
70 goto EXIT;
71 }
72 strncpy(ota_param.ver, version->valuestring, sizeof(ota_param.ver));
73 ota_param.ver[sizeof(ota_param.ver) - 1] = 0;
74 cJSON *signMethod = cJSON_GetObjectItem(json_obj, "signMethod");
75 if (signMethod != NULL) {
76 memset(ota_param.hash, 0x00, OTA_HASH_LEN);
77 ret = ota_to_capital(signMethod->valuestring, strlen(signMethod->valuestring));
78 if (ret != 0) {
79 ret = OTA_VER_PAR_FAIL;
80 goto EXIT;
81 }
82 if (0 == strncmp(signMethod->valuestring, "MD5", strlen("MD5"))) {
83 cJSON *md5 = cJSON_GetObjectItem(json_obj, "sign");
84 if (NULL == md5) {
85 ret = OTA_MD5_PAR_FAIL;
86 goto EXIT;
87 }
88 ota_param.hash_type = OTA_MD5;
89 strncpy(ota_param.hash, md5->valuestring, OTA_HASH_LEN - 1);
90 ret = ota_to_capital(ota_param.hash, strlen(ota_param.hash));
91 if (ret != 0) {
92 ret = OTA_VER_PAR_FAIL;
93 goto EXIT;
94 }
95 } else if (0 == strncmp(signMethod->valuestring, "SHA256", strlen("SHA256"))) {
96 cJSON *sha256 = cJSON_GetObjectItem(json_obj, "sign");
97 if (NULL == sha256) {
98 ret = OTA_SHA256_PAR_FAIL;
99 goto EXIT;
100 }
101 ota_param.hash_type = OTA_SHA256;
102 strncpy(ota_param.hash, sha256->valuestring, OTA_HASH_LEN - 1);
103 ret = ota_to_capital(ota_param.hash, strlen(ota_param.hash));
104 if (ret != 0) {
105 ret = OTA_VER_PAR_FAIL;
106 goto EXIT;
107 }
108 } else {
109 ret = OTA_HASH_PAR_FAIL;
110 goto EXIT;
111 }
112 } else { /* old protocol*/
113 memset(ota_param.hash, 0x00, OTA_HASH_LEN);
114 cJSON *md5 = cJSON_GetObjectItem(json_obj, "md5");
115 if (NULL == md5) {
116 ret = OTA_MD5_PAR_FAIL;
117 goto EXIT;
118 }
119 ota_param.hash_type = OTA_MD5;
120 strncpy(ota_param.hash, md5->valuestring, OTA_HASH_LEN - 1);
121 ret = ota_to_capital(ota_param.hash, strlen(ota_param.hash));
122 if (ret != 0) {
123 ret = OTA_VER_PAR_FAIL;
124 goto EXIT;
125 }
126 }
127 cJSON *size = cJSON_GetObjectItem(json_obj, "size");
128 if (NULL == size) {
129 ret = OTA_SIZE_PAR_FAIL;
130 goto EXIT;
131 }
132 ota_param.len = size->valueint;
133 cJSON *digestSign = cJSON_GetObjectItem(json_obj, "digestsign");
134 if (digestSign != NULL) {
135 unsigned int sign_len = OTA_SIGN_LEN;
136 memset(ota_param.sign, 0x00, OTA_SIGN_LEN);
137 if (ota_base64_decode((const unsigned char *)digestSign->valuestring, strlen(digestSign->valuestring), (unsigned char*)ota_param.sign, &sign_len) != 0) {
138 ret = OTA_SIGN_PAR_FAIL;
139 goto EXIT;
140 }
141 }
142 }
143
144 EXIT:
145 if (root != NULL) {
146 cJSON_Delete(root);
147 root = NULL;
148 }
149 OTA_LOG_I("Parse ota version:%s url:%s ret:%d\n", ota_param.ver, ota_param.url, ret);
150 if (ret < 0) {
151 ret = OTA_TRANSPORT_PAR_FAIL;
152 if (ctx->report_func.report_status_cb != NULL) {
153 ctx->report_func.report_status_cb(ctx->report_func.param, ret);
154 }
155 } else {
156 if (ctx->report_func.report_status_cb != NULL) {
157 ctx->report_func.report_status_cb(ctx->report_func.param, 1);
158 }
159 ota_param.upg_flag = 0x00;
160 if (ctx->dev_type == 0) {
161 if (is_get_module == 0) {
162 strncpy(ctx->module_name, "default", 7);
163 }
164 }
165 OTA_LOG_I("upg_flag = %04x", ota_param.upg_flag);
166 ota_param.upg_status = OTA_TRANSPORT;
167 ret = ota_update_parameter(&ota_param);
168 if (ret != 0) {
169 OTA_LOG_I("ota param err.\n");
170 if (ctx->report_func.report_status_cb != NULL) {
171 ctx->report_func.report_status_cb(ctx->report_func.param, OTA_TRANSPORT_PAR_FAIL);
172 }
173 }
174 if (ctx->ota_triggered_func.triggered_ota_cb != NULL) {
175 ctx->ota_triggered_func.triggered_ota_cb(ctx, ota_param.ver, ctx->module_name, ctx->ota_triggered_func.param);
176 }
177 }
178 return ret;
179 }
180
181 /**
182 * ota_mqtt_publish message to Cloud
183 *
184 * @param[in] mqtt_client mqtt client ptr
185 * @param[in] name topic name
186 * @param[in] msg message content
187 * @param[in] pk product key
188 * @param[in] dn device name
189 *
190 * @return OTA_SUCCESS OTA success.
191 * @return OTA_TRANSPORT_INT_FAIL OTA transport init fail.
192 * @return OTA_TRANSPORT_PAR_FAIL OTA transport parse fail.
193 * @return OTA_TRANSPORT_VER_FAIL OTA transport verion is too old.
194 */
ota_mqtt_publish(void * mqtt_client,const char * name,char * msg,char * pk,char * dn)195 static int ota_mqtt_publish(void *mqtt_client, const char *name, char *msg, char *pk, char *dn)
196 {
197 int ret = 0;
198 char topic[OTA_MSG_LEN] = {0};
199 if (name == NULL || msg == NULL || pk == NULL || dn == NULL) {
200 return OTA_TRANSPORT_INT_FAIL;
201 }
202 ret = ota_snprintf(topic, OTA_MSG_LEN - 1, "/ota/device/%s/%s/%s", name, pk, dn);
203 if (ret < 0) {
204 return OTA_TRANSPORT_INT_FAIL;
205 }
206 OTA_LOG_I("Public topic:%s msg:%s", topic, msg);
207 ret = ota_hal_mqtt_publish(mqtt_client, topic, 1, (void *)msg, strlen(msg) + 1);
208 if (ret < 0) {
209 return OTA_TRANSPORT_INT_FAIL;
210 }
211 return ret;
212 }
213
214 /**
215 * ota_mqtt_sub_cb upgrade callback
216 *
217 * @param[in] pctx ota context
218 * @param[in] pclient mqtt pclient
219 * @param[in] msg mqtt message
220 *
221 * @return void
222 */
ota_mqtt_sub_cb(void * mqtt_client,void * msg,void * pctx)223 static void ota_mqtt_sub_cb(void *mqtt_client, void *msg, void *pctx)
224 {
225 char *payload = NULL;
226 ota_service_t *ctx = (ota_service_t *)pctx;
227 aiot_mqtt_recv_t *mqtt_msg = (aiot_mqtt_recv_t *)msg;
228 if ((msg == NULL) && (ctx == NULL)) {
229 OTA_LOG_E("mqtt sub param err!");
230 return;
231 }
232 if (mqtt_msg->type == AIOT_MQTTRECV_PUB) {
233 payload = (char *)mqtt_msg->data.pub.payload;
234 OTA_LOG_I("pub, qos: %d, topic: %.*s\n", mqtt_msg->data.pub.qos, mqtt_msg->data.pub.topic_len, mqtt_msg->data.pub.topic);
235 if (payload != NULL) {
236 OTA_LOG_I("mqtt cb evt:%d %s", mqtt_msg->type, payload);
237 ota_sevice_parse_msg(ctx, payload);
238 }
239 } else {
240 OTA_LOG_I("mqtt type = %d", mqtt_msg->type);
241 payload = (char *)mqtt_msg->data.pub.payload;
242 // OTA_LOG_I("pub, qos: %d, topic: %.*s\n", mqtt_msg->data.pub.qos, mqtt_msg->data.pub.topic_len, mqtt_msg->data.pub.topic);
243 OTA_LOG_E("mqtt receive err msg type!");
244 }
245 }
246
247 /**
248 * ota_transport_inform OTA inform version to cloud.
249 *
250 * @param[in] void *mqttclient mqtt client ptr
251 * @param[in] char *pk product key value
252 * @param[in] char *dn device name
253 * @param[in] char *module_name want to report module name, when module_name == NULL, report default module ver
254 * @param[in] char *ver version string
255 *
256 * @return OTA_SUCCESS OTA success.
257 * @return OTA_TRANSPORT_INT_FAIL OTA transport init fail.
258 * @return OTA_TRANSPORT_PAR_FAIL OTA transport parse fail.
259 * @return OTA_TRANSPORT_VER_FAIL OTA transport verion is too old.
260 */
ota_transport_inform(void * mqttclient,char * pk,char * dn,char * module_name,char * ver)261 int ota_transport_inform(void *mqttclient, char *pk, char *dn, char *module_name, char *ver)
262 {
263 int ret = 0;
264 char msg[OTA_MSG_LEN] = {0};
265 if ((mqttclient == NULL) || (ver == NULL) || (pk == NULL) ||
266 (dn == NULL) || (module_name == NULL)) {
267 OTA_LOG_E("inform version input param err!");
268 goto OTA_TRANS_INFOR_OVER;
269 }
270 if (strncmp(module_name, "default", strlen("default")) == 0) {
271 ret = ota_snprintf(msg, OTA_MSG_LEN - 1, "{\"id\":%d,\"params\":{\"version\":\"%s\"}}", 0, ver);
272 } else {
273 ret = ota_snprintf(msg, OTA_MSG_LEN - 1, "{\"id\":%d,\"params\":{\"version\":\"%s\",\"module\":\"%s\"}}", 0, ver, module_name);
274 }
275 if (ret < 0) {
276 OTA_LOG_E("inform version pack msg err!");
277 goto OTA_TRANS_INFOR_OVER;
278 }
279 ret = ota_mqtt_publish(mqttclient, "inform", msg, pk, dn);
280 OTA_TRANS_INFOR_OVER:
281 if (ret < 0) {
282 OTA_LOG_E("inform version failed!");
283 }
284 return ret;
285 }
286
ota_transport_inform_otaver(ota_service_t * ctx)287 int ota_transport_inform_otaver(ota_service_t *ctx)
288 {
289 int ret = 0;
290 char topic[OTA_MSG_LEN] = {0};
291 char msg[OTA_MSG_LEN] = {0};
292 char keyver[20] = "SYS_OTA_ID";
293 char attver[64] = {0};
294 if (ctx == NULL) {
295 return OTA_TRANSPORT_PAR_FAIL;
296 }
297 ret = ota_snprintf(topic, OTA_MSG_LEN - 1, "/sys/%s/%s/thing/deviceinfo/update", ctx->pk, ctx->dn);
298 if (ret < 0) {
299 return OTA_TRANSPORT_PAR_FAIL;
300 }
301 ret = ota_snprintf(attver, sizeof(attver) - 1, "HOTA-%s-%s-%s-%s", OTA_VERSION, OTA_TRANSTYPE, OTA_OS_TYPE, OTA_BOARD_TYPE);
302 if (ret < 0) {
303 return OTA_TRANSPORT_PAR_FAIL;
304 }
305 OTA_LOG_I("Public topic:%s", topic);
306 ret = ota_snprintf(msg, OTA_MSG_LEN - 1, "{\"id\":\"%d\",\"version\":\"1.0\",\"params\":[{\"attrKey\":\"%s\",\"attrValue\":\"%s\"}],\"method\":\"thing.deviceinfo.update\"}",
307 0, keyver, attver);
308 if (ret < 0) {
309 return OTA_TRANSPORT_PAR_FAIL;
310 }
311 OTA_LOG_I("Public msg:%s", msg);
312 ret = ota_hal_mqtt_publish(ctx->mqtt_client, topic, 1, (void *)msg, strlen(msg) + 1);
313 if (ret < 0) {
314 return OTA_TRANSPORT_INT_FAIL;
315 }
316 return ret;
317 }
318 /**
319 * ota_transport_upgrade OTA subcribe message from Cloud.
320 *
321 * @param[in] ota_service_t *ctx ctx ota service context
322 *
323 * @return OTA_SUCCESS OTA success.
324 * @return OTA_TRANSPORT_INT_FAIL OTA transport init fail.
325 * @return OTA_TRANSPORT_PAR_FAIL OTA transport parse fail.
326 * @return OTA_TRANSPORT_VER_FAIL OTA transport verion is too old.
327 */
ota_transport_upgrade(ota_service_t * ctx)328 int ota_transport_upgrade(ota_service_t *ctx)
329 {
330 int ret = OTA_TRANSPORT_INT_FAIL;
331 char topic[OTA_MSG_LEN] = {0};
332
333 if (ctx == NULL) {
334 return ret;
335 }
336 ret = ota_snprintf(topic, OTA_MSG_LEN - 1, "/ota/device/%s/%s/%s", "upgrade", ctx->pk, ctx->dn);
337 if (ret < 0) {
338 ret = OTA_TRANSPORT_INT_FAIL;
339 } else {
340 ret = ota_hal_mqtt_subscribe(ctx->mqtt_client, topic, ota_mqtt_sub_cb, ctx);
341 }
342 return ret;
343 }
344
345 /**
346 * ota_transport_status OTA report status to Cloud
347 *
348 * @param[in] void *param param ota service context
349 * @param[in] status [1-100] percent, [<0] error no.
350 *
351 * @return OTA_SUCCESS OTA success.
352 * @return OTA_TRANSPORT_INT_FAIL OTA transport init fail.
353 * @return OTA_TRANSPORT_PAR_FAIL OTA transport parse fail.
354 * @return OTA_TRANSPORT_VER_FAIL OTA transport verion is too old.
355 */
ota_transport_status(void * param,int status)356 int ota_transport_status(void *param, int status)
357 {
358 int ret = OTA_TRANSPORT_INT_FAIL;
359 ota_service_t *ctx = NULL;
360 char msg[OTA_MSG_LEN] = {0};
361 char *err_str = "";
362 int tmp_status = 0;
363 if (param == NULL) {
364 OTA_LOG_E("report status param is null!");
365 return ret;
366 }
367 ctx = (ota_service_t *)param;
368 tmp_status = status;
369 if (status < 0) {
370 switch (status) {
371 case OTA_INIT_FAIL:
372 err_str = "OTA init failed";
373 tmp_status = OTA_REPORT_UPGRADE_ERR;
374 break;
375 case OTA_TRANSPORT_INT_FAIL:
376 err_str = "OTA transport init failed";
377 tmp_status = OTA_REPORT_UPGRADE_ERR;
378 break;
379 case OTA_TRANSPORT_VER_FAIL:
380 err_str = "OTA transport verion is too old";
381 tmp_status = OTA_REPORT_UPGRADE_ERR;
382 break;
383 case OTA_TRANSPORT_PAR_FAIL:
384 err_str = "OTA transport parse failed";
385 tmp_status = OTA_REPORT_UPGRADE_ERR;
386 break;
387 case OTA_DOWNLOAD_INIT_FAIL:
388 err_str = "OTA download init failed";
389 tmp_status = OTA_REPORT_DOWNLOAD_ERR;
390 break;
391 case OTA_DOWNLOAD_HEAD_FAIL:
392 err_str = "OTA download header failed";
393 tmp_status = OTA_REPORT_DOWNLOAD_ERR;
394 break;
395 case OTA_DOWNLOAD_CON_FAIL:
396 err_str = "OTA download connect failed";
397 tmp_status = OTA_REPORT_DOWNLOAD_ERR;
398 break;
399 case OTA_DOWNLOAD_REQ_FAIL:
400 err_str = "OTA download request failed";
401 tmp_status = OTA_REPORT_DOWNLOAD_ERR;
402 break;
403 case OTA_DOWNLOAD_RECV_FAIL:
404 err_str = "OTA download receive failed";
405 tmp_status = OTA_REPORT_DOWNLOAD_ERR;
406 break;
407 case OTA_VERIFY_MD5_FAIL:
408 err_str = "OTA verfiy MD5 failed";
409 tmp_status = OTA_REPORT_VERIFY_ERR;
410 break;
411 case OTA_VERIFY_SHA2_FAIL:
412 err_str = "OTA verfiy SHA256 failed";
413 tmp_status = OTA_REPORT_VERIFY_ERR;
414 break;
415 case OTA_VERIFY_RSA_FAIL:
416 err_str = "OTA verfiy RSA failed";
417 tmp_status = OTA_REPORT_VERIFY_ERR;
418 break;
419 case OTA_VERIFY_IMAGE_FAIL:
420 err_str = "OTA verfiy image failed";
421 tmp_status = OTA_REPORT_VERIFY_ERR;
422 break;
423 case OTA_UPGRADE_WRITE_FAIL:
424 err_str = "OTA upgrade write failed";
425 tmp_status = OTA_REPORT_BURN_ERR;
426 break;
427 case OTA_UPGRADE_FW_SIZE_FAIL:
428 err_str = "OTA upgrade FW too big";
429 tmp_status = OTA_REPORT_BURN_ERR;
430 break;
431 case OTA_CUSTOM_CALLBAK_FAIL:
432 err_str = "OTA register callback failed";
433 tmp_status = OTA_REPORT_BURN_ERR;
434 break;
435 case OTA_MCU_INIT_FAIL:
436 err_str = "OTA MCU init failed";
437 tmp_status = OTA_REPORT_BURN_ERR;
438 break;
439 case OTA_MCU_VERSION_FAIL:
440 err_str = "OTA MCU init failed";
441 tmp_status = OTA_REPORT_BURN_ERR;
442 break;
443 case OTA_MCU_NOT_READY:
444 err_str = "OTA MCU not ready";
445 tmp_status = OTA_REPORT_BURN_ERR;
446 break;
447 case OTA_MCU_REBOOT_FAIL:
448 err_str = "OTA MCU fail to reboot";
449 tmp_status = OTA_REPORT_BURN_ERR;
450 break;
451 case OTA_MCU_HEADER_FAIL:
452 err_str = "OTA MCU header error";
453 tmp_status = OTA_REPORT_BURN_ERR;
454 break;
455 case OTA_MCU_UPGRADE_FAIL:
456 err_str = "OTA MCU upgrade fail";
457 tmp_status = OTA_REPORT_BURN_ERR;
458 break;
459 case OTA_INVALID_PARAMETER:
460 err_str = "OTA invalid parameter";
461 tmp_status = OTA_REPORT_BURN_ERR;
462 break;
463 default:
464 err_str = "OTA undefined failed";
465 tmp_status = OTA_REPORT_UPGRADE_ERR;
466 break;
467 }
468 }
469 if (strncmp(ctx->module_name, "default", strlen("default")) == 0) {
470 ret = ota_snprintf(msg, OTA_MSG_LEN - 1, "{\"id\":%d,\"params\":{\"step\": \"%d\",\"desc\":\"%s\"}}", 1, tmp_status, err_str);
471 } else {
472 ret = ota_snprintf(msg, OTA_MSG_LEN - 1, "{\"id\":%d,\"params\":{\"step\": \"%d\",\"desc\":\"%s\",\"module\":\"%s\"}}", 1, tmp_status, err_str, ctx->module_name);
473 }
474 if (ret < 0) {
475 return OTA_TRANSPORT_INT_FAIL;
476 }
477 ret = ota_mqtt_publish(ctx->mqtt_client, "progress", msg, ctx->pk, ctx->dn);
478 if (ret < 0) {
479 OTA_LOG_E("report status failed!");
480 return OTA_TRANSPORT_INT_FAIL;
481 }
482 return ret;
483 }
484
485