更新硬件SDK

This commit is contained in:
kerwincui
2023-03-04 03:44:56 +08:00
parent dcdf6e1b7c
commit e39d3d2f03
1900 changed files with 663153 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
Name: 固件升级模块
OTA Component for Link SDK V4.0.0

View File

@@ -0,0 +1,650 @@
/**
* @file aiot_mqtt_download_api.c
* @brief mqtt文件下载的实现文件
* @date 2019-12-27
*
* @copyright Copyright (C) 2015-2018 Alibaba Group Holding Limited
*
*/
#include "aiot_ota_api.h"
#include "core_mqtt.h"
#include "core_string.h"
#include "core_sha256.h"
#include "ota_md5.h"
#include "core_log.h"
#include "core_global.h"
#include "mqtt_download_private.h"
#include "aiot_mqtt_download_api.h"
#include "ota_private.h"
#include "core_string.h"
static int32_t _md_send_request(void *handle);
static void _md_recv_data_reply_handler(void *handle, const aiot_mqtt_recv_t *msg, void *userdata);
/*
* CRC lookup table for bytes, generating polynomial is 0x8005
* input: reflexed (LSB first)
* output: reflexed also...
*/
const uint16_t crc_ibm_table[256] = {
0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040,
};
uint16_t crc_ibm(uint8_t const *buffer, size_t len)
{
uint16_t crc = 0x0000;
uint8_t lut;
while (len--) {
lut = (crc ^ (*buffer++)) & 0xFF;
crc = (crc >> 8) ^ crc_ibm_table[lut];
}
return crc;
}
int32_t _md_sub_response_topic(void *handle)
{
char topic[128];
mqtt_download_handle_t *md_handle = (mqtt_download_handle_t *)handle;
if(handle == NULL) {
return STATE_DOWNLOAD_DEINIT_HANDLE_IS_NULL;
}
memset(topic, 0, sizeof(topic));
snprintf(topic, sizeof(topic) - 1, MQTT_DOWNLOAD_RESPONSE_TOPIC,
core_mqtt_get_product_key(md_handle->task_desc->mqtt_handle), core_mqtt_get_device_name(md_handle->task_desc->mqtt_handle));
return aiot_mqtt_sub(md_handle->task_desc->mqtt_handle, topic, _md_recv_data_reply_handler, 0, handle);
}
int32_t _md_unsub_response_topic(void *handle)
{
char topic[128];
mqtt_download_handle_t *md_handle = (mqtt_download_handle_t *)handle;
if(handle == NULL) {
return STATE_DOWNLOAD_DEINIT_HANDLE_IS_NULL;
}
memset(topic, 0, sizeof(topic));
snprintf(topic, sizeof(topic) - 1, MQTT_DOWNLOAD_RESPONSE_TOPIC,
core_mqtt_get_product_key(md_handle->task_desc->mqtt_handle), core_mqtt_get_device_name(md_handle->task_desc->mqtt_handle));
return aiot_mqtt_unsub(md_handle->task_desc->mqtt_handle, topic);
}
void *aiot_mqtt_download_init(void)
{
mqtt_download_handle_t *md_handle = NULL;
aiot_sysdep_portfile_t *sysdep = NULL;
sysdep = aiot_sysdep_get_portfile();
if (sysdep == NULL) {
return NULL;
}
md_handle = sysdep->core_sysdep_malloc(sizeof(mqtt_download_handle_t), MQTT_DOWNLOAD_MODULE_NAME);
if (md_handle == NULL) {
return NULL;
}
memset(md_handle, 0, sizeof(mqtt_download_handle_t));
md_handle->status = STATE_MQTT_DOWNLOAD_INIT;
md_handle->sysdep = sysdep;
md_handle->request_size = MQTT_DOWNLOAD_DEFAULT_REQUEST_SIZE;
md_handle->last_request_time = 0;
md_handle->data_mutex = sysdep->core_sysdep_mutex_init();
md_handle->recv_mutex = sysdep->core_sysdep_mutex_init();
return md_handle;
}
static void _md_core_mqtt_process_handler(void *context, aiot_mqtt_event_t *event, core_mqtt_event_t *core_event)
{
mqtt_download_handle_t *md_handle = (mqtt_download_handle_t *)context;
if (core_event != NULL) {
switch (core_event->type) {
case CORE_MQTTEVT_DEINIT: {
md_handle->task_desc->mqtt_handle = NULL;
return;
}
default: {
}
break;
}
}
}
int32_t aiot_mqtt_download_deinit(void **handle)
{
int32_t res = STATE_SUCCESS;
if (NULL == handle || NULL == *handle) {
return STATE_DOWNLOAD_DEINIT_HANDLE_IS_NULL;
}
mqtt_download_handle_t *md_handle = *(mqtt_download_handle_t **)handle;
if (NULL != md_handle->task_desc) {
if (AIOT_OTA_DIGEST_MD5 == md_handle->task_desc->digest_method) {
if (NULL != md_handle->digest_ctx) {
utils_md5_free(md_handle->digest_ctx);
md_handle->sysdep->core_sysdep_free(md_handle->digest_ctx);
md_handle->digest_ctx = NULL;
}
}
if(md_handle->task_desc->mqtt_handle != NULL) {
core_mqtt_process_data_t process_data;
memset(&process_data, 0, sizeof(core_mqtt_process_data_t));
process_data.handler = _md_core_mqtt_process_handler;
process_data.context = handle;
core_mqtt_setopt(md_handle->task_desc->mqtt_handle, CORE_MQTTOPT_REMOVE_PROCESS_HANDLER, &process_data);
_md_unsub_response_topic(md_handle);
}
_download_deep_free_task_desc(md_handle->sysdep, md_handle->task_desc);
md_handle->sysdep->core_sysdep_free(md_handle->task_desc);
md_handle->task_desc = NULL;
}
md_handle->sysdep->core_sysdep_mutex_deinit(&md_handle->data_mutex);
md_handle->sysdep->core_sysdep_mutex_deinit(&md_handle->recv_mutex);
md_handle->sysdep->core_sysdep_free(md_handle);
*handle = NULL;
return res;
}
/* 根据下载到的固件的内容, 计算其digest值 */
static int32_t _download_digest_update(mqtt_download_handle_t *download_handle, uint8_t *buffer, uint32_t buffer_len)
{
int32_t res = STATE_SUCCESS;
if (AIOT_OTA_DIGEST_SHA256 == download_handle->task_desc->digest_method) {
core_sha256_update(download_handle->digest_ctx, buffer, buffer_len);
} else if (AIOT_OTA_DIGEST_MD5 == download_handle->task_desc->digest_method) {
res = utils_md5_update(download_handle->digest_ctx, buffer, buffer_len);
}
return res;
}
/* 对计算出来的digest值, 与云端下发的digest值进行比较 */
static int32_t _download_digest_verify(mqtt_download_handle_t *download_handle)
{
uint8_t output[32] = {0};
uint8_t expected_digest[32] = {0};
if (AIOT_OTA_DIGEST_SHA256 == download_handle->task_desc->digest_method) {
core_str2hex(download_handle->task_desc->expect_digest, OTA_SHA256_LEN, expected_digest);
core_sha256_finish(download_handle->digest_ctx, output);
if (memcmp(output, expected_digest, 32) == 0) {
return STATE_SUCCESS;
}
} else if (AIOT_OTA_DIGEST_MD5 == download_handle->task_desc->digest_method) {
core_str2hex(download_handle->task_desc->expect_digest, OTA_MD5_LEN, expected_digest);
utils_md5_finish(download_handle->digest_ctx, output);
if (memcmp(output, expected_digest, 16) == 0) {
return STATE_SUCCESS;
}
}
return STATE_OTA_DIGEST_MISMATCH;
}
static int32_t _download_report_progress(void *handle, int32_t percent)
{
int32_t res = STATE_SUCCESS;
mqtt_download_handle_t *md_handle = NULL;
aiot_sysdep_portfile_t *sysdep = NULL;
char out_buffer[4] = {0};
uint8_t out_len;
char *payload_string;
if (NULL == handle) {
return STATE_MQTT_DOWNLOAD_MQTT_HANDLE_NULL;
}
md_handle = (mqtt_download_handle_t *)handle;
sysdep = md_handle->sysdep;
if (NULL == md_handle->task_desc) {
return STATE_MQTT_DOWNLOAD_TASK_DEINIT;
}
core_int2str(percent, out_buffer, &out_len);
if (md_handle->task_desc->module) {
char *src[] = {"{\"step\":\"", out_buffer, "\",\"desc\":\"\",\"module\":\"", md_handle->task_desc->module, "\"}"};
uint8_t topic_len = sizeof(src) / sizeof(char *);
core_sprintf(sysdep, &payload_string, "%s%s%s%s%s", src, topic_len, OTA_MODULE_NAME);
} else {
char *src[] = {"{\"step\":\"", out_buffer, "\",\"desc\":\"\"}"};
uint8_t topic_len = sizeof(src) / sizeof(char *);
core_sprintf(sysdep, &payload_string, "%s%s%s", src, topic_len, OTA_MODULE_NAME);
}
res = _ota_publish_base(md_handle->task_desc->mqtt_handle, OTA_PROGRESS_TOPIC_PREFIX,
md_handle->task_desc->product_key,
md_handle->task_desc->device_name, NULL, payload_string);
sysdep->core_sysdep_free(payload_string);
return res;
}
static int32_t _parse_json_header(void *handle, char *data, uint32_t data_len, aiot_mqtt_download_recv_t *pakcet)
{
mqtt_download_handle_t *md_handle = (mqtt_download_handle_t *)handle;
char *header = data, *file_info = NULL, *value = NULL;
uint32_t header_len = data_len, file_info_len = 0, value_len = 0;
uint32_t code = 0;
uint32_t size = 0, offset = 0, fileLenth = 0;
int32_t res = STATE_SUCCESS;
if ((res = core_json_value((char *)header, header_len, "code", strlen("code"),
&value, &value_len)) < 0 ||
((res = core_str2uint(value, value_len, &code)) < 0) ||
code != 200 ) {
core_log1(md_handle->sysdep, 0, "recv handle parse err code %d\r\n", &code);
return res;
}
if ((res = core_json_value((char *)header, header_len, "data", strlen("data"),
&value, &value_len)) < 0 ) {
core_log(md_handle->sysdep, 0, "json parse error data\r\n");
return res;
}
/* 解析文件的描述信息 */
file_info = value;
file_info_len = value_len;
if ((res = core_json_value((char *)file_info, file_info_len, "bSize", strlen("bSize"),
&value, &value_len)) < 0 ||
((res = core_str2uint(value, value_len, &size)) < 0)) {
core_log(md_handle->sysdep, 0, "json parse error bSize\r\n");
return res;
}
if ((res = core_json_value((char *)file_info, file_info_len, "bOffset", strlen("bOffset"),
&value, &value_len)) < 0 ||
((res = core_str2uint(value, value_len, &offset)) < 0)) {
core_log(md_handle->sysdep, 0, "json parse error bOffset\r\n");
return res;
}
if ((res = core_json_value((char *)file_info, file_info_len, "fileLength", strlen("fileLength"),
&value, &value_len)) < 0 ||
((res = core_str2uint(value, value_len, &fileLenth)) < 0)) {
core_log(md_handle->sysdep, 0, "json parse error bOffset\r\n");
return res;
}
if ((res = core_json_value((char *)file_info, file_info_len, "fileToken", strlen("fileToken"),
&value, &value_len)) == 0 ) {
memcpy(pakcet->data.data_resp.filename, value, value_len);
}
pakcet->data.data_resp.data_size = size;
pakcet->data.data_resp.offset = offset;
pakcet->data.data_resp.file_lenth = fileLenth;
return res;
}
static void _md_resend_request(mqtt_download_handle_t *md_handle)
{
md_handle->failed_counter++;
if(md_handle->failed_counter > 3) {
md_handle->status = STATE_MQTT_DOWNLOAD_FAILED_TIMEOUT;
return;
}
_md_send_request(md_handle);
}
static void _md_recv_data_reply_handler(void *handle, const aiot_mqtt_recv_t *msg, void *userdata)
{
mqtt_download_handle_t *md_handle = (mqtt_download_handle_t *)userdata;
/*有效文件数据*/
uint8_t *data = NULL;
uint32_t data_len = 0;
/*json头解析变量定义*/
char *header = NULL;
uint16_t header_len = 0;
char file_token[MQTT_DOWNLOAD_TOKEN_MAXLEN];
uint16_t crc16 = 0, cal_crc16 = 0;
aiot_mqtt_download_recv_t packet;
memset(file_token, 0, sizeof(file_token));
packet.type = AIOT_MDRECV_DATA_RESP;
packet.data.data_resp.filename = file_token;
if(md_handle == NULL || md_handle->status != STATE_MQTT_DOWNLOAD_ING) {
return;
}
/*获取并解析json头*/
header = (char *)(msg->data.pub.payload + 2);
header_len = *msg->data.pub.payload << 8 | *(msg->data.pub.payload + 1);
if(_parse_json_header(md_handle, header, header_len, &packet) < 0) {
_md_resend_request(md_handle);
return;
}
/* 校验数据长度 */
if(msg->data.pub.payload_len != sizeof(header_len) + header_len + packet.data.data_resp.data_size + sizeof(crc16)) {
core_log(md_handle->sysdep, 0, "payload lenth dismatch data lenth\r\n");
_md_resend_request(md_handle);
return;
}
/* 有效的文件数据 */
data = msg->data.pub.payload + sizeof(header_len) + header_len;
data_len = packet.data.data_resp.data_size;
/* CRC校验 */
crc16 = *(uint16_t *)(msg->data.pub.payload + msg->data.pub.payload_len - sizeof(crc16));
cal_crc16 = crc_ibm(data, data_len);
if(cal_crc16 != crc16) {
_md_resend_request(md_handle);
return;
}
/* 判断接收的数据偏移是否为请求的偏移,可能存在重复请求,这里校验失败,不主动重发请求,等超时 */
if(packet.data.data_resp.offset != md_handle->size_fetched + md_handle->range_start) {
return;
}
/* 生成回调packet包回调用户接口 */
md_handle->size_fetched += data_len;
packet.data.data_resp.data = (char *)data;
packet.data.data_resp.percent = md_handle->size_fetched * 100 / md_handle->range_size;
/* 计算digest, 如果下载完成, 还要看看是否与云端计算出来的一致 */
if(md_handle->md5_enabled) {
_download_digest_update(md_handle, (uint8_t *)packet.data.data_resp.data, packet.data.data_resp.data_size);
}
/* 数据接收成功,失败统计复位 */
md_handle->failed_counter = 0;
/* 回调用户接口, 通知存储数据 */
if(md_handle->recv_handler != NULL) {
md_handle->recv_handler(md_handle, &packet, md_handle->userdata);
}
if(md_handle->size_fetched < md_handle->range_size) {
/*请求下一包*/
_md_send_request(md_handle);
} else if(md_handle->size_fetched == md_handle->range_size) {
/*下载完成, 如果有md5还需要做整个文件的校验*/
md_handle->percent = 100;
md_handle->status = STATE_MQTT_DOWNLOAD_FINISHED;
} else {
md_handle->status = STATE_MQTT_DOWNLOAD_FAILED_RECVERROR;
}
}
int32_t aiot_mqtt_download_setopt(void *handle, aiot_mqtt_download_option_t option, void *data) {
int32_t res = STATE_SUCCESS;
if (NULL == handle) {
return STATE_DOWNLOAD_DEINIT_HANDLE_IS_NULL;
}
mqtt_download_handle_t *md_handle = (mqtt_download_handle_t *)handle;
md_handle->sysdep->core_sysdep_mutex_lock(md_handle->data_mutex);
switch (option) {
case AIOT_MDOPT_USERDATA: {
md_handle->userdata = data;
}
break;
case AIOT_MDOPT_TASK_DESC: {
void *new_task_desc = _download_deep_copy_task_desc(md_handle->sysdep, data);
if (NULL == new_task_desc) {
res = STATE_DOWNLOAD_SETOPT_COPIED_DATA_IS_NULL;
break;
}
md_handle->task_desc = (aiot_download_task_desc_t *)new_task_desc;
core_mqtt_process_data_t process_data;
memset(&process_data, 0, sizeof(core_mqtt_process_data_t));
process_data.handler = _md_core_mqtt_process_handler;
process_data.context = handle;
core_mqtt_setopt(md_handle->task_desc->mqtt_handle, CORE_MQTTOPT_APPEND_PROCESS_HANDLER, &process_data);
}
break;
case AIOT_MDOPT_RANGE_START: {
md_handle->range_start = *(uint32_t *)data;
}
break;
case AIOT_MDOPT_RANGE_END: {
md_handle->range_end = *(uint32_t *)data;
}
break;
case AIOT_MDOPT_RECV_HANDLE: {
md_handle->recv_handler = (aiot_mqtt_download_recv_handler_t)data;
}
break;
case AIOT_MDOPT_DATA_REQUEST_SIZE: {
md_handle->request_size = *(uint32_t *)data;
}
break;
default: {
res = STATE_USER_INPUT_OUT_RANGE;
}
break;
}
md_handle->sysdep->core_sysdep_mutex_unlock(md_handle->data_mutex);
return res;
}
static int32_t _md_send_request(void *handle)
{
mqtt_download_handle_t *md_handle = (mqtt_download_handle_t *)handle;
char *payload_fmt = "{\"id\":\"%s\",\"version\":\"1.0\",\"params\":%s}";
char *params_fmt = "{\"fileToken\":\"%s\",\"fileInfo\":{\"streamId\":%s,\"fileId\":%s,},\"fileBlock\":{\"size\":%s,\"offset\":%s}}";
char *params = NULL, *payload = NULL, *topic = NULL;
char stream_id_string[21], file_id_string[21], request_size_string[21], offset_string[21];
char *params_src[] = {"default", stream_id_string, file_id_string, request_size_string, offset_string };
char id_string[21];
char *payload_src[2] = { id_string };
char *topic_src[2] = { id_string };
uint32_t res = STATE_SUCCESS;
uint32_t offset = md_handle->size_fetched + md_handle->range_start;
/* 生成params */
int32_t size = md_handle->request_size;
if(md_handle->request_size + md_handle->size_fetched > md_handle->range_size)
{
size = md_handle->range_size - md_handle->size_fetched;
}
memset(stream_id_string, 0, sizeof(stream_id_string));
core_uint2str(md_handle->task_desc->stream_id, stream_id_string, NULL);
memset(file_id_string, 0, sizeof(file_id_string));
core_uint2str(md_handle->task_desc->stream_file_id, file_id_string, NULL);
memset(request_size_string, 0, sizeof(request_size_string));
core_uint2str(size, request_size_string, NULL);
memset(offset_string, 0, sizeof(offset_string));
core_uint2str(offset, offset_string, NULL);
core_sprintf(md_handle->sysdep, &params, params_fmt, params_src, sizeof(params_src) / sizeof(char *),
MQTT_DOWNLOAD_MODULE_NAME);
/*生成payload */
md_handle->msg_id++;
memset(id_string, 0, sizeof(id_string));
core_uint2str(md_handle->msg_id, id_string, NULL);
payload_src[1] = params;
core_sprintf(md_handle->sysdep, &payload, payload_fmt, payload_src, sizeof(payload_src) / sizeof(char *),
MQTT_DOWNLOAD_MODULE_NAME);
topic_src[0] = core_mqtt_get_product_key(md_handle->task_desc->mqtt_handle);
topic_src[1] = core_mqtt_get_device_name(md_handle->task_desc->mqtt_handle);
core_sprintf(md_handle->sysdep, &topic, MQTT_DOWNLOAD_REQUEST_TOPIC, topic_src, sizeof(topic_src) / sizeof(char *),
MQTT_DOWNLOAD_MODULE_NAME);
if( payload != NULL && topic != NULL) {
res = aiot_mqtt_pub(md_handle->task_desc->mqtt_handle, topic, (uint8_t *)payload, strlen(payload), 0);
}
md_handle->last_request_time = md_handle->sysdep->core_sysdep_time();
if(topic != NULL) {
md_handle->sysdep->core_sysdep_free(topic);
}
if(payload != NULL) {
md_handle->sysdep->core_sysdep_free(payload);
}
if(params != NULL) {
md_handle->sysdep->core_sysdep_free(params);
}
return res;
}
static int32_t _md_reset_handle(mqtt_download_handle_t *md_handle)
{
if(md_handle == NULL) {
return STATE_MQTT_DOWNLOAD_MQTT_HANDLE_NULL;
}
md_handle->msg_id = 0;
md_handle->size_fetched = 0;
md_handle->percent = 0;
md_handle->last_request_time = 0;
md_handle->failed_counter = 0;
md_handle->last_percent = 0;
md_handle->range_size = 0;
return STATE_SUCCESS;
}
int32_t aiot_mqtt_download_process(void *handle)
{
uint64_t now;
mqtt_download_handle_t *md_handle = (mqtt_download_handle_t *)handle;
int32_t percent = 0;
int32_t res = 0;
if(md_handle == NULL) {
return STATE_MQTT_DOWNLOAD_MQTT_HANDLE_NULL;
}
if(md_handle->task_desc == NULL || md_handle->task_desc->mqtt_handle == NULL) {
return STATE_MQTT_DOWNLOAD_TASK_DEINIT;
}
res = md_handle->status;
switch(md_handle->status) {
case STATE_MQTT_DOWNLOAD_INIT: {
/* 没有设置片段下载结尾,设置下载至文件结尾 */
if(md_handle->range_end == 0) {
md_handle->range_end = md_handle->task_desc->size_total;
}
md_handle->range_size = md_handle->range_end - md_handle->range_start;
if(md_handle->range_size <= 0) {
return STATE_MQTT_DOWNLOAD_FILESIZE_ERROR;
}
/* 订阅数据返回的topic */
_md_sub_response_topic(md_handle);
/* 完整的文件下载做md5校验 */
if(md_handle->range_size == md_handle->task_desc->size_total
&& AIOT_OTA_DIGEST_MD5 == md_handle->task_desc->digest_method
&& NULL != md_handle->task_desc->expect_digest) {
utils_md5_context_t *ctx = md_handle->sysdep->core_sysdep_malloc(sizeof(utils_md5_context_t), MQTT_DOWNLOAD_MODULE_NAME);
if (NULL == ctx) {
res = STATE_DOWNLOAD_SETOPT_MALLOC_MD5_CTX_FAILED;
break;
}
md_handle->md5_enabled = 1;
utils_md5_init(ctx);
utils_md5_starts(ctx);
md_handle->digest_ctx = (void *) ctx;
}
_md_send_request(handle);
md_handle->last_request_time = md_handle->sysdep->core_sysdep_time();
md_handle->status = STATE_MQTT_DOWNLOAD_ING;
res = STATE_MQTT_DOWNLOAD_ING;
}
break;
case STATE_MQTT_DOWNLOAD_ING: {
now = md_handle->sysdep->core_sysdep_time();
if(now - md_handle->last_request_time > MQTT_DOWNLOAD_DEFAULT_RECV_TIMEOUT) {
_md_resend_request(md_handle);
}
percent = md_handle->size_fetched * 100 / md_handle->range_size;
if(percent - md_handle->last_percent >= MQTT_DOWNLOAD_REPORT_INTERNEL) {
md_handle->last_percent = percent;
_download_report_progress(md_handle, percent);
}
}
break;
case STATE_MQTT_DOWNLOAD_FINISHED: {
if(md_handle->md5_enabled) {
int32_t ret = _download_digest_verify(md_handle);
if (ret != STATE_SUCCESS) {
md_handle->status = STATE_MQTT_DOWNLOAD_FAILED_MISMATCH;
core_log(md_handle->sysdep, ret, "digest mismatch\r\n");
} else {
md_handle->status = STATE_MQTT_DOWNLOAD_SUCCESS;
core_log(md_handle->sysdep, STATE_OTA_DIGEST_MATCH, "digest matched\r\n");
}
if (NULL != md_handle->digest_ctx) {
utils_md5_free(md_handle->digest_ctx);
md_handle->sysdep->core_sysdep_free(md_handle->digest_ctx);
md_handle->digest_ctx = NULL;
}
} else {
md_handle->status = STATE_MQTT_DOWNLOAD_SUCCESS;
}
}
break;
case STATE_MQTT_DOWNLOAD_SUCCESS: {
_download_report_progress(md_handle, 100);
_md_reset_handle(md_handle);
md_handle->status = STATE_MQTT_DOWNLOAD_INIT;
}
break;
case STATE_MQTT_DOWNLOAD_FAILED_MISMATCH: {
_download_report_progress(md_handle, AIOT_OTAERR_CHECKSUM_MISMATCH);
_md_reset_handle(md_handle);
md_handle->status = STATE_MQTT_DOWNLOAD_INIT;
}
break;
case STATE_MQTT_DOWNLOAD_FAILED_RECVERROR:
case STATE_MQTT_DOWNLOAD_FAILED_TIMEOUT: {
_download_report_progress(md_handle, AIOT_OTAERR_BURN_FAILED);
_md_reset_handle(md_handle);
md_handle->status = STATE_MQTT_DOWNLOAD_INIT;
}
break;
}
return res;
}

View File

@@ -0,0 +1,289 @@
/**
* @file aiot_mqtt_download_api.h
* @brief mqtt_download模块头文件, 提供mqtt文件传输的能力
*
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
*
*/
#ifndef __AIOT_MQTT_DOWNLOAD_API_H__
#define __AIOT_MQTT_DOWNLOAD_API_H__
#if defined(__cplusplus)
extern "C" {
#endif
#include <stdint.h>
/**
* @brief -0x1D00~-0x1DFF表达SDK在mqtt_download模块内的状态码
*/
#define STATE_MQTT_DOWNLOAD_BASE (-0x1D00)
/**
* @brief mqtt_download_handle为空
*/
#define STATE_MQTT_DOWNLOAD_MQTT_HANDLE_NULL (-0x1D01)
/**
* @brief 任务未初始化
*/
#define STATE_MQTT_DOWNLOAD_TASK_DEINIT (-0x1D02)
/**
* @brief 初始化完,第一次执行请求
*/
#define STATE_MQTT_DOWNLOAD_INIT (-0x1D03)
/**
* @brief 正在下载文件
*/
#define STATE_MQTT_DOWNLOAD_ING (-0x1D04)
/**
* @brief 文件已经下载完,但未校验
*/
#define STATE_MQTT_DOWNLOAD_FINISHED (-0x1D05)
/**
* @brief 文件下载完成,并且校验通过
*/
#define STATE_MQTT_DOWNLOAD_SUCCESS (-0x1D06)
/**
* @brief 文件下载接收失败,重试几个后还是失败,认定为超时
*/
#define STATE_MQTT_DOWNLOAD_FAILED_TIMEOUT (-0x1D07)
/**
* @brief 完整文件下载时MD5校验失败
*/
#define STATE_MQTT_DOWNLOAD_FAILED_MISMATCH (-0x1D08)
/**
* @brief 接收长度校验错误
*/
#define STATE_MQTT_DOWNLOAD_FAILED_RECVERROR (-0x1D09)
/**
* @brief 用户主动取消下载任务
*/
#define STATE_MQTT_DOWNLOAD_ABORT (-0x1D0A)
/**
* @brief 设置的下载长度为空
*/
#define STATE_MQTT_DOWNLOAD_FILESIZE_ERROR (-0x1D0B)
/**
* @brief mqtt_download模块收到从网络上来的报文时, 通知用户的报文类型
*/
typedef enum {
/**
* @brief 文件分片下载请求的返回报文
*/
AIOT_MDRECV_DATA_RESP,
} aiot_mqtt_download_recv_type_t;
/**
* @brief mqtt_download模块收到从网络上来的报文时, 通知用户的报文内容
*/
typedef struct {
/**
* @brief 报文内容所对应的报文类型, 更多信息请参考@ref aiot_mqtt_download_recv_type_t
*/
aiot_mqtt_download_recv_type_t type;
union {
/**
* @brief data_resp_type的说明
*/
struct {
/**
* @brief 用户标准的文件名称,一般为设置的文件名
*/
char *filename;
/**
* @brief 文件的偏移
*/
uint32_t offset;
/**
* @brief 接收到的数据长度
*/
uint32_t data_size;
/**
* @brief 接收到的数据
*/
char *data;
/**
* @brief 接收到的数据
*/
int32_t percent;
/**
* @brief 文件的总大小
*/
int32_t file_lenth;
} data_resp;
} data;
} aiot_mqtt_download_recv_t;
/**
* @brief mqtt_download模块收到从网络上来的报文时, 通知用户所调用的数据回调函数
*
* @param[in] handle mqtt_download会话句柄
* @param[in] packet mqtt_download消息结构体, 存放收到的mqtt_download报文内容
* @param[in] userdata 用户上下文
*
* @return void
*/
typedef void (* aiot_mqtt_download_recv_handler_t)(void *handle,
const aiot_mqtt_download_recv_t *packet, void *userdata);
/**
* @brief @ref aiot_mqtt_download_setopt 接口的option参数可选值.
*
* @details 下文每个选项中的数据类型, 指的是@ref aiot_mqtt_download_setopt 中, data参数的数据类型
*/
typedef enum {
/**
* @brief 设置处理OTA消息的用户回调函数
*
* @details
*
* 数据类型: (aiot_mqtt_download_recv_handler_t)
*/
AIOT_MDOPT_RECV_HANDLE,
/**
* @brief 设置MQTT的handle
*
* @details
*
* 文件下载过程中使用MQTT的通道能力, 用以请求数据及接收数据
*
* 数据类型: (void *)
*/
AIOT_MDOPT_MQTT_HANDLE,
/**
* @brief 用户需要SDK暂存的上下文
*
* @details
*
* 该上下文会在@ref AIOT_OTAOPT_RECV_HANDLER 中传回给用户
*
* 数据类型: (void *)
*/
AIOT_MDOPT_USERDATA,
/**
* @brief 设置download实例句柄所包含下载任务的具体内容
*
* @details
*
* 用户在收到OTA的mqtt消息后, 如果决定升级, 则需要通过该选项, 在download实例句柄中开辟内存,
* 将OTA消息中携带的url, version, digest method, sign等信息复制过来, 有了这些信息后才能开始下载任务
*
* 数据类型: (aiot_download_task_desc_t *)
*
**/
AIOT_MDOPT_TASK_DESC,
/**
* @brief 设置按照range下载的起始地址
*
* @details
*
* MQTT 范围请求(range requests)特性中, 表示从第该byte开始下载
* 如果指定从头开始下载, 则start的值为0
*
* 数据类型: (uint32_t *)
*
**/
AIOT_MDOPT_RANGE_START,
/**
* @brief 设置按照range下载的结束地址
*
* @details
* MQTT 范围请求(range requests)特性中, 表示下载到该byte后结束.
* 如果指定从头开始下载到10个byte后结束,
* 则需要指定start = 0, end = 9, 这样总共10个byte
*
* 数据类型: (uint32_t *)
*
**/
AIOT_MDOPT_RANGE_END,
/**
* @brief 单次请求数据的最大长度
*
* @details
*
* 数据类型: (uint32_t *) 默认值: (2 *1024) Bytes
*/
AIOT_MDOPT_DATA_REQUEST_SIZE,
AIOT_MDOPT_MAX,
} aiot_mqtt_download_option_t;
/**
* @brief 创建mqtt_download会话实例, 并以默认值配置会话参数
*
* @return void *
* @retval 非NULL mqtt_download实例的句柄
* @retval NULL 初始化失败, 一般是内存分配失败导致
*
*/
void *aiot_mqtt_download_init(void);
/**
* @brief 配置mqtt_download会话
*
* @param[in] handle mqtt_download会话句柄
* @param[in] option 配置选项, 更多信息请参考@ref aiot_mqtt_download_option_t
* @param[in] data 配置选项数据, 更多信息请参考@ref aiot_mqtt_download_option_t
*
* @return int32_t
* @retval <STATE_SUCCESS 参数配置失败
* @retval >=STATE_SUCCESS 参数配置成功
*
*/
int32_t aiot_mqtt_download_setopt(void *handle, aiot_mqtt_download_option_t option, void *data);
/**
* @brief 结束mqtt_download会话, 销毁实例并回收资源
*
* @param[in] handle 指向mqtt_download会话句柄的指针
*
* @return int32_t
* @retval <STATE_SUCCESS 执行失败
* @retval >=STATE_SUCCESS 执行成功
*
*/
int32_t aiot_mqtt_download_deinit(void **handle);
/**
* @brief 处理下载逻辑
*
* @param handle mqtt_download会话句柄
*
* @return int32_t
* @retval STATE_MQTT_DOWNLOAD_INIT 初始化完成
* @retval STATE_MQTT_DOWNLOAD_ING 正在下载
* @retval STATE_MQTT_DOWNLOAD_SUCCESS 下载完成
* @retval STATE_MQTT_DOWNLOAD_FAILED_RECVERROR 数据接收错误
* @retval STATE_MQTT_DOWNLOAD_FAILED_TIMEOUT 接收超时
* @retval STATE_MQTT_DOWNLOAD_FAILED_MISMATCH 校验错误
* @retval STATE_MQTT_DOWNLOAD_MQTT_HANDLE_NULL handle没有初始化
* @retval STATE_MQTT_DOWNLOAD_TASK_DEINIT 没有设置task
*/
int32_t aiot_mqtt_download_process(void *handle);
#if defined(__cplusplus)
}
#endif
#endif /* __AIOT_MQTT_DOWNLOAD_API_H__ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,68 @@
/**
* @file mqtt_download_private.h
* @brief mqtt_download模块内部的宏定义和数据结构声明, 不面向其它模块, 更不面向用户
*
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
*
*/
#ifndef __MQTT_DOWNLOAD_PRIVATE_H__
#define __MQTT_DOWNLOAD_PRIVATE_H__
#if defined(__cplusplus)
extern "C" {
#endif
#include "core_stdinc.h"
#include "aiot_state_api.h"
#include "aiot_sysdep_api.h"
#include "aiot_ota_api.h"
#include "aiot_mqtt_download_api.h" /* 内部头文件是用户可见头文件的超集 */
/* 定义mqtt_download模块内部的会话句柄结构体, SDK用户不可见, 只能得到void *handle类型的指针 */
typedef struct {
aiot_sysdep_portfile_t *sysdep; /* 底层依赖回调合集的引用指针 */
aiot_mqtt_download_recv_handler_t recv_handler; /* 组件从协议栈读到内容时, 通知用户的回调 */
void *userdata; /* 组件调用以上2个 mqtt_download_handler 时的入参之一 */
aiot_download_task_desc_t *task_desc; /* 某次下载活动的目标描述信息, 如URL等 */
uint32_t range_start;
uint32_t range_end;
uint32_t request_size; /* 每次请求的size */
/*---- 以上都是用户在API可配 ----*/
uint32_t msg_id;
uint32_t size_fetched;
int32_t percent;
uint64_t last_request_time;
uint64_t failed_counter;
int32_t status;
int32_t last_percent;
uint32_t range_size;
int8_t md5_enabled;
void *digest_ctx;
void *data_mutex;
void *recv_mutex;
} mqtt_download_handle_t;
/* 用于内存统计的模块名字符串 */
#define MQTT_DOWNLOAD_MODULE_NAME "mqtt_download"
/* 发送请求后,等待回复的超时时间设置 */
#define MQTT_DOWNLOAD_DEFAULT_RECV_TIMEOUT (10 * 1000)
/* 默认的单次请求长度 */
#define MQTT_DOWNLOAD_DEFAULT_REQUEST_SIZE (5 * 1024)
/* 请求及回复的topic定义 */
#define MQTT_DOWNLOAD_REQUEST_TOPIC "/sys/%s/%s/thing/file/download"
#define MQTT_DOWNLOAD_RESPONSE_TOPIC "/sys/%s/%s/thing/file/download_reply"
/* TOKEN的最长长度 */
#define MQTT_DOWNLOAD_TOKEN_MAXLEN (128)
/* 上报进度的间隔,单位:% */
#define MQTT_DOWNLOAD_REPORT_INTERNEL (5)
#if defined(__cplusplus)
}
#endif
#endif /* __MQTT_DOWNLOAD_PRIVATE_H__ */

View File

@@ -0,0 +1,299 @@
#include "ota_md5.h"
/*
* 32-bit integer manipulation macros (little endian)
*/
#ifndef GET_UINT32_LE
#define GET_UINT32_LE(n,b,i) \
{ \
(n) = ( (uint32_t) (b)[(i) ] ) \
| ( (uint32_t) (b)[(i) + 1] << 8 ) \
| ( (uint32_t) (b)[(i) + 2] << 16 ) \
| ( (uint32_t) (b)[(i) + 3] << 24 ); \
}
#endif
#ifndef PUT_UINT32_LE
#define PUT_UINT32_LE(n,b,i) \
{ \
(b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \
(b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \
(b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \
(b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \
}
#endif
static void utils_md5_zeroize(void *v, uint32_t n)
{
volatile unsigned char *p = v;
while (n--) {
*p++ = 0;
}
}
void utils_md5_init(utils_md5_context_t *ctx)
{
memset(ctx, 0, sizeof(utils_md5_context_t));
}
void utils_md5_free(utils_md5_context_t *ctx)
{
if (ctx == NULL) {
return;
}
utils_md5_zeroize(ctx, sizeof(utils_md5_context_t));
}
/*
* MD5 context setup
*/
int32_t utils_md5_starts(utils_md5_context_t *ctx)
{
ctx->total[0] = 0;
ctx->total[1] = 0;
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
return (0);
}
int32_t utils_internal_md5_process(utils_md5_context_t *ctx,
const unsigned char data[64])
{
uint32_t X[16], A, B, C, D;
GET_UINT32_LE(X[ 0], data, 0);
GET_UINT32_LE(X[ 1], data, 4);
GET_UINT32_LE(X[ 2], data, 8);
GET_UINT32_LE(X[ 3], data, 12);
GET_UINT32_LE(X[ 4], data, 16);
GET_UINT32_LE(X[ 5], data, 20);
GET_UINT32_LE(X[ 6], data, 24);
GET_UINT32_LE(X[ 7], data, 28);
GET_UINT32_LE(X[ 8], data, 32);
GET_UINT32_LE(X[ 9], data, 36);
GET_UINT32_LE(X[10], data, 40);
GET_UINT32_LE(X[11], data, 44);
GET_UINT32_LE(X[12], data, 48);
GET_UINT32_LE(X[13], data, 52);
GET_UINT32_LE(X[14], data, 56);
GET_UINT32_LE(X[15], data, 60);
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
#define P(a,b,c,d,k,s,t) \
{ \
a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
}
A = ctx->state[0];
B = ctx->state[1];
C = ctx->state[2];
D = ctx->state[3];
#define F(x,y,z) (z ^ (x & (y ^ z)))
P(A, B, C, D, 0, 7, 0xD76AA478);
P(D, A, B, C, 1, 12, 0xE8C7B756);
P(C, D, A, B, 2, 17, 0x242070DB);
P(B, C, D, A, 3, 22, 0xC1BDCEEE);
P(A, B, C, D, 4, 7, 0xF57C0FAF);
P(D, A, B, C, 5, 12, 0x4787C62A);
P(C, D, A, B, 6, 17, 0xA8304613);
P(B, C, D, A, 7, 22, 0xFD469501);
P(A, B, C, D, 8, 7, 0x698098D8);
P(D, A, B, C, 9, 12, 0x8B44F7AF);
P(C, D, A, B, 10, 17, 0xFFFF5BB1);
P(B, C, D, A, 11, 22, 0x895CD7BE);
P(A, B, C, D, 12, 7, 0x6B901122);
P(D, A, B, C, 13, 12, 0xFD987193);
P(C, D, A, B, 14, 17, 0xA679438E);
P(B, C, D, A, 15, 22, 0x49B40821);
#undef F
#define F(x,y,z) (y ^ (z & (x ^ y)))
P(A, B, C, D, 1, 5, 0xF61E2562);
P(D, A, B, C, 6, 9, 0xC040B340);
P(C, D, A, B, 11, 14, 0x265E5A51);
P(B, C, D, A, 0, 20, 0xE9B6C7AA);
P(A, B, C, D, 5, 5, 0xD62F105D);
P(D, A, B, C, 10, 9, 0x02441453);
P(C, D, A, B, 15, 14, 0xD8A1E681);
P(B, C, D, A, 4, 20, 0xE7D3FBC8);
P(A, B, C, D, 9, 5, 0x21E1CDE6);
P(D, A, B, C, 14, 9, 0xC33707D6);
P(C, D, A, B, 3, 14, 0xF4D50D87);
P(B, C, D, A, 8, 20, 0x455A14ED);
P(A, B, C, D, 13, 5, 0xA9E3E905);
P(D, A, B, C, 2, 9, 0xFCEFA3F8);
P(C, D, A, B, 7, 14, 0x676F02D9);
P(B, C, D, A, 12, 20, 0x8D2A4C8A);
#undef F
#define F(x,y,z) (x ^ y ^ z)
P(A, B, C, D, 5, 4, 0xFFFA3942);
P(D, A, B, C, 8, 11, 0x8771F681);
P(C, D, A, B, 11, 16, 0x6D9D6122);
P(B, C, D, A, 14, 23, 0xFDE5380C);
P(A, B, C, D, 1, 4, 0xA4BEEA44);
P(D, A, B, C, 4, 11, 0x4BDECFA9);
P(C, D, A, B, 7, 16, 0xF6BB4B60);
P(B, C, D, A, 10, 23, 0xBEBFBC70);
P(A, B, C, D, 13, 4, 0x289B7EC6);
P(D, A, B, C, 0, 11, 0xEAA127FA);
P(C, D, A, B, 3, 16, 0xD4EF3085);
P(B, C, D, A, 6, 23, 0x04881D05);
P(A, B, C, D, 9, 4, 0xD9D4D039);
P(D, A, B, C, 12, 11, 0xE6DB99E5);
P(C, D, A, B, 15, 16, 0x1FA27CF8);
P(B, C, D, A, 2, 23, 0xC4AC5665);
#undef F
#define F(x,y,z) (y ^ (x | ~z))
P(A, B, C, D, 0, 6, 0xF4292244);
P(D, A, B, C, 7, 10, 0x432AFF97);
P(C, D, A, B, 14, 15, 0xAB9423A7);
P(B, C, D, A, 5, 21, 0xFC93A039);
P(A, B, C, D, 12, 6, 0x655B59C3);
P(D, A, B, C, 3, 10, 0x8F0CCC92);
P(C, D, A, B, 10, 15, 0xFFEFF47D);
P(B, C, D, A, 1, 21, 0x85845DD1);
P(A, B, C, D, 8, 6, 0x6FA87E4F);
P(D, A, B, C, 15, 10, 0xFE2CE6E0);
P(C, D, A, B, 6, 15, 0xA3014314);
P(B, C, D, A, 13, 21, 0x4E0811A1);
P(A, B, C, D, 4, 6, 0xF7537E82);
P(D, A, B, C, 11, 10, 0xBD3AF235);
P(C, D, A, B, 2, 15, 0x2AD7D2BB);
P(B, C, D, A, 9, 21, 0xEB86D391);
#undef F
ctx->state[0] += A;
ctx->state[1] += B;
ctx->state[2] += C;
ctx->state[3] += D;
return (0);
}
/*
* MD5 process buffer
*/
int32_t utils_md5_update(utils_md5_context_t *ctx,
const unsigned char *input,
uint32_t ilen)
{
int32_t ret;
uint32_t fill;
uint32_t left;
if (ilen == 0) {
return (0);
}
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += (uint32_t) ilen;
ctx->total[0] &= 0xFFFFFFFF;
if (ctx->total[0] < (uint32_t) ilen) {
ctx->total[1]++;
}
if (left && ilen >= fill) {
memcpy((void *)(ctx->buffer + left), input, fill);
if ((ret = utils_internal_md5_process(ctx, ctx->buffer)) != 0) {
return (ret);
}
input += fill;
ilen -= fill;
left = 0;
}
while (ilen >= 64) {
if ((ret = utils_internal_md5_process(ctx, input)) != 0) {
return (ret);
}
input += 64;
ilen -= 64;
}
if (ilen > 0) {
memcpy((void *)(ctx->buffer + left), input, ilen);
}
return (0);
}
/*
* MD5 final digest
*/
int32_t utils_md5_finish(utils_md5_context_t *ctx,
unsigned char output[16])
{
int32_t ret;
uint32_t used;
uint32_t high, low;
/*
* Add padding: 0x80 then 0x00 until 8 bytes remain for the length
*/
used = ctx->total[0] & 0x3F;
ctx->buffer[used++] = 0x80;
if (used <= 56) {
/* Enough room for padding + length in current block */
memset(ctx->buffer + used, 0, 56 - used);
} else {
/* We'll need an extra block */
memset(ctx->buffer + used, 0, 64 - used);
if ((ret = utils_internal_md5_process(ctx, ctx->buffer)) != 0) {
return (ret);
}
memset(ctx->buffer, 0, 56);
}
/*
* Add message length
*/
high = (ctx->total[0] >> 29)
| (ctx->total[1] << 3);
low = (ctx->total[0] << 3);
PUT_UINT32_LE(low, ctx->buffer, 56);
PUT_UINT32_LE(high, ctx->buffer, 60);
if ((ret = utils_internal_md5_process(ctx, ctx->buffer)) != 0) {
return (ret);
}
/*
* Output final state
*/
PUT_UINT32_LE(ctx->state[0], output, 0);
PUT_UINT32_LE(ctx->state[1], output, 4);
PUT_UINT32_LE(ctx->state[2], output, 8);
PUT_UINT32_LE(ctx->state[3], output, 12);
return (0);
}

View File

@@ -0,0 +1,136 @@
#ifndef __OTA_MD5_H__
#define __OTA_MD5_H__
#if defined(__cplusplus)
extern "C" {
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stddef.h>
/**
* \brief MD5 context structure
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
typedef struct {
uint32_t total[2]; /*!< number of bytes processed */
uint32_t state[4]; /*!< intermediate digest state */
unsigned char buffer[64]; /*!< data block being processed */
} utils_md5_context_t;
/**
* \brief Initialize MD5 context
*
* \param ctx MD5 context to be initialized
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
void utils_md5_init(utils_md5_context_t *ctx);
/**
* \brief Clear MD5 context
*
* \param ctx MD5 context to be cleared
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
void utils_md5_free(utils_md5_context_t *ctx);
/**
* \brief MD5 context setup
*
* \param ctx context to be initialized
*
* \return 0 if successful
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
int32_t utils_md5_starts(utils_md5_context_t *ctx);
/**
* \brief MD5 process buffer
*
* \param ctx MD5 context
* \param input buffer holding the data
* \param ilen length of the input data
*
* \return 0 if successful
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
int32_t utils_md5_update(utils_md5_context_t *ctx,
const unsigned char *input,
uint32_t ilen);
/**
* \brief MD5 final digest
*
* \param ctx MD5 context
* \param output MD5 checksum result
*
* \return 0 if successful
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
int32_t utils_md5_finish(utils_md5_context_t *ctx,
unsigned char output[16]);
/**
* \brief MD5 process data block (internal use only)
*
* \param ctx MD5 context
* \param data buffer holding one block of data
*
* \return 0 if successful
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
int32_t utils_internal_md5_process(utils_md5_context_t *ctx,
const unsigned char data[64]);
/**
* \brief Output = MD5( input buffer )
*
* \param input buffer holding the data
* \param ilen length of the input data
* \param output MD5 checksum result
*
* \return 0 if successful
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
#if defined(__cplusplus)
}
#endif
#endif /* __OTA_MD5_H__ */

View File

@@ -0,0 +1,116 @@
#ifndef __OTA_PRIVATE_H__
#define __OTA_PRIVATE_H__
#if defined(__cplusplus)
extern "C" {
#endif
#include "core_stdinc.h"
#include "core_http.h"
#include "aiot_ota_api.h"
#define OTA_VERSION_TOPIC_PREFIX "/ota/device/inform"
#define OTA_PROGRESS_TOPIC_PREFIX "/ota/device/progress"
#define OTA_MODULE_NAME "OTA"
#define DOWNLOAD_MODULE_NAME "DOWNLOAD"
#define OTA_DEFAULT_DOWNLOAD_BUFLEN (2 * 1024)
#define OTA_DEFAULT_DOWNLOAD_TIMEOUT_MS (5 * 1000)
#define OTA_FOTA_TOPIC "/ota/device/upgrade/+/+"
#define OTA_FOTA_TOPIC_PREFIX "/ota/device/upgrade"
#define OTA_COTA_PUSH_TOPIC "/sys/+/+/thing/config/push"
#define OTA_COTA_PUSH_TOPIC_POSTFIX "/thing/config/push"
#define OTA_COTA_GET_REPLY_TOPIC "/sys/+/+/thing/config/get_reply"
#define OTA_COTA_GET_REPLY_TOPIC_POSTFIX "/thing/config/get_reply"
#define OTA_COTA_TOPIC_PREFIX "/sys/"
#define OTA_GET_TOPIC_PREFIX "/sys"
#define OTA_GET_TOPIC_SUFFIX "thing/ota/firmware/get"
#define OTA_GET_REPLY_TOPIC_SUFFIX "thing/ota/firmware/get_reply"
#define OTA_OTA_GET_REPLY_TOPIC "/sys/+/+/thing/ota/firmware/get_reply"
#define OTA_HTTPCLIENT_MAX_URL_LEN (256)
#define OTA_MAX_DIGIT_NUM_OF_UINT32 (20)
#define OTA_RESPONSE_PARTIAL (206)
#define OTA_RESPONSE_OK (200)
#define OTA_TOPIC_NUM (4)
#define OTA_MD5_LEN (32)
#define OTA_SHA256_LEN (64)
typedef enum {
DOWNLOAD_STATUS_START,
DOWNLOAD_STATUS_FETCH,
DOWNLOAD_STATUS_RENEWAL,
} download_status_t;
typedef enum {
OTA_TYPE_FOTA,
OTA_TYPE_CONFIG_PUSH,
OTA_TYPE_CONFIG_GET,
} ota_type_t;
/**
* @brief OTA过程中处理mqtt消息的句柄, 该句柄主要用于通过mqtt协议从云端收取固件升级消息, 包括固件的url等
*
*/
typedef struct {
void *userdata; /* 组件调用recv_handler的入参之一, 传入用户数据 */
aiot_ota_recv_handler_t recv_handler; /* OTA的mqtt消息到达设备端时, 通知用户的回调 */
aiot_sysdep_portfile_t *sysdep;
/*---- 以上都是用户在API可配 ----*/
/*---- 以下都是OTA内部使用, 用户无感知 ----*/
void *mqtt_handle;
void *module;
void *data_mutex;
} ota_handle_t;
/**
* @brief 处理下载任务的句柄, 该句柄主要用于通过http协议从指定的url下载固件
*
*/
typedef struct {
void
*userdata; /* 组件调用recv_handler 时的入参之一, 传入用户数据 */
aiot_download_recv_handler_t recv_handler; /* 设备收到分段的固件报文时的回调函数 */
aiot_download_task_desc_t *task_desc; /* 某次下载活动的目标描述信息, 如URL等 */
aiot_sysdep_portfile_t *sysdep;
uint32_t range_start;
uint32_t range_end;
/*---- 以上都是用户在API可配 ----*/
/*---- 以下都是downloader内部使用, 用户无感知 ----*/
uint8_t download_status;
void *http_handle;
uint32_t size_fetched;
uint32_t range_size_fetched;
uint32_t content_len;
int32_t percent;
int32_t http_rsp_status_code;
void *digest_ctx;
void *data_mutex;
void *recv_mutex;
} download_handle_t;
typedef struct {
char *pos;
int len;
} ota_list_json;
#define OTA_ARRAY_MAX (20)
void *_download_deep_copy_task_desc(aiot_sysdep_portfile_t *sysdep, void *data);
int32_t _download_deep_free_task_desc(aiot_sysdep_portfile_t *sysdep, void *data);
int32_t _ota_publish_base(void *handle, char *topic_prefix, char *product_key, char *device_name, char *suffix,
char *params);
#if defined(__cplusplus)
}
#endif
#endif /* __OTA_PRIVATE_H__ */