update qcloud sdk
1. iot-hub sdk update to 3.2.0 2. iot-explorer update to 3.1.1
This commit is contained in:
496
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/dynreg/dynreg.c
vendored
Normal file
496
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/dynreg/dynreg.c
vendored
Normal file
@@ -0,0 +1,496 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "lite-utils.h"
|
||||
#include "qcloud_iot_ca.h"
|
||||
#include "qcloud_iot_common.h"
|
||||
#include "qcloud_iot_device.h"
|
||||
#include "qcloud_iot_export.h"
|
||||
#include "qcloud_iot_import.h"
|
||||
#include "utils_aes.h"
|
||||
#include "utils_base64.h"
|
||||
#include "utils_hmac.h"
|
||||
#include "utils_httpc.h"
|
||||
|
||||
#define REG_URL_MAX_LEN (128)
|
||||
#define DYN_REG_SIGN_LEN (64)
|
||||
#define DYN_BUFF_DATA_MORE (10)
|
||||
#define BASE64_ENCODE_OUT_LEN(x) (((x + 3) * 4) / 3)
|
||||
#define DYN_REG_RES_HTTP_TIMEOUT_MS (2000)
|
||||
|
||||
#ifdef AUTH_MODE_CERT
|
||||
#define DYN_RESPONSE_BUFF_LEN (5 * 1024)
|
||||
#define DECODE_BUFF_LEN (5 * 1024)
|
||||
#else
|
||||
#define DYN_RESPONSE_BUFF_LEN (256)
|
||||
#define DECODE_BUFF_LEN (256)
|
||||
#endif
|
||||
|
||||
/* Knuth's TAOCP section 3.6 */
|
||||
#define M ((1U << 31) - 1)
|
||||
#define A 48271
|
||||
#define Q 44488 // M/A
|
||||
#define R 3399 // M%A; R < Q !!!
|
||||
|
||||
#define CODE_RESAULT "code"
|
||||
#define ENCRYPT_TYPE "encryptionType"
|
||||
#define PSK_DATA "psk"
|
||||
#define CERT_DATA "clientCert"
|
||||
#define KEY_DATA "clientKey"
|
||||
|
||||
typedef enum {
|
||||
eCERT_TYPE = 1,
|
||||
ePSK_TYPE = 2,
|
||||
} eAuthType;
|
||||
|
||||
/*Global value*/
|
||||
static unsigned int _seed = 1;
|
||||
|
||||
int rand_r(unsigned int *seed)
|
||||
{
|
||||
int32_t X;
|
||||
|
||||
X = *seed;
|
||||
X = A * (X % Q) - R * (int32_t)(X / Q);
|
||||
if (X < 0)
|
||||
X += M;
|
||||
|
||||
*seed = X;
|
||||
return X;
|
||||
}
|
||||
|
||||
int rand_d(void)
|
||||
{
|
||||
return rand_r(&_seed);
|
||||
}
|
||||
|
||||
void srand_d(unsigned int i)
|
||||
{
|
||||
_seed = i;
|
||||
}
|
||||
|
||||
static int _get_json_resault_code(char *json)
|
||||
{
|
||||
int resault = -1;
|
||||
char *v = LITE_json_value_of(CODE_RESAULT, json);
|
||||
|
||||
if (v == NULL) {
|
||||
Log_e("Invalid json content: %s", json);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (LITE_get_int32(&resault, v) != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("Invalid json content: %s", json);
|
||||
HAL_Free(v);
|
||||
return -1;
|
||||
}
|
||||
|
||||
HAL_Free(v);
|
||||
|
||||
return resault;
|
||||
}
|
||||
|
||||
static int _get_json_encry_type(char *json)
|
||||
{
|
||||
int type = -1;
|
||||
char *v = LITE_json_value_of(ENCRYPT_TYPE, json);
|
||||
|
||||
if (v == NULL) {
|
||||
Log_e("Get encry type fail, %s", json);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (LITE_get_int32(&type, v) != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("Invalid json content: %s", json);
|
||||
HAL_Free(v);
|
||||
return -1;
|
||||
}
|
||||
|
||||
HAL_Free(v);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
#ifndef AUTH_MODE_CERT
|
||||
|
||||
static char *_get_json_psk(char *json)
|
||||
{
|
||||
char *psk = LITE_json_value_of(PSK_DATA, json);
|
||||
|
||||
if (psk == NULL) {
|
||||
Log_e("Get psk fail: %s", json);
|
||||
}
|
||||
|
||||
return psk;
|
||||
}
|
||||
|
||||
#else
|
||||
static char *_get_json_cert_data(char *json)
|
||||
{
|
||||
char *cert = LITE_json_value_of(CERT_DATA, json);
|
||||
|
||||
if (cert == NULL) {
|
||||
Log_e("Get clientCert fail: %s", json);
|
||||
}
|
||||
|
||||
return cert;
|
||||
}
|
||||
|
||||
static char *_get_json_key_data(char *json)
|
||||
{
|
||||
char *key = LITE_json_value_of(KEY_DATA, json);
|
||||
|
||||
if (key == NULL) {
|
||||
Log_e("Get clientCert fail: %s", json);
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/*\\n in data change to '\n'*/
|
||||
static void _deal_transfer(char *data, uint32_t dataLen)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dataLen; i++) {
|
||||
if ((data[i] == '\\') && (data[i + 1] == 'n')) {
|
||||
data[i] = ' ';
|
||||
data[i + 1] = '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int _cert_file_save(const char *fileName, char *data, uint32_t dataLen)
|
||||
{
|
||||
FILE * fp;
|
||||
char filePath[FILE_PATH_MAX_LEN];
|
||||
uint32_t len;
|
||||
int Ret = QCLOUD_ERR_FAILURE;
|
||||
|
||||
memset(filePath, 0, FILE_PATH_MAX_LEN);
|
||||
HAL_Snprintf(filePath, FILE_PATH_MAX_LEN, "./certs/%s", fileName);
|
||||
|
||||
if ((fp = fopen(filePath, "w+")) == NULL) {
|
||||
Log_e("fail to open file %s", fileName);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
_deal_transfer(data, dataLen);
|
||||
len = fprintf(fp, "%s", data);
|
||||
fclose(fp);
|
||||
|
||||
if (len == dataLen) {
|
||||
Log_d("save %s file succes", fileName);
|
||||
Ret = QCLOUD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
exit:
|
||||
return Ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int _parse_devinfo(char *jdoc, DeviceInfo *pDevInfo)
|
||||
{
|
||||
int ret = 0;
|
||||
size_t len;
|
||||
int datalen;
|
||||
int enType;
|
||||
unsigned int keybits;
|
||||
char key[UTILS_AES_BLOCK_LEN + 1];
|
||||
char decodeBuff[DECODE_BUFF_LEN] = {0};
|
||||
unsigned char iv[16];
|
||||
char * payload = NULL;
|
||||
|
||||
#ifdef AUTH_MODE_CERT
|
||||
char *clientCert;
|
||||
char *clientKey;
|
||||
#else
|
||||
char *psk;
|
||||
#endif
|
||||
|
||||
Log_d("recv: %s", jdoc);
|
||||
|
||||
ret = _get_json_resault_code(jdoc);
|
||||
if (QCLOUD_RET_SUCCESS != ret) {
|
||||
Log_e("response err, ret:%d", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
payload = LITE_json_value_of("payload", jdoc);
|
||||
if (payload == NULL) {
|
||||
Log_e("Invalid json content: %s", jdoc);
|
||||
ret = QCLOUD_ERR_FAILURE;
|
||||
goto exit;
|
||||
} else {
|
||||
Log_d("payload:%s", payload);
|
||||
}
|
||||
|
||||
ret = qcloud_iot_utils_base64decode((uint8_t *)decodeBuff, sizeof(decodeBuff), &len, (uint8_t *)payload,
|
||||
strlen(payload));
|
||||
if (ret != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("Response decode err, response:%s", payload);
|
||||
ret = QCLOUD_ERR_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
datalen = len + (UTILS_AES_BLOCK_LEN - len % UTILS_AES_BLOCK_LEN);
|
||||
keybits = AES_KEY_BITS_128;
|
||||
memset(key, 0, UTILS_AES_BLOCK_LEN);
|
||||
strncpy(key, pDevInfo->product_secret, UTILS_AES_BLOCK_LEN);
|
||||
memset(iv, '0', UTILS_AES_BLOCK_LEN);
|
||||
ret = utils_aes_cbc((uint8_t *)decodeBuff, datalen, (uint8_t *)decodeBuff, DECODE_BUFF_LEN, UTILS_AES_DECRYPT,
|
||||
(uint8_t *)key, keybits, iv);
|
||||
if (QCLOUD_RET_SUCCESS == ret) {
|
||||
// Log_d("The decrypted data is:%s", decodeBuff);
|
||||
|
||||
} else {
|
||||
Log_e("data decry err,ret:%d", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
enType = _get_json_encry_type(decodeBuff);
|
||||
if (enType < 0) {
|
||||
Log_e("invlid encryt type, decrypt maybe faild");
|
||||
ret = QCLOUD_ERR_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
#ifdef AUTH_MODE_CERT
|
||||
if (eCERT_TYPE != enType) {
|
||||
Log_e("encryt type should be cert type");
|
||||
ret = QCLOUD_ERR_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
clientCert = _get_json_cert_data(decodeBuff);
|
||||
if (NULL != clientCert) {
|
||||
memset(pDevInfo->dev_cert_file_name, 0, MAX_SIZE_OF_DEVICE_CERT_FILE_NAME);
|
||||
HAL_Snprintf(pDevInfo->dev_cert_file_name, MAX_SIZE_OF_DEVICE_CERT_FILE_NAME, "%s_cert.crt",
|
||||
pDevInfo->device_name);
|
||||
if (QCLOUD_RET_SUCCESS != _cert_file_save(pDevInfo->dev_cert_file_name, clientCert, strlen(clientCert))) {
|
||||
Log_e("save %s file fail", pDevInfo->dev_cert_file_name);
|
||||
ret = QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
HAL_Free(clientCert);
|
||||
|
||||
} else {
|
||||
Log_e("Get clientCert data fail");
|
||||
ret = QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
clientKey = _get_json_key_data(decodeBuff);
|
||||
if (NULL != clientKey) {
|
||||
memset(pDevInfo->dev_key_file_name, 0, MAX_SIZE_OF_DEVICE_SECRET_FILE_NAME);
|
||||
HAL_Snprintf(pDevInfo->dev_key_file_name, MAX_SIZE_OF_DEVICE_SECRET_FILE_NAME, "%s_private.key",
|
||||
pDevInfo->device_name);
|
||||
if (QCLOUD_RET_SUCCESS != _cert_file_save(pDevInfo->dev_key_file_name, clientKey, strlen(clientKey))) {
|
||||
Log_e("save %s file fail", pDevInfo->dev_key_file_name);
|
||||
ret = QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
HAL_Free(clientKey);
|
||||
|
||||
} else {
|
||||
Log_e("Get clientCert data fail");
|
||||
ret = QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
#else
|
||||
if (ePSK_TYPE != enType) {
|
||||
Log_e("encryt type should be psk type");
|
||||
ret = QCLOUD_ERR_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
psk = _get_json_psk(decodeBuff);
|
||||
if (NULL != psk) {
|
||||
if (strlen(psk) > MAX_SIZE_OF_DEVICE_SECRET) {
|
||||
Log_e("psk exceed max len,%s", psk);
|
||||
strcpy(pDevInfo->device_secret, psk);
|
||||
} else {
|
||||
strncpy(pDevInfo->device_secret, psk, MAX_SIZE_OF_DEVICE_SECRET);
|
||||
pDevInfo->device_secret[MAX_SIZE_OF_DEVICE_SECRET] = '\0';
|
||||
}
|
||||
HAL_Free(psk);
|
||||
} else {
|
||||
Log_e("Get psk data fail");
|
||||
}
|
||||
#endif
|
||||
exit:
|
||||
|
||||
if (payload) {
|
||||
HAL_Free(payload);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _post_reg_request_by_http(char *request_buf, DeviceInfo *pDevInfo)
|
||||
{
|
||||
int Ret = 0;
|
||||
HTTPClient http_client; /* http client */
|
||||
HTTPClientData http_data; /* http client data */
|
||||
|
||||
const char *url_format = "%s://%s/register/dev";
|
||||
char url[REG_URL_MAX_LEN] = {0};
|
||||
int port;
|
||||
const char *ca_crt = NULL;
|
||||
char respbuff[DYN_RESPONSE_BUFF_LEN];
|
||||
|
||||
/*format URL*/
|
||||
#ifndef AUTH_WITH_NOTLS
|
||||
HAL_Snprintf(url, REG_URL_MAX_LEN, url_format, "https", DYN_REG_SERVER_URL);
|
||||
port = DYN_REG_SERVER_PORT_TLS;
|
||||
ca_crt = iot_ca_get();
|
||||
#else
|
||||
HAL_Snprintf(url, REG_URL_MAX_LEN, url_format, "http", DYN_REG_SERVER_URL);
|
||||
port = DYN_REG_SERVER_PORT;
|
||||
#endif
|
||||
|
||||
memset((char *)&http_client, 0, sizeof(HTTPClient));
|
||||
memset((char *)&http_data, 0, sizeof(HTTPClientData));
|
||||
|
||||
http_client.header = "Accept: text/xml,application/json;*/*\r\n";
|
||||
|
||||
http_data.post_content_type = "application/x-www-form-urlencoded";
|
||||
http_data.post_buf = request_buf;
|
||||
http_data.post_buf_len = strlen(request_buf);
|
||||
|
||||
Ret = qcloud_http_client_common(&http_client, url, port, ca_crt, HTTP_POST, &http_data);
|
||||
if (QCLOUD_RET_SUCCESS != Ret) {
|
||||
Log_e("qcloud_http_client_common failed, Ret = %d", Ret);
|
||||
return Ret;
|
||||
}
|
||||
|
||||
memset(respbuff, 0, DYN_RESPONSE_BUFF_LEN);
|
||||
http_data.response_buf_len = DYN_RESPONSE_BUFF_LEN;
|
||||
http_data.response_buf = respbuff;
|
||||
|
||||
Ret = qcloud_http_recv_data(&http_client, DYN_REG_RES_HTTP_TIMEOUT_MS, &http_data);
|
||||
if (QCLOUD_RET_SUCCESS != Ret) {
|
||||
Log_e("dynamic register response fail, Ret = %d", Ret);
|
||||
} else {
|
||||
/*Parse dev info*/
|
||||
Ret = _parse_devinfo(http_data.response_buf, pDevInfo);
|
||||
if (QCLOUD_RET_SUCCESS != Ret) {
|
||||
Log_e("parse device info err");
|
||||
}
|
||||
}
|
||||
|
||||
qcloud_http_client_close(&http_client);
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
static int _cal_dynreg_sign(DeviceInfo *pDevInfo, char *signout, int max_signlen, int nonce, uint32_t timestamp)
|
||||
{
|
||||
int sign_len;
|
||||
size_t olen = 0;
|
||||
char * pSignSource = NULL;
|
||||
const char *sign_fmt = "deviceName=%s&nonce=%d&productId=%s×tamp=%d";
|
||||
char sign[DYN_REG_SIGN_LEN] = {0};
|
||||
|
||||
/*format sign data*/
|
||||
sign_len = strlen(sign_fmt) + strlen(pDevInfo->device_name) + strlen(pDevInfo->product_id) + sizeof(int) +
|
||||
sizeof(uint32_t) + DYN_BUFF_DATA_MORE;
|
||||
pSignSource = HAL_Malloc(sign_len);
|
||||
if (pSignSource == NULL) {
|
||||
Log_e("malloc sign source buff fail");
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
memset(pSignSource, 0, sign_len);
|
||||
HAL_Snprintf((char *)pSignSource, sign_len, sign_fmt, pDevInfo->device_name, nonce, pDevInfo->product_id,
|
||||
timestamp);
|
||||
|
||||
/*cal hmac sha1*/
|
||||
utils_hmac_sha1(pSignSource, strlen(pSignSource), sign, pDevInfo->product_secret, strlen(pDevInfo->product_secret));
|
||||
|
||||
/*base64 encode*/
|
||||
qcloud_iot_utils_base64encode((uint8_t *)signout, max_signlen, &olen, (const uint8_t *)sign, strlen(sign));
|
||||
|
||||
HAL_Free(pSignSource);
|
||||
|
||||
return (olen > max_signlen) ? QCLOUD_ERR_FAILURE : QCLOUD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
int IOT_DynReg_Device(DeviceInfo *pDevInfo)
|
||||
{
|
||||
const char *para_format =
|
||||
"{\"deviceName\":\"%s\",\"nonce\":%d,\"productId\":\"%s\",\"timestamp\":%d,\"signature\":\"%s\"}";
|
||||
int nonce;
|
||||
int Ret;
|
||||
uint32_t timestamp;
|
||||
int len;
|
||||
char sign[DYN_REG_SIGN_LEN] = {0};
|
||||
char * pRequest = NULL;
|
||||
|
||||
if (strlen(pDevInfo->product_secret) < UTILS_AES_BLOCK_LEN) {
|
||||
Log_e("product key inllegal");
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
srand_d(HAL_GetTimeMs());
|
||||
nonce = rand_d();
|
||||
timestamp = time(0);
|
||||
|
||||
/*cal sign*/
|
||||
if (QCLOUD_RET_SUCCESS == _cal_dynreg_sign(pDevInfo, sign, DYN_REG_SIGN_LEN, nonce, timestamp)) {
|
||||
Log_d("sign:%s", sign);
|
||||
} else {
|
||||
Log_e("cal sign fail");
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
/*format http request*/
|
||||
len = strlen(para_format) + strlen(pDevInfo->product_id) + strlen(pDevInfo->device_name) + sizeof(int) +
|
||||
sizeof(uint32_t) + strlen(sign) + DYN_BUFF_DATA_MORE;
|
||||
pRequest = HAL_Malloc(len);
|
||||
if (!pRequest) {
|
||||
Log_e("malloc request memory fail");
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
memset(pRequest, 0, len);
|
||||
HAL_Snprintf(pRequest, len, para_format, pDevInfo->device_name, nonce, pDevInfo->product_id, timestamp, sign);
|
||||
Log_d("request:%s", pRequest);
|
||||
|
||||
Log_d("resbuff len:%d", DYN_RESPONSE_BUFF_LEN);
|
||||
/*post request*/
|
||||
Ret = _post_reg_request_by_http(pRequest, pDevInfo);
|
||||
if (QCLOUD_RET_SUCCESS == Ret) {
|
||||
Log_d("request dev info success");
|
||||
} else {
|
||||
Log_e("request dev info fail");
|
||||
}
|
||||
|
||||
HAL_Free(pRequest);
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
318
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/gateway/gateway_api.c
vendored
Normal file
318
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/gateway/gateway_api.c
vendored
Normal file
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "gateway_common.h"
|
||||
#include "mqtt_client.h"
|
||||
#include "utils_param_check.h"
|
||||
|
||||
void _gateway_event_handler(void *client, void *context, MQTTEventMsg *msg)
|
||||
{
|
||||
uintptr_t packet_id = (uintptr_t)msg->msg;
|
||||
Gateway * gateway = (Gateway *)context;
|
||||
|
||||
POINTER_SANITY_CHECK_RTN(context);
|
||||
POINTER_SANITY_CHECK_RTN(msg);
|
||||
MQTTMessage *topic_info = (MQTTMessage *)msg->msg;
|
||||
|
||||
switch (msg->event_type) {
|
||||
case MQTT_EVENT_SUBCRIBE_SUCCESS:
|
||||
case MQTT_EVENT_UNSUBCRIBE_SUCCESS:
|
||||
Log_d("gateway sub|unsub(%d) success, packet-id=%u", msg->event_type, (unsigned int)packet_id);
|
||||
if (gateway->gateway_data.sync_status == packet_id) {
|
||||
gateway->gateway_data.sync_status = 0;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBCRIBE_TIMEOUT:
|
||||
case MQTT_EVENT_UNSUBCRIBE_TIMEOUT:
|
||||
case MQTT_EVENT_SUBCRIBE_NACK:
|
||||
case MQTT_EVENT_UNSUBCRIBE_NACK:
|
||||
Log_d("gateway timeout|nack(%d) event, packet-id=%u", msg->event_type, (unsigned int)packet_id);
|
||||
if (gateway->gateway_data.sync_status == packet_id) {
|
||||
gateway->gateway_data.sync_status = -1;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_PUBLISH_RECVEIVED:
|
||||
Log_d("gateway topic message arrived but without any related handle: topic=%.*s, topic_msg=%.*s",
|
||||
topic_info->topic_len, topic_info->ptopic, topic_info->payload_len, topic_info->payload);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (gateway->event_handle.h_fp != NULL) {
|
||||
gateway->event_handle.h_fp(client, gateway->event_handle.context, msg);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void *IOT_Gateway_Construct(GatewayInitParam *init_param)
|
||||
{
|
||||
int rc = 0;
|
||||
GatewayParam param = DEFAULT_GATEWAY_PARAMS;
|
||||
POINTER_SANITY_CHECK(init_param, NULL);
|
||||
|
||||
Gateway *gateway = (Gateway *)HAL_Malloc(sizeof(Gateway));
|
||||
if (gateway == NULL) {
|
||||
Log_e("gateway malloc failed");
|
||||
IOT_FUNC_EXIT_RC(NULL);
|
||||
}
|
||||
|
||||
memset(gateway, 0, sizeof(Gateway));
|
||||
|
||||
/* replace user event handle */
|
||||
gateway->event_handle.h_fp = init_param->init_param.event_handle.h_fp;
|
||||
gateway->event_handle.context = init_param->init_param.event_handle.context;
|
||||
|
||||
/* set _gateway_event_handler as mqtt event handle */
|
||||
init_param->init_param.event_handle.h_fp = _gateway_event_handler;
|
||||
init_param->init_param.event_handle.context = gateway;
|
||||
|
||||
/* construct MQTT client */
|
||||
gateway->mqtt = IOT_MQTT_Construct(&init_param->init_param);
|
||||
if (NULL == gateway->mqtt) {
|
||||
Log_e("construct MQTT failed");
|
||||
HAL_Free(gateway);
|
||||
IOT_FUNC_EXIT_RC(NULL);
|
||||
}
|
||||
|
||||
/* subscribe default topic */
|
||||
param.product_id = init_param->init_param.product_id;
|
||||
param.device_name = init_param->init_param.device_name;
|
||||
rc = gateway_subscribe_unsubscribe_default(gateway, ¶m);
|
||||
if (QCLOUD_RET_SUCCESS != rc) {
|
||||
Log_e("subscribe default topic failed");
|
||||
IOT_Gateway_Destroy((void *)gateway);
|
||||
IOT_FUNC_EXIT_RC(NULL);
|
||||
}
|
||||
|
||||
return (void *)gateway;
|
||||
}
|
||||
|
||||
int IOT_Gateway_Subdev_Online(void *client, GatewayParam *param)
|
||||
{
|
||||
int rc = 0;
|
||||
char topic[MAX_SIZE_OF_CLOUD_TOPIC + 1] = {0};
|
||||
char payload[GATEWAY_PAYLOAD_BUFFER_LEN + 1] = {0};
|
||||
int size = 0;
|
||||
SubdevSession *session = NULL;
|
||||
PublishParams params = DEFAULT_PUB_PARAMS;
|
||||
Gateway * gateway = (Gateway *)client;
|
||||
|
||||
POINTER_SANITY_CHECK(gateway, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(param, QCLOUD_ERR_INVAL);
|
||||
|
||||
STRING_PTR_SANITY_CHECK(param->product_id, QCLOUD_ERR_INVAL);
|
||||
STRING_PTR_SANITY_CHECK(param->device_name, QCLOUD_ERR_INVAL);
|
||||
STRING_PTR_SANITY_CHECK(param->subdev_product_id, QCLOUD_ERR_INVAL);
|
||||
STRING_PTR_SANITY_CHECK(param->subdev_device_name, QCLOUD_ERR_INVAL);
|
||||
|
||||
session = subdev_find_session(gateway, param->subdev_product_id, param->subdev_device_name);
|
||||
if (NULL == session) {
|
||||
Log_d("there is no session, create a new session");
|
||||
|
||||
/* create subdev session */
|
||||
session = subdev_add_session(gateway, param->subdev_product_id, param->subdev_device_name);
|
||||
if (NULL == session) {
|
||||
Log_e("create session error!");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_GATEWAY_CREATE_SESSION_FAIL);
|
||||
}
|
||||
} else {
|
||||
if (SUBDEV_SEESION_STATUS_ONLINE == session->session_status) {
|
||||
Log_i("device have online");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_GATEWAY_SUBDEV_ONLINE);
|
||||
}
|
||||
}
|
||||
|
||||
size = HAL_Snprintf(topic, MAX_SIZE_OF_CLOUD_TOPIC + 1, GATEWAY_TOPIC_OPERATION_FMT, param->product_id,
|
||||
param->device_name);
|
||||
if (size < 0 || size > MAX_SIZE_OF_CLOUD_TOPIC) {
|
||||
Log_e("buf size < topic length!");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
|
||||
size = HAL_Snprintf(payload, GATEWAY_PAYLOAD_BUFFER_LEN + 1, GATEWAY_PAYLOAD_STATUS_FMT, "online",
|
||||
param->subdev_product_id, param->subdev_device_name);
|
||||
if (size < 0 || size > GATEWAY_PAYLOAD_BUFFER_LEN) {
|
||||
Log_e("buf size < payload length!");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
|
||||
size = HAL_Snprintf(gateway->gateway_data.online.client_id, MAX_SIZE_OF_CLIENT_ID, GATEWAY_CLIENT_ID_FMT,
|
||||
param->subdev_product_id, param->subdev_device_name);
|
||||
if (size < 0 || size > MAX_SIZE_OF_CLIENT_ID) {
|
||||
Log_e("buf size < client_id length!");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
gateway->gateway_data.online.result = -1;
|
||||
|
||||
params.qos = QOS0;
|
||||
params.payload_len = strlen(payload);
|
||||
params.payload = (char *)payload;
|
||||
|
||||
/* publish packet */
|
||||
rc = gateway_publish_sync(gateway, topic, ¶ms, &gateway->gateway_data.online.result);
|
||||
if (QCLOUD_RET_SUCCESS != rc) {
|
||||
subdev_remove_session(gateway, param->subdev_product_id, param->subdev_device_name);
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
session->session_status = SUBDEV_SEESION_STATUS_ONLINE;
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
|
||||
}
|
||||
|
||||
int IOT_Gateway_Subdev_Offline(void *client, GatewayParam *param)
|
||||
{
|
||||
int rc = 0;
|
||||
char topic[MAX_SIZE_OF_CLOUD_TOPIC + 1] = {0};
|
||||
char payload[GATEWAY_PAYLOAD_BUFFER_LEN + 1] = {0};
|
||||
int size = 0;
|
||||
SubdevSession *session = NULL;
|
||||
Gateway * gateway = (Gateway *)client;
|
||||
|
||||
POINTER_SANITY_CHECK(gateway, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(param, QCLOUD_ERR_INVAL);
|
||||
|
||||
STRING_PTR_SANITY_CHECK(param->product_id, QCLOUD_ERR_INVAL);
|
||||
STRING_PTR_SANITY_CHECK(param->device_name, QCLOUD_ERR_INVAL);
|
||||
STRING_PTR_SANITY_CHECK(param->subdev_product_id, QCLOUD_ERR_INVAL);
|
||||
STRING_PTR_SANITY_CHECK(param->subdev_device_name, QCLOUD_ERR_INVAL);
|
||||
|
||||
session = subdev_find_session(gateway, param->subdev_product_id, param->subdev_device_name);
|
||||
if (NULL == session) {
|
||||
Log_d("no session, can not offline");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_GATEWAY_SESSION_NO_EXIST);
|
||||
}
|
||||
if (SUBDEV_SEESION_STATUS_OFFLINE == session->session_status) {
|
||||
Log_i("device have offline");
|
||||
/* free session */
|
||||
subdev_remove_session(gateway, param->subdev_product_id, param->subdev_device_name);
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_GATEWAY_SUBDEV_OFFLINE);
|
||||
}
|
||||
|
||||
size = HAL_Snprintf(topic, MAX_SIZE_OF_CLOUD_TOPIC + 1, GATEWAY_TOPIC_OPERATION_FMT, param->product_id,
|
||||
param->device_name);
|
||||
if (size < 0 || size > MAX_SIZE_OF_CLOUD_TOPIC) {
|
||||
Log_e("buf size < topic length!");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
|
||||
size = HAL_Snprintf(payload, GATEWAY_PAYLOAD_BUFFER_LEN + 1, GATEWAY_PAYLOAD_STATUS_FMT, "offline",
|
||||
param->subdev_product_id, param->subdev_device_name);
|
||||
if (size < 0 || size > GATEWAY_PAYLOAD_BUFFER_LEN) {
|
||||
Log_e("buf size < payload length!");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
|
||||
size = HAL_Snprintf(gateway->gateway_data.offline.client_id, MAX_SIZE_OF_CLIENT_ID, GATEWAY_CLIENT_ID_FMT,
|
||||
param->subdev_product_id, param->subdev_device_name);
|
||||
if (size < 0 || size > MAX_SIZE_OF_CLIENT_ID) {
|
||||
Log_e("buf size < client_id length!");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
gateway->gateway_data.offline.result = -1;
|
||||
|
||||
PublishParams params = DEFAULT_PUB_PARAMS;
|
||||
params.qos = QOS0;
|
||||
params.payload_len = strlen(payload);
|
||||
params.payload = (char *)payload;
|
||||
|
||||
/* publish packet */
|
||||
rc = gateway_publish_sync(gateway, topic, ¶ms, &gateway->gateway_data.offline.result);
|
||||
if (QCLOUD_RET_SUCCESS != rc) {
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
session->session_status = SUBDEV_SEESION_STATUS_OFFLINE;
|
||||
|
||||
/* free session */
|
||||
subdev_remove_session(gateway, param->subdev_product_id, param->subdev_device_name);
|
||||
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
|
||||
}
|
||||
|
||||
void *IOT_Gateway_Get_Mqtt_Client(void *handle)
|
||||
{
|
||||
POINTER_SANITY_CHECK(handle, NULL);
|
||||
|
||||
Gateway *gateway = (Gateway *)handle;
|
||||
|
||||
return gateway->mqtt;
|
||||
}
|
||||
|
||||
int IOT_Gateway_Destroy(void *client)
|
||||
{
|
||||
Gateway *gateway = (Gateway *)client;
|
||||
POINTER_SANITY_CHECK(gateway, QCLOUD_ERR_INVAL);
|
||||
|
||||
SubdevSession *cur_session = gateway->session_list;
|
||||
while (cur_session) {
|
||||
SubdevSession *session = cur_session;
|
||||
cur_session = cur_session->next;
|
||||
HAL_Free(session);
|
||||
}
|
||||
|
||||
IOT_MQTT_Destroy(&gateway->mqtt);
|
||||
HAL_Free(client);
|
||||
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS)
|
||||
}
|
||||
|
||||
int IOT_Gateway_Yield(void *client, uint32_t timeout_ms)
|
||||
{
|
||||
Gateway *gateway = (Gateway *)client;
|
||||
POINTER_SANITY_CHECK(gateway, QCLOUD_ERR_INVAL);
|
||||
|
||||
return IOT_MQTT_Yield(gateway->mqtt, timeout_ms);
|
||||
}
|
||||
|
||||
int IOT_Gateway_Subscribe(void *client, char *topic_filter, SubscribeParams *params)
|
||||
{
|
||||
Gateway *gateway = (Gateway *)client;
|
||||
POINTER_SANITY_CHECK(gateway, QCLOUD_ERR_INVAL);
|
||||
|
||||
return IOT_MQTT_Subscribe(gateway->mqtt, topic_filter, params);
|
||||
}
|
||||
|
||||
int IOT_Gateway_Unsubscribe(void *client, char *topic_filter)
|
||||
{
|
||||
Gateway *gateway = (Gateway *)client;
|
||||
POINTER_SANITY_CHECK(gateway, QCLOUD_ERR_INVAL);
|
||||
|
||||
return IOT_MQTT_Unsubscribe(gateway->mqtt, topic_filter);
|
||||
}
|
||||
|
||||
int IOT_Gateway_IsSubReady(void *client, char *topic_filter)
|
||||
{
|
||||
Gateway *gateway = (Gateway *)client;
|
||||
POINTER_SANITY_CHECK(gateway, QCLOUD_ERR_INVAL);
|
||||
|
||||
return IOT_MQTT_IsSubReady(gateway->mqtt, topic_filter);
|
||||
}
|
||||
|
||||
int IOT_Gateway_Publish(void *client, char *topic_name, PublishParams *params)
|
||||
{
|
||||
Gateway *gateway = (Gateway *)client;
|
||||
POINTER_SANITY_CHECK(gateway, QCLOUD_ERR_INVAL);
|
||||
|
||||
return IOT_MQTT_Publish(gateway->mqtt, topic_name, params);
|
||||
}
|
353
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/gateway/gateway_common.c
vendored
Normal file
353
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/gateway/gateway_common.c
vendored
Normal file
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
#include "gateway_common.h"
|
||||
|
||||
#include "lite-utils.h"
|
||||
#include "mqtt_client.h"
|
||||
|
||||
static bool get_json_type(char *json, char **v)
|
||||
{
|
||||
*v = LITE_json_value_of("type", json);
|
||||
return *v == NULL ? false : true;
|
||||
}
|
||||
|
||||
static bool get_json_devices(char *json, char **v)
|
||||
{
|
||||
*v = LITE_json_value_of("payload.devices", json);
|
||||
return *v == NULL ? false : true;
|
||||
}
|
||||
|
||||
static bool get_json_result(char *json, int32_t *res)
|
||||
{
|
||||
char *v = LITE_json_value_of("result", json);
|
||||
if (v == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (LITE_get_int32(res, v) != QCLOUD_RET_SUCCESS) {
|
||||
HAL_Free(v);
|
||||
return false;
|
||||
}
|
||||
HAL_Free(v);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool get_json_product_id(char *json, char **v)
|
||||
{
|
||||
*v = LITE_json_value_of("product_id", json);
|
||||
return *v == NULL ? false : true;
|
||||
}
|
||||
|
||||
static bool get_json_device_name(char *json, char **v)
|
||||
{
|
||||
*v = LITE_json_value_of("device_name", json);
|
||||
return *v == NULL ? false : true;
|
||||
}
|
||||
|
||||
static void _gateway_message_handler(void *client, MQTTMessage *message, void *user_data)
|
||||
{
|
||||
Qcloud_IoT_Client *mqtt = NULL;
|
||||
Gateway * gateway = NULL;
|
||||
char * topic = NULL;
|
||||
size_t topic_len = 0;
|
||||
int cloud_rcv_len = 0;
|
||||
char * type = NULL;
|
||||
char * devices = NULL, *devices_strip = NULL;
|
||||
char * product_id = NULL;
|
||||
char * device_name = NULL;
|
||||
int32_t result = 0;
|
||||
char client_id[MAX_SIZE_OF_CLIENT_ID + 1] = {0};
|
||||
int size = 0;
|
||||
|
||||
POINTER_SANITY_CHECK_RTN(client);
|
||||
POINTER_SANITY_CHECK_RTN(message);
|
||||
|
||||
mqtt = (Qcloud_IoT_Client *)client;
|
||||
gateway = (Gateway *)mqtt->event_handle.context;
|
||||
POINTER_SANITY_CHECK_RTN(gateway);
|
||||
|
||||
topic = (char *)message->ptopic;
|
||||
topic_len = message->topic_len;
|
||||
if (NULL == topic || topic_len == 0) {
|
||||
Log_e("topic == NULL or topic_len == 0.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (message->payload_len > GATEWAY_RECEIVE_BUFFER_LEN) {
|
||||
Log_e("message->payload_len > GATEWAY_RECEIVE_BUFFER_LEN.");
|
||||
return;
|
||||
}
|
||||
|
||||
cloud_rcv_len = Min(GATEWAY_RECEIVE_BUFFER_LEN - 1, message->payload_len);
|
||||
char *json_buf = gateway->recv_buf;
|
||||
memcpy(gateway->recv_buf, message->payload, cloud_rcv_len);
|
||||
json_buf[cloud_rcv_len] = '\0'; // jsmn_parse relies on a string
|
||||
|
||||
if (!get_json_type(json_buf, &type)) {
|
||||
Log_e("Fail to parse type from msg: %s", json_buf);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!get_json_devices(json_buf, &devices)) {
|
||||
Log_e("Fail to parse devices from msg: %s", json_buf);
|
||||
HAL_Free(type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (devices[0] == '[') {
|
||||
devices_strip = devices + 1;
|
||||
} else {
|
||||
devices_strip = devices;
|
||||
}
|
||||
|
||||
if (!get_json_result(devices_strip, &result)) {
|
||||
Log_e("Fail to parse result from msg: %s", json_buf);
|
||||
HAL_Free(type);
|
||||
HAL_Free(devices);
|
||||
return;
|
||||
}
|
||||
if (!get_json_product_id(devices_strip, &product_id)) {
|
||||
Log_e("Fail to parse product_id from msg: %s", json_buf);
|
||||
HAL_Free(type);
|
||||
HAL_Free(devices);
|
||||
return;
|
||||
}
|
||||
if (!get_json_device_name(devices_strip, &device_name)) {
|
||||
Log_e("Fail to parse device_name from msg: %s", json_buf);
|
||||
HAL_Free(type);
|
||||
HAL_Free(devices);
|
||||
HAL_Free(product_id);
|
||||
return;
|
||||
}
|
||||
|
||||
size = HAL_Snprintf(client_id, MAX_SIZE_OF_CLIENT_ID + 1, GATEWAY_CLIENT_ID_FMT, product_id, device_name);
|
||||
if (size < 0 || size > MAX_SIZE_OF_CLIENT_ID) {
|
||||
Log_e("generate client_id fail.");
|
||||
HAL_Free(type);
|
||||
HAL_Free(devices);
|
||||
HAL_Free(product_id);
|
||||
HAL_Free(device_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strncmp(type, "online", sizeof("online") - 1) == 0) {
|
||||
if (strncmp(client_id, gateway->gateway_data.online.client_id, size) == 0) {
|
||||
Log_i("client_id(%s), online success. result %d", client_id, result);
|
||||
gateway->gateway_data.online.result = result;
|
||||
}
|
||||
} else if (strncmp(type, "offline", sizeof("offline") - 1) == 0) {
|
||||
if (strncmp(client_id, gateway->gateway_data.offline.client_id, size) == 0) {
|
||||
Log_i("client_id(%s), offline success. result %d", client_id, result);
|
||||
gateway->gateway_data.offline.result = result;
|
||||
}
|
||||
}
|
||||
|
||||
HAL_Free(type);
|
||||
HAL_Free(devices);
|
||||
HAL_Free(product_id);
|
||||
HAL_Free(device_name);
|
||||
return;
|
||||
}
|
||||
|
||||
int gateway_subscribe_unsubscribe_topic(Gateway *gateway, char *topic_filter, SubscribeParams *params, int is_subscribe)
|
||||
{
|
||||
int rc = 0;
|
||||
int loop_count = 0;
|
||||
uint32_t status = -1;
|
||||
|
||||
POINTER_SANITY_CHECK(gateway, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(params, QCLOUD_ERR_INVAL);
|
||||
|
||||
STRING_PTR_SANITY_CHECK(topic_filter, QCLOUD_ERR_INVAL);
|
||||
|
||||
params->qos = QOS1;
|
||||
gateway->gateway_data.sync_status = status;
|
||||
|
||||
if (is_subscribe) {
|
||||
/* subscribe */
|
||||
rc = IOT_MQTT_Subscribe(gateway->mqtt, topic_filter, params);
|
||||
} else {
|
||||
/* unsubscribe */
|
||||
rc = IOT_MQTT_Unsubscribe(gateway->mqtt, topic_filter);
|
||||
}
|
||||
|
||||
if (rc < 0) {
|
||||
Log_e("subscribe or un(%d), result(%d)", is_subscribe, rc);
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
gateway->gateway_data.sync_status = status = rc;
|
||||
while (status == gateway->gateway_data.sync_status) {
|
||||
if (loop_count > GATEWAY_LOOP_MAX_COUNT) {
|
||||
Log_i("loop max count, time out");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
|
||||
IOT_Gateway_Yield(gateway, 200);
|
||||
loop_count++;
|
||||
}
|
||||
|
||||
if (gateway->gateway_data.sync_status != 0) {
|
||||
Log_e("gateway->gateway_data.sync_status(%u) != 0", gateway->gateway_data.sync_status);
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
|
||||
}
|
||||
|
||||
int gateway_subscribe_unsubscribe_default(Gateway *gateway, GatewayParam *param)
|
||||
{
|
||||
int rc = 0;
|
||||
int size = 0;
|
||||
char topic_filter[MAX_SIZE_OF_CLOUD_TOPIC + 1] = {0};
|
||||
SubscribeParams subscribe_params = DEFAULT_SUB_PARAMS;
|
||||
|
||||
POINTER_SANITY_CHECK(param, QCLOUD_ERR_INVAL);
|
||||
|
||||
STRING_PTR_SANITY_CHECK(param->product_id, QCLOUD_ERR_INVAL);
|
||||
STRING_PTR_SANITY_CHECK(param->device_name, QCLOUD_ERR_INVAL);
|
||||
|
||||
// subscribe online/offline operation reslut
|
||||
size = HAL_Snprintf(topic_filter, MAX_SIZE_OF_CLOUD_TOPIC + 1, GATEWAY_TOPIC_OPERATION_RESULT_FMT,
|
||||
param->product_id, param->device_name);
|
||||
if (size < 0 || size > MAX_SIZE_OF_CLOUD_TOPIC) {
|
||||
Log_e("buf size < topic length!");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
subscribe_params.on_message_handler = _gateway_message_handler;
|
||||
rc = gateway_subscribe_unsubscribe_topic(gateway, topic_filter, &subscribe_params, IOT_TRUE);
|
||||
if (QCLOUD_RET_SUCCESS != rc) {
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
|
||||
}
|
||||
|
||||
SubdevSession *subdev_find_session(Gateway *gateway, char *product_id, char *device_name)
|
||||
{
|
||||
SubdevSession *session = NULL;
|
||||
|
||||
POINTER_SANITY_CHECK(gateway, NULL);
|
||||
STRING_PTR_SANITY_CHECK(product_id, NULL);
|
||||
STRING_PTR_SANITY_CHECK(device_name, NULL);
|
||||
|
||||
session = gateway->session_list;
|
||||
|
||||
/* session is exist */
|
||||
while (session) {
|
||||
if (0 == strncmp(session->product_id, product_id, strlen(product_id)) &&
|
||||
0 == strncmp(session->device_name, device_name, strlen(device_name))) {
|
||||
IOT_FUNC_EXIT_RC(session);
|
||||
}
|
||||
session = session->next;
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(NULL);
|
||||
}
|
||||
|
||||
SubdevSession *subdev_add_session(Gateway *gateway, char *product_id, char *device_name)
|
||||
{
|
||||
SubdevSession *session = NULL;
|
||||
|
||||
POINTER_SANITY_CHECK(gateway, NULL);
|
||||
STRING_PTR_SANITY_CHECK(product_id, NULL);
|
||||
STRING_PTR_SANITY_CHECK(device_name, NULL);
|
||||
|
||||
session = HAL_Malloc(sizeof(SubdevSession));
|
||||
if (session == NULL) {
|
||||
Log_e("Not enough memory");
|
||||
IOT_FUNC_EXIT_RC(NULL);
|
||||
}
|
||||
|
||||
memset(session, 0, sizeof(SubdevSession));
|
||||
/* add session to list */
|
||||
session->next = gateway->session_list;
|
||||
gateway->session_list = session;
|
||||
|
||||
int size = strlen(product_id);
|
||||
strncpy(session->product_id, product_id, size);
|
||||
session->product_id[size] = '\0';
|
||||
size = strlen(device_name);
|
||||
strncpy(session->device_name, device_name, size);
|
||||
session->device_name[size] = '\0';
|
||||
session->session_status = SUBDEV_SEESION_STATUS_INIT;
|
||||
|
||||
IOT_FUNC_EXIT_RC(session);
|
||||
}
|
||||
|
||||
int subdev_remove_session(Gateway *gateway, char *product_id, char *device_name)
|
||||
{
|
||||
SubdevSession *cur_session = NULL;
|
||||
SubdevSession *pre_session = NULL;
|
||||
|
||||
POINTER_SANITY_CHECK(gateway, QCLOUD_ERR_FAILURE);
|
||||
STRING_PTR_SANITY_CHECK(product_id, QCLOUD_ERR_FAILURE);
|
||||
STRING_PTR_SANITY_CHECK(device_name, QCLOUD_ERR_FAILURE);
|
||||
|
||||
pre_session = cur_session = gateway->session_list;
|
||||
|
||||
if (NULL == cur_session) {
|
||||
Log_e("session list is empty");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
|
||||
}
|
||||
|
||||
/* session is exist */
|
||||
while (cur_session) {
|
||||
if (0 == strncmp(cur_session->product_id, product_id, strlen(product_id)) &&
|
||||
0 == strncmp(cur_session->device_name, device_name, strlen(device_name))) {
|
||||
if (cur_session == gateway->session_list) {
|
||||
gateway->session_list = cur_session->next;
|
||||
} else {
|
||||
pre_session->next = cur_session->next;
|
||||
}
|
||||
HAL_Free(cur_session);
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
|
||||
}
|
||||
pre_session = cur_session;
|
||||
cur_session = cur_session->next;
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
|
||||
int gateway_publish_sync(Gateway *gateway, char *topic, PublishParams *params, int32_t *result)
|
||||
{
|
||||
int rc = 0;
|
||||
int loop_count = 0;
|
||||
int32_t res = *result;
|
||||
|
||||
POINTER_SANITY_CHECK(gateway, QCLOUD_ERR_INVAL);
|
||||
|
||||
rc = IOT_Gateway_Publish(gateway, topic, params);
|
||||
if (rc < 0) {
|
||||
Log_e("publish fail.");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
|
||||
/* wait for response */
|
||||
while (res == *result) {
|
||||
if (loop_count > GATEWAY_LOOP_MAX_COUNT) {
|
||||
Log_i("loop max count, time out.");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_GATEWAY_SESSION_TIMEOUT);
|
||||
}
|
||||
|
||||
IOT_Gateway_Yield(gateway, 200);
|
||||
loop_count++;
|
||||
}
|
||||
|
||||
if (*result != 0) {
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
|
||||
}
|
240
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/log/log_mqtt.c
vendored
Normal file
240
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/log/log_mqtt.c
vendored
Normal file
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#ifdef LOG_UPLOAD
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "lite-utils.h"
|
||||
#include "log_upload.h"
|
||||
#include "mqtt_client.h"
|
||||
#include "qcloud_iot_device.h"
|
||||
|
||||
typedef struct _log_mqtt_state {
|
||||
bool topic_sub_ok;
|
||||
bool result_recv_ok;
|
||||
int log_level;
|
||||
} LogMQTTState;
|
||||
|
||||
static LogMQTTState sg_state = {.topic_sub_ok = false, .result_recv_ok = false, .log_level = eLOG_ERROR};
|
||||
|
||||
static bool _get_json_log_level(char *json, int32_t *res)
|
||||
{
|
||||
char *v = LITE_json_value_of("log_level", json);
|
||||
if (v == NULL) {
|
||||
Log_e("Invalid log level from JSON: %s", json);
|
||||
return false;
|
||||
}
|
||||
if (LITE_get_int32(res, v) != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("Invalid log level from JSON: %s", json);
|
||||
HAL_Free(v);
|
||||
return false;
|
||||
}
|
||||
HAL_Free(v);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void _log_level_sub_cb(void *pClient, MQTTMessage *message, void *pUserData)
|
||||
{
|
||||
#define LOG_JSON_LENGTH 128
|
||||
char json_buf[LOG_JSON_LENGTH] = {0};
|
||||
int32_t json_buf_len = 0;
|
||||
if (message == NULL) {
|
||||
return;
|
||||
}
|
||||
LogMQTTState *state = (LogMQTTState *)pUserData;
|
||||
|
||||
json_buf_len = Min(LOG_JSON_LENGTH - 1, message->payload_len);
|
||||
memcpy(json_buf, message->payload, json_buf_len);
|
||||
json_buf[json_buf_len] = '\0'; // json_parse relies on a string
|
||||
|
||||
Log_d("Recv Msg Topic:%s, payload:%s", message->ptopic, json_buf);
|
||||
int log_level;
|
||||
if (!_get_json_log_level(json_buf, &log_level)) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (log_level) {
|
||||
case eLOG_DISABLE:
|
||||
Log_w("Upload log level change to: %d", log_level);
|
||||
clear_upload_buffer();
|
||||
set_log_upload_in_comm_err(true);
|
||||
IOT_Log_Set_Upload_Level(eLOG_ERROR);
|
||||
break;
|
||||
case eLOG_ERROR:
|
||||
case eLOG_WARN:
|
||||
case eLOG_INFO:
|
||||
case eLOG_DEBUG:
|
||||
if (log_level < IOT_Log_Get_Upload_Level())
|
||||
clear_upload_buffer();
|
||||
IOT_Log_Set_Upload_Level((LOG_LEVEL)log_level);
|
||||
Log_w("Upload log level change to: %d", log_level);
|
||||
set_log_upload_in_comm_err(false);
|
||||
break;
|
||||
default:
|
||||
Log_e("Invalid log level: %d", log_level);
|
||||
break;
|
||||
}
|
||||
|
||||
state->log_level = log_level;
|
||||
state->result_recv_ok = true;
|
||||
}
|
||||
|
||||
static void _log_mqtt_sub_event_handler(void *pclient, MQTTEventType event_type, void *pUserData)
|
||||
{
|
||||
LogMQTTState *state = (LogMQTTState *)pUserData;
|
||||
|
||||
switch (event_type) {
|
||||
case MQTT_EVENT_SUBCRIBE_SUCCESS:
|
||||
Log_d("mqtt log topic subscribe success");
|
||||
state->topic_sub_ok = true;
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBCRIBE_TIMEOUT:
|
||||
Log_i("mqtt log topic subscribe timeout");
|
||||
state->topic_sub_ok = false;
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBCRIBE_NACK:
|
||||
Log_i("mqtt log topic subscribe NACK");
|
||||
state->topic_sub_ok = false;
|
||||
break;
|
||||
case MQTT_EVENT_UNSUBSCRIBE:
|
||||
Log_i("mqtt log topic has been unsubscribed");
|
||||
state->topic_sub_ok = false;
|
||||
;
|
||||
break;
|
||||
case MQTT_EVENT_CLIENT_DESTROY:
|
||||
Log_i("mqtt client has been destroyed");
|
||||
state->topic_sub_ok = false;
|
||||
;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int _iot_log_level_get_publish(void *pClient)
|
||||
{
|
||||
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
|
||||
static unsigned int sg_client_token = 1;
|
||||
|
||||
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
|
||||
DeviceInfo * dev_info = &mqtt_client->device_info;
|
||||
|
||||
char topic_name[128] = {0};
|
||||
char payload_content[128] = {0};
|
||||
|
||||
HAL_Snprintf(topic_name, sizeof(topic_name), "$log/operation/%s/%s", dev_info->product_id, dev_info->device_name);
|
||||
HAL_Snprintf(payload_content, sizeof(payload_content),
|
||||
"{\"type\": \"get_log_level\", "
|
||||
"\"clientToken\": \"%s-%u\"}",
|
||||
dev_info->product_id, sg_client_token++);
|
||||
|
||||
PublishParams pub_params = DEFAULT_PUB_PARAMS;
|
||||
pub_params.qos = QOS0;
|
||||
pub_params.payload = payload_content;
|
||||
pub_params.payload_len = strlen(payload_content);
|
||||
|
||||
return IOT_MQTT_Publish(mqtt_client, topic_name, &pub_params);
|
||||
}
|
||||
|
||||
int qcloud_log_topic_subscribe(void *client)
|
||||
{
|
||||
/* subscribe the log topic: "$log/operation/result/${productId}/${deviceName}" */
|
||||
char topic_name[128] = {0};
|
||||
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)client;
|
||||
DeviceInfo * dev_info = &mqtt_client->device_info;
|
||||
int size = HAL_Snprintf(topic_name, sizeof(topic_name), "$log/operation/result/%s/%s", dev_info->product_id,
|
||||
dev_info->device_name);
|
||||
if (size < 0 || size > sizeof(topic_name) - 1) {
|
||||
Log_e("topic content buf not enough! content size:%d buf size:%d", size, (int)sizeof(topic_name));
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
SubscribeParams sub_params = DEFAULT_SUB_PARAMS;
|
||||
sub_params.on_message_handler = _log_level_sub_cb;
|
||||
sub_params.on_sub_event_handler = _log_mqtt_sub_event_handler;
|
||||
sub_params.user_data = (void *)&sg_state;
|
||||
sub_params.qos = QOS0;
|
||||
|
||||
return IOT_MQTT_Subscribe(client, topic_name, &sub_params);
|
||||
}
|
||||
|
||||
int qcloud_get_log_level(void *pClient, int *log_level)
|
||||
{
|
||||
int ret = 0;
|
||||
int cntSub = 0;
|
||||
int cntRev = 0;
|
||||
|
||||
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
|
||||
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
|
||||
|
||||
// subscribe log topic: $log/operation/get/${productid}/${devicename}
|
||||
// skip this if the subscription is done and valid
|
||||
if (!sg_state.topic_sub_ok) {
|
||||
for (cntSub = 0; cntSub < 3; cntSub++) {
|
||||
ret = qcloud_log_topic_subscribe(mqtt_client);
|
||||
if (ret < 0) {
|
||||
Log_w("qcloud_log_topic_subscribe failed: %d, cnt: %d", ret, cntSub);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* wait for sub ack */
|
||||
ret = qcloud_iot_mqtt_yield_mt((Qcloud_IoT_Client *)pClient, 100);
|
||||
if (sg_state.topic_sub_ok) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return failure if subscribe failed
|
||||
if (!sg_state.topic_sub_ok) {
|
||||
Log_e("Subscribe log topic failed!");
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
sg_state.result_recv_ok = false;
|
||||
// publish msg to get log level
|
||||
ret = _iot_log_level_get_publish(mqtt_client);
|
||||
if (ret < 0) {
|
||||
Log_e("client publish log topic failed :%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
do {
|
||||
ret = qcloud_iot_mqtt_yield_mt((Qcloud_IoT_Client *)pClient, 100);
|
||||
cntRev++;
|
||||
} while (!ret && !sg_state.result_recv_ok && cntRev < 20);
|
||||
|
||||
*log_level = sg_state.log_level;
|
||||
if (sg_state.result_recv_ok)
|
||||
ret = QCLOUD_RET_SUCCESS;
|
||||
else
|
||||
ret = QCLOUD_ERR_FAILURE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
702
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/log/log_upload.c
vendored
Normal file
702
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/log/log_upload.c
vendored
Normal file
@@ -0,0 +1,702 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "qcloud_iot_export.h"
|
||||
#include "qcloud_iot_import.h"
|
||||
|
||||
#ifdef LOG_UPLOAD
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lite-utils.h"
|
||||
#include "log_upload.h"
|
||||
#include "qcloud_iot_common.h"
|
||||
#include "utils_hmac.h"
|
||||
#include "utils_httpc.h"
|
||||
#include "utils_timer.h"
|
||||
|
||||
/* log post header format */
|
||||
#define TIMESTAMP_SIZE 10
|
||||
#define SIGNATURE_SIZE 40
|
||||
#define CTRL_BYTES_SIZE 4
|
||||
// LOG_BUF_FIXED_HEADER_SIZE = 112
|
||||
#define LOG_BUF_FIXED_HEADER_SIZE \
|
||||
(SIGNATURE_SIZE + CTRL_BYTES_SIZE + MAX_SIZE_OF_PRODUCT_ID + MAX_SIZE_OF_DEVICE_NAME + TIMESTAMP_SIZE)
|
||||
|
||||
/* do immediate log update if buffer is lower than this threshold (about two max log item) */
|
||||
#define LOG_LOW_BUFFER_THRESHOLD (LOG_UPLOAD_BUFFER_SIZE / 4)
|
||||
|
||||
/* log upload buffer */
|
||||
static char * sg_log_buffer = NULL;
|
||||
static uint32_t sg_write_index = LOG_BUF_FIXED_HEADER_SIZE;
|
||||
|
||||
#define SIGN_KEY_SIZE 24
|
||||
static char sg_sign_key[SIGN_KEY_SIZE + 1] = {0};
|
||||
|
||||
/* Log upload feature switch */
|
||||
/* To check log http server return msg or not */
|
||||
#define LOG_CHECK_HTTP_RET_CODE
|
||||
|
||||
typedef struct {
|
||||
const char * url;
|
||||
const char * ca_crt;
|
||||
int port;
|
||||
HTTPClient http; /* http client */
|
||||
HTTPClientData http_data; /* http client data */
|
||||
|
||||
} LogHTTPStruct;
|
||||
|
||||
static LogHTTPStruct *sg_http_c = NULL;
|
||||
|
||||
typedef struct {
|
||||
const char *product_id;
|
||||
const char *device_name;
|
||||
void * mqtt_client;
|
||||
bool upload_only_in_comm_err;
|
||||
|
||||
void *lock_buf;
|
||||
Timer upload_timer;
|
||||
#ifndef LOG_UPDATE_TIME_WHEN_UPLOAD
|
||||
Timer time_update_timer;
|
||||
#endif
|
||||
long system_time;
|
||||
|
||||
LogSaveFunc save_func;
|
||||
LogReadFunc read_func;
|
||||
LogDelFunc del_func;
|
||||
LogGetSizeFunc get_size_func;
|
||||
bool log_save_enabled;
|
||||
|
||||
bool uploader_init_done;
|
||||
|
||||
} LogUploaderStruct;
|
||||
|
||||
static LogUploaderStruct *sg_uploader = NULL;
|
||||
static bool sg_log_uploader_init_done = false;
|
||||
|
||||
#ifdef AUTH_MODE_CERT
|
||||
static int _gen_key_from_file(const char *file_path)
|
||||
{
|
||||
FILE *fp;
|
||||
int len;
|
||||
char line_buf[128] = {0};
|
||||
|
||||
if ((fp = fopen(file_path, "r")) == NULL) {
|
||||
UPLOAD_ERR("fail to open cert file %s", file_path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* find the begin line */
|
||||
do {
|
||||
if (NULL == fgets(line_buf, sizeof(line_buf), fp)) {
|
||||
UPLOAD_ERR("fail to fgets file %s", file_path);
|
||||
return -1;
|
||||
}
|
||||
} while (strstr(line_buf, "-----BEGIN ") == NULL);
|
||||
|
||||
if (feof(fp)) {
|
||||
UPLOAD_ERR("invalid cert file %s", file_path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (NULL == fgets(line_buf, sizeof(line_buf), fp)) {
|
||||
UPLOAD_ERR("fail to fgets file %s", file_path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = strlen(line_buf);
|
||||
memcpy(sg_sign_key, line_buf, len > SIGN_KEY_SIZE ? SIGN_KEY_SIZE : len);
|
||||
UPLOAD_DBG("sign key %s", sg_sign_key);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static long _get_system_time(void)
|
||||
{
|
||||
#ifdef SYSTEM_COMM
|
||||
if (sg_uploader->mqtt_client == NULL)
|
||||
return 0;
|
||||
|
||||
long sys_time = 0;
|
||||
int rc = IOT_Get_SysTime(sg_uploader->mqtt_client, &sys_time);
|
||||
if (rc == QCLOUD_RET_SUCCESS)
|
||||
return sys_time;
|
||||
else
|
||||
return 0;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void _update_system_time(void)
|
||||
{
|
||||
/* to avoid frequent get_system_time */
|
||||
#define LOG_TIME_UPDATE_INTERVAL 2
|
||||
|
||||
if (!expired(&sg_uploader->time_update_timer))
|
||||
return;
|
||||
|
||||
sg_uploader->system_time = _get_system_time();
|
||||
|
||||
countdown(&sg_uploader->time_update_timer, LOG_TIME_UPDATE_INTERVAL);
|
||||
}
|
||||
|
||||
static int _check_server_connection()
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = qcloud_http_client_connect(&sg_http_c->http, sg_http_c->url, sg_http_c->port, sg_http_c->ca_crt);
|
||||
if (rc != QCLOUD_RET_SUCCESS)
|
||||
return rc;
|
||||
|
||||
qcloud_http_client_close(&sg_http_c->http);
|
||||
|
||||
return QCLOUD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef LOG_CHECK_HTTP_RET_CODE
|
||||
static bool _get_json_ret_code(char *json, int32_t *res)
|
||||
{
|
||||
char *v = LITE_json_value_of("Retcode", json);
|
||||
if (v == NULL) {
|
||||
UPLOAD_ERR("Invalid json content: %s", json);
|
||||
return false;
|
||||
}
|
||||
if (LITE_get_int32(res, v) != QCLOUD_RET_SUCCESS) {
|
||||
UPLOAD_ERR("Invalid json content: %s", json);
|
||||
HAL_Free(v);
|
||||
return false;
|
||||
}
|
||||
HAL_Free(v);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _post_one_http_to_server(char *post_buf, size_t post_size)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (sg_http_c == NULL)
|
||||
return QCLOUD_ERR_INVAL;
|
||||
|
||||
sg_http_c->http_data.post_content_type = "text/plain;charset=utf-8";
|
||||
sg_http_c->http_data.post_buf = post_buf;
|
||||
sg_http_c->http_data.post_buf_len = post_size;
|
||||
|
||||
rc = qcloud_http_client_common(&sg_http_c->http, sg_http_c->url, sg_http_c->port, sg_http_c->ca_crt, HTTP_POST,
|
||||
&sg_http_c->http_data);
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
UPLOAD_ERR("qcloud_http_client_common failed, rc = %d", rc);
|
||||
return rc;
|
||||
}
|
||||
UPLOAD_DBG("Log client POST size: %d", post_size);
|
||||
|
||||
#ifdef LOG_CHECK_HTTP_RET_CODE
|
||||
/* TODO: handle recv data from log server */
|
||||
#define HTTP_RET_JSON_LENGTH 256
|
||||
#define HTTP_WAIT_RET_TIMEOUT_MS 1000
|
||||
char buf[HTTP_RET_JSON_LENGTH] = {0};
|
||||
sg_http_c->http_data.response_buf = buf;
|
||||
sg_http_c->http_data.response_buf_len = sizeof(buf);
|
||||
|
||||
rc = qcloud_http_recv_data(&sg_http_c->http, HTTP_WAIT_RET_TIMEOUT_MS, &sg_http_c->http_data);
|
||||
if (QCLOUD_RET_SUCCESS != rc) {
|
||||
UPLOAD_ERR("qcloud_http_recv_data failed, rc = %d", rc);
|
||||
} else {
|
||||
int32_t ret = -1;
|
||||
|
||||
buf[HTTP_RET_JSON_LENGTH - 1] = '\0'; // json_parse relies on a string
|
||||
if (strlen(buf) > 0 && _get_json_ret_code(buf, &ret) && ret == 0) {
|
||||
UPLOAD_DBG("Log server return SUCCESS: %s", buf);
|
||||
} else {
|
||||
UPLOAD_ERR("Log server return FAIL(%d): %s", ret, buf);
|
||||
rc = QCLOUD_ERR_HTTP;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
qcloud_http_client_close(&sg_http_c->http);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void _update_time_and_signature(char *log_buf, size_t log_size)
|
||||
{
|
||||
char timestamp[TIMESTAMP_SIZE + 1] = {0};
|
||||
char signature[SIGNATURE_SIZE + 1] = {0};
|
||||
|
||||
/* get system time from IoT hub first */
|
||||
_update_system_time();
|
||||
|
||||
/* record the timestamp for this log uploading */
|
||||
HAL_Snprintf(timestamp, TIMESTAMP_SIZE + 1, "%010ld", sg_uploader->system_time);
|
||||
memcpy(log_buf + LOG_BUF_FIXED_HEADER_SIZE - TIMESTAMP_SIZE, timestamp, strlen(timestamp));
|
||||
|
||||
/* signature of this log uploading */
|
||||
utils_hmac_sha1(log_buf + SIGNATURE_SIZE, log_size - SIGNATURE_SIZE, signature, sg_sign_key, strlen(sg_sign_key));
|
||||
memcpy(log_buf, signature, SIGNATURE_SIZE);
|
||||
}
|
||||
|
||||
static int _post_log_to_server(char *post_buf, size_t post_size, size_t *actual_post_payload)
|
||||
{
|
||||
#define LOG_DELIMITER "\n\f"
|
||||
int ret = QCLOUD_RET_SUCCESS;
|
||||
/* one shot upload */
|
||||
if (post_size < MAX_HTTP_LOG_POST_SIZE) {
|
||||
_update_time_and_signature(post_buf, post_size);
|
||||
ret = _post_one_http_to_server(post_buf, post_size);
|
||||
if (QCLOUD_RET_SUCCESS == ret) {
|
||||
*actual_post_payload = post_size - LOG_BUF_FIXED_HEADER_SIZE;
|
||||
} else {
|
||||
UPLOAD_ERR("one time log send failed");
|
||||
*actual_post_payload = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Log size is larger than one HTTP post size */
|
||||
/* Fragment the log and upload multi-times */
|
||||
UPLOAD_DBG("to post large log size %d", post_size);
|
||||
*actual_post_payload = 0;
|
||||
size_t delimiter_len = strlen(LOG_DELIMITER);
|
||||
size_t orig_post_size = post_size;
|
||||
size_t post_payload, upload_size, possible_size;
|
||||
do {
|
||||
char *next_log_buf = NULL;
|
||||
possible_size = 0;
|
||||
while (possible_size < MAX_HTTP_LOG_POST_SIZE) {
|
||||
/*remember last valid position */
|
||||
upload_size = possible_size;
|
||||
/* locate the delimiter */
|
||||
next_log_buf = strstr(post_buf + upload_size, LOG_DELIMITER);
|
||||
if (next_log_buf == NULL) {
|
||||
UPLOAD_ERR("Invalid log delimiter. Total sent: %d. Left: %d",
|
||||
*actual_post_payload + LOG_BUF_FIXED_HEADER_SIZE, post_size);
|
||||
return QCLOUD_ERR_INVAL;
|
||||
}
|
||||
possible_size = (size_t)(next_log_buf - post_buf + delimiter_len);
|
||||
/* end of log */
|
||||
if (next_log_buf[delimiter_len] == 0 && possible_size < MAX_HTTP_LOG_POST_SIZE) {
|
||||
upload_size = possible_size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (upload_size == 0) {
|
||||
UPLOAD_ERR("Upload size should not be 0! Total sent: %d. Left: %d",
|
||||
*actual_post_payload + LOG_BUF_FIXED_HEADER_SIZE, post_size);
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
_update_time_and_signature(post_buf, upload_size);
|
||||
ret = _post_one_http_to_server(post_buf, upload_size);
|
||||
if (QCLOUD_RET_SUCCESS != ret) {
|
||||
UPLOAD_ERR("Send log failed. Total sent: %d. Left: %d", *actual_post_payload + LOG_BUF_FIXED_HEADER_SIZE,
|
||||
post_size);
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
/* move the left log forward and do next upload */
|
||||
memmove(post_buf + LOG_BUF_FIXED_HEADER_SIZE, post_buf + upload_size, post_size - upload_size);
|
||||
post_payload = upload_size - LOG_BUF_FIXED_HEADER_SIZE;
|
||||
post_size -= post_payload;
|
||||
*actual_post_payload += post_payload;
|
||||
memset(post_buf + post_size, 0, orig_post_size - post_size);
|
||||
UPLOAD_DBG("post log %d OK. Total sent: %d. Left: %d", upload_size,
|
||||
*actual_post_payload + LOG_BUF_FIXED_HEADER_SIZE, post_size);
|
||||
} while (post_size > LOG_BUF_FIXED_HEADER_SIZE);
|
||||
|
||||
return QCLOUD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static void _reset_log_buffer(void)
|
||||
{
|
||||
sg_write_index = LOG_BUF_FIXED_HEADER_SIZE;
|
||||
memset(sg_log_buffer + LOG_BUF_FIXED_HEADER_SIZE, 0, LOG_UPLOAD_BUFFER_SIZE - LOG_BUF_FIXED_HEADER_SIZE);
|
||||
}
|
||||
|
||||
static int _save_log(char *log_buf, size_t log_size)
|
||||
{
|
||||
int rc = 0;
|
||||
size_t write_size, current_size = sg_uploader->get_size_func();
|
||||
|
||||
/* overwrite the previous saved log to avoid too many saved logs */
|
||||
if ((current_size + log_size) > MAX_LOG_SAVE_SIZE) {
|
||||
UPLOAD_ERR("overwrite the previous saved log. %d", current_size);
|
||||
rc = sg_uploader->del_func();
|
||||
if (rc) {
|
||||
Log_e("fail to delete previous log");
|
||||
}
|
||||
}
|
||||
|
||||
write_size = sg_uploader->save_func(log_buf, log_size);
|
||||
if (write_size != log_size) {
|
||||
Log_e("fail to save log. RC %d - log size %d", write_size, log_size);
|
||||
rc = -1;
|
||||
} else {
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int _handle_saved_log(void)
|
||||
{
|
||||
int rc = QCLOUD_RET_SUCCESS;
|
||||
size_t whole_log_size = sg_uploader->get_size_func();
|
||||
if (whole_log_size > 0) {
|
||||
/* only do the job when connection is OK */
|
||||
if (_check_server_connection() != QCLOUD_RET_SUCCESS)
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
|
||||
size_t buf_size = whole_log_size + LOG_BUF_FIXED_HEADER_SIZE + 1;
|
||||
char * log_buf = HAL_Malloc(buf_size);
|
||||
if (log_buf != NULL) {
|
||||
/* read the whole log to buffer */
|
||||
size_t read_len = sg_uploader->read_func(log_buf + LOG_BUF_FIXED_HEADER_SIZE, whole_log_size);
|
||||
if (read_len == whole_log_size) {
|
||||
size_t upload_size = whole_log_size + LOG_BUF_FIXED_HEADER_SIZE;
|
||||
|
||||
/* copy header from global log buffer */
|
||||
memcpy(log_buf, sg_log_buffer, LOG_BUF_FIXED_HEADER_SIZE);
|
||||
log_buf[buf_size - 1] = 0;
|
||||
|
||||
size_t actual_post_payload;
|
||||
rc = _post_log_to_server(log_buf, upload_size, &actual_post_payload);
|
||||
if (rc == QCLOUD_RET_SUCCESS || rc == QCLOUD_ERR_INVAL) {
|
||||
Log_d("handle saved log done! Size: %d. upload paylod: %d", whole_log_size, actual_post_payload);
|
||||
sg_uploader->del_func();
|
||||
}
|
||||
HAL_Free(log_buf);
|
||||
} else {
|
||||
Log_e("fail to read whole saved log. Size: %u - read: %u", whole_log_size, read_len);
|
||||
HAL_Free(log_buf);
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
} else {
|
||||
Log_e("Malloc failed, size: %u", buf_size);
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void set_log_mqtt_client(void *client)
|
||||
{
|
||||
if (!sg_log_uploader_init_done)
|
||||
return;
|
||||
|
||||
sg_uploader->mqtt_client = client;
|
||||
}
|
||||
|
||||
void set_log_upload_in_comm_err(bool value)
|
||||
{
|
||||
if (!sg_log_uploader_init_done)
|
||||
return;
|
||||
|
||||
sg_uploader->upload_only_in_comm_err = value;
|
||||
}
|
||||
|
||||
int append_to_upload_buffer(const char *log_content, size_t log_size)
|
||||
{
|
||||
if (!sg_log_uploader_init_done)
|
||||
return -1;
|
||||
|
||||
if (log_content == NULL || log_size == 0) {
|
||||
UPLOAD_ERR("invalid log content!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (HAL_MutexTryLock(sg_uploader->lock_buf) != 0) {
|
||||
UPLOAD_ERR("trylock buffer failed!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((sg_write_index + log_size + 1) > LOG_UPLOAD_BUFFER_SIZE) {
|
||||
countdown_ms(&sg_uploader->upload_timer, 0);
|
||||
HAL_MutexUnlock(sg_uploader->lock_buf);
|
||||
UPLOAD_ERR("log upload buffer is not enough!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(sg_log_buffer + sg_write_index, log_content, log_size);
|
||||
|
||||
sg_write_index += log_size;
|
||||
|
||||
/* replace \r\n to \n\f as delimiter */
|
||||
sg_log_buffer[sg_write_index - 1] = '\f';
|
||||
sg_log_buffer[sg_write_index - 2] = '\n';
|
||||
|
||||
HAL_MutexUnlock(sg_uploader->lock_buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void clear_upload_buffer(void)
|
||||
{
|
||||
if (!sg_log_uploader_init_done)
|
||||
return;
|
||||
|
||||
HAL_MutexLock(sg_uploader->lock_buf);
|
||||
_reset_log_buffer();
|
||||
HAL_MutexUnlock(sg_uploader->lock_buf);
|
||||
}
|
||||
|
||||
int init_log_uploader(LogUploadInitParams *init_params)
|
||||
{
|
||||
if (sg_log_uploader_init_done)
|
||||
return QCLOUD_RET_SUCCESS;
|
||||
|
||||
if (init_params == NULL || init_params->product_id == NULL || init_params->device_name == NULL ||
|
||||
init_params->sign_key == NULL) {
|
||||
UPLOAD_ERR("invalid init parameters");
|
||||
return QCLOUD_ERR_INVAL;
|
||||
}
|
||||
|
||||
int key_len = strlen(init_params->sign_key);
|
||||
if (key_len == 0) {
|
||||
UPLOAD_ERR("invalid key length");
|
||||
return QCLOUD_ERR_INVAL;
|
||||
}
|
||||
|
||||
sg_log_buffer = HAL_Malloc(LOG_UPLOAD_BUFFER_SIZE);
|
||||
if (sg_log_buffer == NULL) {
|
||||
UPLOAD_ERR("malloc log buffer failed");
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < LOG_BUF_FIXED_HEADER_SIZE; i++) sg_log_buffer[i] = '#';
|
||||
|
||||
#ifdef AUTH_MODE_CERT
|
||||
if (_gen_key_from_file(init_params->sign_key) != 0) {
|
||||
UPLOAD_ERR("gen_key_from_file failed");
|
||||
goto err_exit;
|
||||
}
|
||||
sg_log_buffer[SIGNATURE_SIZE] = 'C';
|
||||
#else
|
||||
memcpy(sg_sign_key, init_params->sign_key, key_len > SIGN_KEY_SIZE ? SIGN_KEY_SIZE : key_len);
|
||||
sg_log_buffer[SIGNATURE_SIZE] = 'P';
|
||||
#endif
|
||||
|
||||
memcpy(sg_log_buffer + SIGNATURE_SIZE + CTRL_BYTES_SIZE, init_params->product_id, MAX_SIZE_OF_PRODUCT_ID);
|
||||
memcpy(sg_log_buffer + SIGNATURE_SIZE + CTRL_BYTES_SIZE + MAX_SIZE_OF_PRODUCT_ID, init_params->device_name,
|
||||
strlen(init_params->device_name));
|
||||
|
||||
if (NULL == (sg_uploader = HAL_Malloc(sizeof(LogUploaderStruct)))) {
|
||||
UPLOAD_ERR("allocate for LogUploaderStruct failed");
|
||||
goto err_exit;
|
||||
}
|
||||
memset(sg_uploader, 0, sizeof(LogUploaderStruct));
|
||||
|
||||
sg_uploader->product_id = init_params->product_id;
|
||||
sg_uploader->device_name = init_params->device_name;
|
||||
sg_uploader->mqtt_client = NULL;
|
||||
sg_uploader->system_time = 0;
|
||||
sg_uploader->upload_only_in_comm_err = false;
|
||||
|
||||
/* all the call back functions are necessary to handle log save and re-upload */
|
||||
if (init_params->save_func != NULL && init_params->read_func != NULL && init_params->del_func != NULL &&
|
||||
init_params->get_size_func) {
|
||||
sg_uploader->save_func = init_params->save_func;
|
||||
sg_uploader->read_func = init_params->read_func;
|
||||
sg_uploader->del_func = init_params->del_func;
|
||||
sg_uploader->get_size_func = init_params->get_size_func;
|
||||
sg_uploader->log_save_enabled = true;
|
||||
} else {
|
||||
sg_uploader->log_save_enabled = false;
|
||||
}
|
||||
|
||||
InitTimer(&sg_uploader->upload_timer);
|
||||
InitTimer(&sg_uploader->time_update_timer);
|
||||
|
||||
if ((sg_uploader->lock_buf = HAL_MutexCreate()) == NULL) {
|
||||
UPLOAD_ERR("mutex create failed");
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
if (NULL == (sg_http_c = HAL_Malloc(sizeof(LogHTTPStruct)))) {
|
||||
UPLOAD_ERR("allocate for LogHTTPStruct failed");
|
||||
goto err_exit;
|
||||
}
|
||||
memset(sg_http_c, 0, sizeof(LogHTTPStruct));
|
||||
|
||||
/* set http request-header parameter */
|
||||
sg_http_c->http.header = "Accept:application/json;*/*\r\n";
|
||||
sg_http_c->url = LOG_UPLOAD_SERVER_URL;
|
||||
sg_http_c->port = LOG_UPLOAD_SERVER_PORT;
|
||||
sg_http_c->ca_crt = NULL;
|
||||
|
||||
_reset_log_buffer();
|
||||
sg_log_uploader_init_done = true;
|
||||
|
||||
return QCLOUD_RET_SUCCESS;
|
||||
err_exit:
|
||||
HAL_Free(sg_log_buffer);
|
||||
sg_log_buffer = NULL;
|
||||
|
||||
if (sg_uploader && sg_uploader->lock_buf) {
|
||||
HAL_MutexDestroy(sg_uploader->lock_buf);
|
||||
sg_uploader->lock_buf = NULL;
|
||||
}
|
||||
HAL_Free(sg_uploader);
|
||||
sg_uploader = NULL;
|
||||
HAL_Free(sg_http_c);
|
||||
sg_http_c = NULL;
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
void fini_log_uploader(void)
|
||||
{
|
||||
if (!sg_log_uploader_init_done)
|
||||
return;
|
||||
|
||||
HAL_MutexLock(sg_uploader->lock_buf);
|
||||
sg_log_uploader_init_done = false;
|
||||
if (sg_log_buffer) {
|
||||
_reset_log_buffer();
|
||||
HAL_Free(sg_log_buffer);
|
||||
sg_log_buffer = NULL;
|
||||
}
|
||||
HAL_MutexUnlock(sg_uploader->lock_buf);
|
||||
|
||||
HAL_MutexDestroy(sg_uploader->lock_buf);
|
||||
sg_uploader->lock_buf = NULL;
|
||||
HAL_Free(sg_uploader);
|
||||
sg_uploader = NULL;
|
||||
HAL_Free(sg_http_c);
|
||||
sg_http_c = NULL;
|
||||
}
|
||||
|
||||
bool is_log_uploader_init(void)
|
||||
{
|
||||
return sg_log_uploader_init_done;
|
||||
}
|
||||
|
||||
static bool _check_force_upload(bool force_upload)
|
||||
{
|
||||
if (!force_upload) {
|
||||
/* Double check if the buffer is low */
|
||||
HAL_MutexLock(sg_uploader->lock_buf);
|
||||
bool is_low_buffer = (LOG_UPLOAD_BUFFER_SIZE - sg_write_index) < LOG_LOW_BUFFER_THRESHOLD ? true : false;
|
||||
|
||||
/* force_upload is false and upload_only_in_comm_err is true */
|
||||
if (sg_uploader->upload_only_in_comm_err) {
|
||||
/* buffer is low but we couldn't upload now, reset buffer */
|
||||
if (is_low_buffer)
|
||||
_reset_log_buffer();
|
||||
|
||||
HAL_MutexUnlock(sg_uploader->lock_buf);
|
||||
countdown_ms(&sg_uploader->upload_timer, LOG_UPLOAD_INTERVAL_MS);
|
||||
return false;
|
||||
}
|
||||
HAL_MutexUnlock(sg_uploader->lock_buf);
|
||||
|
||||
if (is_low_buffer) {
|
||||
/* buffer is low, handle it right now */
|
||||
return true;
|
||||
} else {
|
||||
return expired(&sg_uploader->upload_timer);
|
||||
}
|
||||
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int do_log_upload(bool force_upload)
|
||||
{
|
||||
int rc;
|
||||
int upload_log_size = 0;
|
||||
static bool unhandle_saved_log = true;
|
||||
|
||||
if (!sg_log_uploader_init_done)
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
|
||||
/* double check force upload */
|
||||
if (!_check_force_upload(force_upload))
|
||||
return QCLOUD_RET_SUCCESS;
|
||||
|
||||
/* handle previously saved log */
|
||||
if (sg_uploader->log_save_enabled && unhandle_saved_log) {
|
||||
rc = _handle_saved_log();
|
||||
if (rc == QCLOUD_RET_SUCCESS)
|
||||
unhandle_saved_log = false;
|
||||
}
|
||||
|
||||
/* no more log in buffer */
|
||||
if (sg_write_index == LOG_BUF_FIXED_HEADER_SIZE)
|
||||
return QCLOUD_RET_SUCCESS;
|
||||
|
||||
HAL_MutexLock(sg_uploader->lock_buf);
|
||||
upload_log_size = sg_write_index;
|
||||
HAL_MutexUnlock(sg_uploader->lock_buf);
|
||||
|
||||
size_t actual_post_payload;
|
||||
rc = _post_log_to_server(sg_log_buffer, upload_log_size, &actual_post_payload);
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
/* save log via user callbacks when log upload fail */
|
||||
if (sg_uploader->log_save_enabled) {
|
||||
/* new error logs should have been added, update log size */
|
||||
HAL_MutexLock(sg_uploader->lock_buf);
|
||||
/* parts of log were uploaded succesfully. Need to move the new logs forward */
|
||||
if (actual_post_payload) {
|
||||
UPLOAD_DBG("move the new log %d forward", actual_post_payload);
|
||||
memmove(sg_log_buffer + upload_log_size - actual_post_payload, sg_log_buffer + upload_log_size,
|
||||
sg_write_index - upload_log_size);
|
||||
sg_write_index = sg_write_index - actual_post_payload;
|
||||
memset(sg_log_buffer + sg_write_index, 0, LOG_UPLOAD_BUFFER_SIZE - sg_write_index);
|
||||
}
|
||||
upload_log_size = sg_write_index;
|
||||
HAL_MutexUnlock(sg_uploader->lock_buf);
|
||||
_save_log(sg_log_buffer + LOG_BUF_FIXED_HEADER_SIZE, upload_log_size - LOG_BUF_FIXED_HEADER_SIZE);
|
||||
unhandle_saved_log = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* move the new log during send_log_to_server */
|
||||
HAL_MutexLock(sg_uploader->lock_buf);
|
||||
if (upload_log_size == sg_write_index) {
|
||||
_reset_log_buffer();
|
||||
} else {
|
||||
memmove(sg_log_buffer + LOG_BUF_FIXED_HEADER_SIZE, sg_log_buffer + upload_log_size,
|
||||
sg_write_index - upload_log_size);
|
||||
sg_write_index = sg_write_index - upload_log_size + LOG_BUF_FIXED_HEADER_SIZE;
|
||||
memset(sg_log_buffer + sg_write_index, 0, LOG_UPLOAD_BUFFER_SIZE - sg_write_index);
|
||||
}
|
||||
HAL_MutexUnlock(sg_uploader->lock_buf);
|
||||
|
||||
countdown_ms(&sg_uploader->upload_timer, LOG_UPLOAD_INTERVAL_MS);
|
||||
|
||||
return QCLOUD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
661
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/ota/ota_client.c
vendored
Normal file
661
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/ota/ota_client.c
vendored
Normal file
@@ -0,0 +1,661 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ota_client.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ota_fetch.h"
|
||||
#include "ota_lib.h"
|
||||
#include "qcloud_iot_export.h"
|
||||
#include "utils_param_check.h"
|
||||
#include "utils_timer.h"
|
||||
|
||||
#define OTA_VERSION_STR_LEN_MIN (1)
|
||||
#define OTA_VERSION_STR_LEN_MAX (32)
|
||||
|
||||
typedef struct {
|
||||
const char *product_id; /* point to product id */
|
||||
const char *device_name; /* point to device name */
|
||||
|
||||
uint32_t id; /* message id */
|
||||
IOT_OTA_State_Code state; /* OTA state */
|
||||
uint32_t size_last_fetched; /* size of last downloaded */
|
||||
uint32_t size_fetched; /* size of already downloaded */
|
||||
uint32_t size_file; /* size of file */
|
||||
|
||||
char *purl; /* point to URL */
|
||||
char *version; /* point to string */
|
||||
char md5sum[33]; /* MD5 string */
|
||||
|
||||
void *md5; /* MD5 handle */
|
||||
void *ch_signal; /* channel handle of signal exchanged with OTA server */
|
||||
void *ch_fetch; /* channel handle of download */
|
||||
|
||||
int err; /* last error code */
|
||||
|
||||
short current_signal_type;
|
||||
|
||||
Timer report_timer;
|
||||
|
||||
} OTA_Struct_t;
|
||||
|
||||
/* check ota progress */
|
||||
/* return: true, valid progress state; false, invalid progress state. */
|
||||
static int _ota_check_progress(IOT_OTA_Progress_Code progress)
|
||||
{
|
||||
return ((progress >= IOT_OTAP_BURN_FAILED) && (progress <= IOT_OTAP_FETCH_PERCENTAGE_MAX));
|
||||
}
|
||||
|
||||
/* callback when OTA topic msg is received */
|
||||
static void _ota_callback(void *pcontext, const char *msg, uint32_t msg_len)
|
||||
{
|
||||
#define OTA_JSON_TYPE_VALUE_LENGTH 64
|
||||
|
||||
char *json_type = NULL;
|
||||
|
||||
OTA_Struct_t *h_ota = (OTA_Struct_t *)pcontext;
|
||||
|
||||
if (h_ota->state >= IOT_OTAS_FETCHING) {
|
||||
Log_i("In downloading or downloaded state");
|
||||
goto End;
|
||||
}
|
||||
|
||||
if (msg == NULL || msg_len == 0) {
|
||||
Log_e("OTA response message is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
if (qcloud_otalib_get_firmware_type(msg, &json_type) != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("Get firmware type failed!");
|
||||
goto End;
|
||||
}
|
||||
|
||||
if (!strcmp(json_type, REPORT_VERSION_RSP)) {
|
||||
if (qcloud_otalib_get_report_version_result(msg) < QCLOUD_RET_SUCCESS) {
|
||||
Log_e("Report version failed!");
|
||||
h_ota->err = IOT_OTA_ERR_REPORT_VERSION;
|
||||
h_ota->state = IOT_OTAS_FETCHED;
|
||||
} else {
|
||||
Log_i("Report version success!");
|
||||
}
|
||||
goto End;
|
||||
} else {
|
||||
if (strcmp(json_type, UPDATE_FIRMWARE) != 0) {
|
||||
Log_e("Netheir Report version result nor update firmware! type: %s", json_type);
|
||||
goto End;
|
||||
}
|
||||
|
||||
if (NULL != json_type) {
|
||||
HAL_Free(json_type);
|
||||
json_type = NULL;
|
||||
}
|
||||
|
||||
if (0 != qcloud_otalib_get_params(msg, &json_type, &h_ota->purl, &h_ota->version, h_ota->md5sum,
|
||||
&h_ota->size_file)) {
|
||||
Log_e("Get firmware parameter failed");
|
||||
goto End;
|
||||
}
|
||||
|
||||
h_ota->state = IOT_OTAS_FETCHING;
|
||||
}
|
||||
|
||||
End:
|
||||
if (json_type != NULL)
|
||||
HAL_Free(json_type);
|
||||
|
||||
#undef OTA_JSON_TYPE_VALUE_LENGTH
|
||||
}
|
||||
|
||||
static void IOT_OTA_ResetStatus(void *handle)
|
||||
{
|
||||
OTA_Struct_t *h_ota = (OTA_Struct_t *)handle;
|
||||
h_ota->state = IOT_OTAS_INITED;
|
||||
}
|
||||
|
||||
static int IOT_OTA_ReportProgress(void *handle, IOT_OTA_Progress_Code progress, IOT_OTAReportType reportType)
|
||||
{
|
||||
#define MSG_REPORT_LEN (256)
|
||||
|
||||
int ret = QCLOUD_ERR_FAILURE;
|
||||
char * msg_reported;
|
||||
OTA_Struct_t *h_ota = (OTA_Struct_t *)handle;
|
||||
|
||||
if (NULL == handle) {
|
||||
Log_e("handle is NULL");
|
||||
return IOT_OTA_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (IOT_OTAS_UNINITED == h_ota->state) {
|
||||
Log_e("handle is uninitialized");
|
||||
h_ota->err = IOT_OTA_ERR_INVALID_STATE;
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
if (!_ota_check_progress(progress)) {
|
||||
Log_e("progress is a invalid parameter: %d", progress);
|
||||
h_ota->err = IOT_OTA_ERR_INVALID_PARAM;
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
if (NULL == (msg_reported = HAL_Malloc(MSG_REPORT_LEN))) {
|
||||
Log_e("allocate for msg_reported failed");
|
||||
h_ota->err = IOT_OTA_ERR_NOMEM;
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
ret = qcloud_otalib_gen_report_msg(msg_reported, MSG_REPORT_LEN, h_ota->id, h_ota->version, progress, reportType);
|
||||
if (0 != ret) {
|
||||
Log_e("generate reported message failed");
|
||||
h_ota->err = ret;
|
||||
goto do_exit;
|
||||
}
|
||||
|
||||
ret = qcloud_osc_report_progress(h_ota->ch_signal, msg_reported);
|
||||
if (QCLOUD_RET_SUCCESS != ret) {
|
||||
Log_e("Report progress failed");
|
||||
h_ota->err = ret;
|
||||
goto do_exit;
|
||||
}
|
||||
|
||||
ret = QCLOUD_RET_SUCCESS;
|
||||
|
||||
do_exit:
|
||||
if (NULL != msg_reported) {
|
||||
HAL_Free(msg_reported);
|
||||
}
|
||||
return ret;
|
||||
|
||||
#undef MSG_REPORT_LEN
|
||||
}
|
||||
|
||||
static int IOT_OTA_ReportUpgradeResult(void *handle, const char *version, IOT_OTAReportType reportType)
|
||||
{
|
||||
#define MSG_UPGPGRADE_LEN (256)
|
||||
|
||||
POINTER_SANITY_CHECK(handle, IOT_OTA_ERR_INVALID_PARAM);
|
||||
POINTER_SANITY_CHECK(version, IOT_OTA_ERR_INVALID_PARAM);
|
||||
|
||||
int ret, len;
|
||||
char * msg_upgrade;
|
||||
OTA_Struct_t *h_ota = (OTA_Struct_t *)handle;
|
||||
|
||||
if (IOT_OTAS_UNINITED == h_ota->state) {
|
||||
Log_e("handle is uninitialized");
|
||||
h_ota->err = IOT_OTA_ERR_INVALID_STATE;
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
len = strlen(version);
|
||||
if ((len < OTA_VERSION_STR_LEN_MIN) || (len > OTA_VERSION_STR_LEN_MAX)) {
|
||||
Log_e("version string is invalid: must be [1, 32] chars");
|
||||
h_ota->err = IOT_OTA_ERR_INVALID_PARAM;
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
if (NULL == (msg_upgrade = HAL_Malloc(MSG_UPGPGRADE_LEN))) {
|
||||
Log_e("allocate for msg_informed failed");
|
||||
h_ota->err = IOT_OTA_ERR_NOMEM;
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
ret = qcloud_otalib_gen_report_msg(msg_upgrade, MSG_UPGPGRADE_LEN, 1, version, 1, reportType);
|
||||
if (ret != 0) {
|
||||
Log_e("generate inform message failed");
|
||||
h_ota->err = ret;
|
||||
ret = QCLOUD_ERR_FAILURE;
|
||||
goto do_exit;
|
||||
}
|
||||
|
||||
ret = qcloud_osc_report_upgrade_result(h_ota->ch_signal, msg_upgrade);
|
||||
if (0 > ret) {
|
||||
Log_e("Report version failed");
|
||||
h_ota->err = ret;
|
||||
ret = QCLOUD_ERR_FAILURE;
|
||||
goto do_exit;
|
||||
}
|
||||
|
||||
IOT_OTA_ResetStatus(h_ota);
|
||||
|
||||
do_exit:
|
||||
if (NULL != msg_upgrade) {
|
||||
HAL_Free(msg_upgrade);
|
||||
}
|
||||
return ret;
|
||||
|
||||
#undef MSG_UPGPGRADE_LEN
|
||||
}
|
||||
|
||||
/* Init OTA handle */
|
||||
void *IOT_OTA_Init(const char *product_id, const char *device_name, void *ch_signal)
|
||||
{
|
||||
POINTER_SANITY_CHECK(product_id, NULL);
|
||||
POINTER_SANITY_CHECK(device_name, NULL);
|
||||
POINTER_SANITY_CHECK(ch_signal, NULL);
|
||||
|
||||
OTA_Struct_t *h_ota = NULL;
|
||||
|
||||
if (NULL == (h_ota = HAL_Malloc(sizeof(OTA_Struct_t)))) {
|
||||
Log_e("allocate failed");
|
||||
return NULL;
|
||||
}
|
||||
memset(h_ota, 0, sizeof(OTA_Struct_t));
|
||||
h_ota->state = IOT_OTAS_UNINITED;
|
||||
|
||||
h_ota->ch_signal = qcloud_osc_init(product_id, device_name, ch_signal, _ota_callback, h_ota);
|
||||
if (NULL == h_ota->ch_signal) {
|
||||
Log_e("initialize signal channel failed");
|
||||
goto do_exit;
|
||||
}
|
||||
|
||||
h_ota->md5 = qcloud_otalib_md5_init();
|
||||
if (NULL == h_ota->md5) {
|
||||
Log_e("initialize md5 failed");
|
||||
goto do_exit;
|
||||
}
|
||||
|
||||
h_ota->product_id = product_id;
|
||||
h_ota->device_name = device_name;
|
||||
h_ota->state = IOT_OTAS_INITED;
|
||||
#ifdef OTA_MQTT_CHANNEL
|
||||
h_ota->current_signal_type = MQTT_CHANNEL;
|
||||
#else
|
||||
h_ota->current_signal_type = COAP_CHANNEL;
|
||||
#endif
|
||||
return h_ota;
|
||||
|
||||
do_exit:
|
||||
|
||||
if (NULL != h_ota->ch_signal) {
|
||||
qcloud_osc_deinit(h_ota->ch_signal);
|
||||
}
|
||||
|
||||
if (NULL != h_ota->md5) {
|
||||
qcloud_otalib_md5_deinit(h_ota->md5);
|
||||
}
|
||||
|
||||
if (NULL != h_ota) {
|
||||
HAL_Free(h_ota);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
#undef AOM_INFO_MSG_LEN
|
||||
}
|
||||
|
||||
/* Destroy OTA handle and resource */
|
||||
int IOT_OTA_Destroy(void *handle)
|
||||
{
|
||||
OTA_Struct_t *h_ota = (OTA_Struct_t *)handle;
|
||||
|
||||
if (NULL == h_ota) {
|
||||
Log_e("handle is NULL");
|
||||
return IOT_OTA_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (IOT_OTAS_UNINITED == h_ota->state) {
|
||||
Log_e("handle is uninitialized");
|
||||
h_ota->err = IOT_OTA_ERR_INVALID_STATE;
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
qcloud_osc_deinit(h_ota->ch_signal);
|
||||
qcloud_ofc_deinit(h_ota->ch_fetch);
|
||||
qcloud_otalib_md5_deinit(h_ota->md5);
|
||||
|
||||
if (NULL != h_ota->purl) {
|
||||
HAL_Free(h_ota->purl);
|
||||
}
|
||||
|
||||
if (NULL != h_ota->version) {
|
||||
HAL_Free(h_ota->version);
|
||||
}
|
||||
|
||||
HAL_Free(h_ota);
|
||||
return QCLOUD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
/*support continuous transmission of breakpoints*/
|
||||
int IOT_OTA_StartDownload(void *handle, uint32_t offset, uint32_t size)
|
||||
{
|
||||
OTA_Struct_t *h_ota = (OTA_Struct_t *)handle;
|
||||
int Ret;
|
||||
|
||||
Log_d("to download FW from offset: %u, size: %u", offset, size);
|
||||
h_ota->size_fetched = offset;
|
||||
h_ota->ch_fetch = ofc_Init(h_ota->purl, offset, size);
|
||||
if (NULL == h_ota->ch_fetch) {
|
||||
Log_e("Initialize fetch module failed");
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
Ret = qcloud_ofc_connect(h_ota->ch_fetch);
|
||||
if (QCLOUD_RET_SUCCESS != Ret) {
|
||||
Log_e("Connect fetch module failed");
|
||||
h_ota->state = IOT_OTAS_DISCONNECTED;
|
||||
}
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
/*support continuous transmission of breakpoints*/
|
||||
void IOT_OTA_UpdateClientMd5(void *handle, char *buff, uint32_t size)
|
||||
{
|
||||
OTA_Struct_t *h_ota = (OTA_Struct_t *)handle;
|
||||
|
||||
qcloud_otalib_md5_update(h_ota->md5, buff, size);
|
||||
}
|
||||
|
||||
/*support continuous transmission of breakpoints*/
|
||||
int IOT_OTA_ResetClientMD5(void *handle)
|
||||
{
|
||||
OTA_Struct_t *h_ota = (OTA_Struct_t *)handle;
|
||||
|
||||
qcloud_otalib_md5_deinit(h_ota->md5);
|
||||
h_ota->md5 = qcloud_otalib_md5_init();
|
||||
if (NULL == h_ota->md5) {
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
return QCLOUD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
int IOT_OTA_ReportVersion(void *handle, const char *version)
|
||||
{
|
||||
#define MSG_INFORM_LEN (128)
|
||||
|
||||
int ret, len;
|
||||
char * msg_informed;
|
||||
OTA_Struct_t *h_ota = (OTA_Struct_t *)handle;
|
||||
|
||||
POINTER_SANITY_CHECK(handle, IOT_OTA_ERR_INVALID_PARAM);
|
||||
POINTER_SANITY_CHECK(version, IOT_OTA_ERR_INVALID_PARAM);
|
||||
|
||||
len = strlen(version);
|
||||
if ((len < OTA_VERSION_STR_LEN_MIN) || (len > OTA_VERSION_STR_LEN_MAX)) {
|
||||
Log_e("version string is invalid: must be [1, 32] chars");
|
||||
h_ota->err = IOT_OTA_ERR_INVALID_PARAM;
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
if (IOT_OTAS_UNINITED == h_ota->state) {
|
||||
Log_e("handle is uninitialized");
|
||||
h_ota->err = IOT_OTA_ERR_INVALID_STATE;
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
IOT_OTA_ResetStatus(h_ota);
|
||||
|
||||
if (NULL == (msg_informed = HAL_Malloc(MSG_INFORM_LEN))) {
|
||||
Log_e("allocate for msg_informed failed");
|
||||
h_ota->err = IOT_OTA_ERR_NOMEM;
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
ret = qcloud_otalib_gen_info_msg(msg_informed, MSG_INFORM_LEN, h_ota->id, version);
|
||||
if (ret != 0) {
|
||||
Log_e("generate inform message failed");
|
||||
h_ota->err = ret;
|
||||
ret = QCLOUD_ERR_FAILURE;
|
||||
goto do_exit;
|
||||
}
|
||||
|
||||
ret = qcloud_osc_report_version(h_ota->ch_signal, msg_informed);
|
||||
if (0 > ret) {
|
||||
Log_e("Report version failed");
|
||||
h_ota->err = ret;
|
||||
ret = QCLOUD_ERR_FAILURE;
|
||||
goto do_exit;
|
||||
}
|
||||
|
||||
do_exit:
|
||||
if (NULL != msg_informed) {
|
||||
HAL_Free(msg_informed);
|
||||
}
|
||||
return ret;
|
||||
|
||||
#undef MSG_INFORM_LEN
|
||||
}
|
||||
|
||||
int IOT_OTA_ReportUpgradeBegin(void *handle)
|
||||
{
|
||||
OTA_Struct_t *h_ota = (OTA_Struct_t *)handle;
|
||||
return IOT_OTA_ReportUpgradeResult(handle, h_ota->version, IOT_OTAR_UPGRADE_BEGIN);
|
||||
}
|
||||
|
||||
int IOT_OTA_ReportUpgradeSuccess(void *handle, const char *version)
|
||||
{
|
||||
OTA_Struct_t *h_ota = (OTA_Struct_t *)handle;
|
||||
int ret;
|
||||
|
||||
if (NULL == version) {
|
||||
ret = IOT_OTA_ReportUpgradeResult(handle, h_ota->version, IOT_OTAR_UPGRADE_SUCCESS);
|
||||
} else {
|
||||
ret = IOT_OTA_ReportUpgradeResult(handle, version, IOT_OTAR_UPGRADE_SUCCESS);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int IOT_OTA_ReportUpgradeFail(void *handle, const char *version)
|
||||
{
|
||||
OTA_Struct_t *h_ota = (OTA_Struct_t *)handle;
|
||||
int ret;
|
||||
|
||||
if (NULL == version) {
|
||||
ret = IOT_OTA_ReportUpgradeResult(handle, h_ota->version, IOT_OTAR_UPGRADE_FAIL);
|
||||
} else {
|
||||
ret = IOT_OTA_ReportUpgradeResult(handle, version, IOT_OTAR_UPGRADE_FAIL);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* check whether is downloading */
|
||||
int IOT_OTA_IsFetching(void *handle)
|
||||
{
|
||||
OTA_Struct_t *h_ota = (OTA_Struct_t *)handle;
|
||||
|
||||
if (NULL == handle) {
|
||||
Log_e("handle is NULL");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (IOT_OTAS_UNINITED == h_ota->state) {
|
||||
Log_e("handle is uninitialized");
|
||||
h_ota->err = IOT_OTA_ERR_INVALID_STATE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (IOT_OTAS_FETCHING == h_ota->state);
|
||||
}
|
||||
|
||||
/* check whether fetch over */
|
||||
int IOT_OTA_IsFetchFinish(void *handle)
|
||||
{
|
||||
OTA_Struct_t *h_ota = (OTA_Struct_t *)handle;
|
||||
|
||||
if (NULL == handle) {
|
||||
Log_e("handle is NULL");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (IOT_OTAS_UNINITED == h_ota->state) {
|
||||
Log_e("handle is uninitialized");
|
||||
h_ota->err = IOT_OTA_ERR_INVALID_STATE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (IOT_OTAS_FETCHED == h_ota->state);
|
||||
}
|
||||
|
||||
int IOT_OTA_FetchYield(void *handle, char *buf, uint32_t buf_len, uint32_t timeout_ms)
|
||||
{
|
||||
int ret;
|
||||
OTA_Struct_t *h_ota = (OTA_Struct_t *)handle;
|
||||
|
||||
POINTER_SANITY_CHECK(handle, IOT_OTA_ERR_INVALID_PARAM);
|
||||
POINTER_SANITY_CHECK(buf, IOT_OTA_ERR_INVALID_PARAM);
|
||||
NUMBERIC_SANITY_CHECK(buf_len, IOT_OTA_ERR_INVALID_PARAM);
|
||||
|
||||
if (IOT_OTAS_FETCHING != h_ota->state) {
|
||||
h_ota->err = IOT_OTA_ERR_INVALID_STATE;
|
||||
return IOT_OTA_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
ret = qcloud_ofc_fetch(h_ota->ch_fetch, buf, buf_len, timeout_ms);
|
||||
if (ret < 0) {
|
||||
h_ota->state = IOT_OTAS_FETCHED;
|
||||
h_ota->err = IOT_OTA_ERR_FETCH_FAILED;
|
||||
|
||||
if (ret == IOT_OTA_ERR_FETCH_AUTH_FAIL) { // OTA auth failed
|
||||
IOT_OTA_ReportUpgradeResult(h_ota, h_ota->version, IOT_OTAR_AUTH_FAIL);
|
||||
h_ota->err = ret;
|
||||
} else if (ret == IOT_OTA_ERR_FETCH_NOT_EXIST) { // fetch not existed
|
||||
IOT_OTA_ReportUpgradeResult(h_ota, h_ota->version, IOT_OTAR_FILE_NOT_EXIST);
|
||||
h_ota->err = ret;
|
||||
} else if (ret == IOT_OTA_ERR_FETCH_TIMEOUT) { // fetch timeout
|
||||
IOT_OTA_ReportUpgradeResult(h_ota, h_ota->version, IOT_OTAR_DOWNLOAD_TIMEOUT);
|
||||
h_ota->err = ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
} else if (0 == h_ota->size_fetched) {
|
||||
/* force report status in the first */
|
||||
IOT_OTA_ReportProgress(h_ota, IOT_OTAP_FETCH_PERCENTAGE_MIN, IOT_OTAR_DOWNLOAD_BEGIN);
|
||||
|
||||
InitTimer(&h_ota->report_timer);
|
||||
countdown(&h_ota->report_timer, 1);
|
||||
}
|
||||
|
||||
h_ota->size_last_fetched = ret;
|
||||
h_ota->size_fetched += ret;
|
||||
|
||||
/* report percent every second. */
|
||||
uint32_t percent = (h_ota->size_fetched * 100) / h_ota->size_file;
|
||||
if (percent == 100) {
|
||||
IOT_OTA_ReportProgress(h_ota, percent, IOT_OTAR_DOWNLOADING);
|
||||
} else if (h_ota->size_last_fetched > 0 && expired(&h_ota->report_timer)) {
|
||||
IOT_OTA_ReportProgress(h_ota, percent, IOT_OTAR_DOWNLOADING);
|
||||
countdown(&h_ota->report_timer, 1);
|
||||
}
|
||||
|
||||
if (h_ota->size_fetched >= h_ota->size_file) {
|
||||
h_ota->state = IOT_OTAS_FETCHED;
|
||||
}
|
||||
|
||||
qcloud_otalib_md5_update(h_ota->md5, buf, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int IOT_OTA_Ioctl(void *handle, IOT_OTA_CmdType type, void *buf, size_t buf_len)
|
||||
{
|
||||
OTA_Struct_t *h_ota = (OTA_Struct_t *)handle;
|
||||
|
||||
POINTER_SANITY_CHECK(handle, IOT_OTA_ERR_INVALID_PARAM);
|
||||
POINTER_SANITY_CHECK(buf, IOT_OTA_ERR_INVALID_PARAM);
|
||||
NUMBERIC_SANITY_CHECK(buf_len, IOT_OTA_ERR_INVALID_PARAM);
|
||||
|
||||
if (h_ota->state < IOT_OTAS_FETCHING) {
|
||||
h_ota->err = IOT_OTA_ERR_INVALID_STATE;
|
||||
return IOT_OTA_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case IOT_OTAG_FETCHED_SIZE:
|
||||
if ((4 != buf_len) || (0 != ((unsigned long)buf & 0x3))) {
|
||||
Log_e("Invalid parameter");
|
||||
h_ota->err = IOT_OTA_ERR_INVALID_PARAM;
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
} else {
|
||||
*((uint32_t *)buf) = h_ota->size_fetched;
|
||||
return 0;
|
||||
}
|
||||
|
||||
case IOT_OTAG_FILE_SIZE:
|
||||
if ((4 != buf_len) || (0 != ((unsigned long)buf & 0x3))) {
|
||||
Log_e("Invalid parameter");
|
||||
h_ota->err = IOT_OTA_ERR_INVALID_PARAM;
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
} else {
|
||||
*((uint32_t *)buf) = h_ota->size_file;
|
||||
return 0;
|
||||
}
|
||||
|
||||
case IOT_OTAG_VERSION:
|
||||
strncpy(buf, h_ota->version, buf_len);
|
||||
((char *)buf)[buf_len - 1] = '\0';
|
||||
break;
|
||||
|
||||
case IOT_OTAG_MD5SUM:
|
||||
strncpy(buf, h_ota->md5sum, buf_len);
|
||||
((char *)buf)[buf_len - 1] = '\0';
|
||||
break;
|
||||
|
||||
case IOT_OTAG_CHECK_FIRMWARE:
|
||||
if ((4 != buf_len) || (0 != ((unsigned long)buf & 0x3))) {
|
||||
Log_e("Invalid parameter");
|
||||
h_ota->err = IOT_OTA_ERR_INVALID_PARAM;
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
} else if (h_ota->state != IOT_OTAS_FETCHED) {
|
||||
h_ota->err = IOT_OTA_ERR_INVALID_STATE;
|
||||
Log_e("Firmware can be checked in IOT_OTAS_FETCHED state only");
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
} else {
|
||||
char md5_str[33];
|
||||
qcloud_otalib_md5_finalize(h_ota->md5, md5_str);
|
||||
Log_i("FW MD5 check: origin=%s, now=%s", h_ota->md5sum, md5_str);
|
||||
if (0 == strcmp(h_ota->md5sum, md5_str)) {
|
||||
*((uint32_t *)buf) = 1;
|
||||
} else {
|
||||
*((uint32_t *)buf) = 0;
|
||||
// report MD5 inconsistent
|
||||
IOT_OTA_ReportUpgradeResult(h_ota, h_ota->version, IOT_OTAR_MD5_NOT_MATCH);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
default:
|
||||
Log_e("invalid cmd type");
|
||||
h_ota->err = IOT_OTA_ERR_INVALID_PARAM;
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get last error code */
|
||||
int IOT_OTA_GetLastError(void *handle)
|
||||
{
|
||||
OTA_Struct_t *h_ota = (OTA_Struct_t *)handle;
|
||||
|
||||
if (NULL == handle) {
|
||||
Log_e("handle is NULL");
|
||||
return IOT_OTA_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
return h_ota->err;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
201
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/ota/ota_coap.c
vendored
Normal file
201
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/ota/ota_coap.c
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "qcloud_iot_export.h"
|
||||
#include "qcloud_iot_import.h"
|
||||
|
||||
#ifndef OTA_MQTT_CHANNEL
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "ota_client.h"
|
||||
|
||||
typedef struct {
|
||||
void *coap;
|
||||
|
||||
const char *product_id;
|
||||
const char *device_name;
|
||||
|
||||
char topic_upgrade[OTA_MAX_TOPIC_LEN];
|
||||
|
||||
OnOTAMessageCallback msg_callback;
|
||||
|
||||
void *context;
|
||||
} OTA_CoAP_Struct_t;
|
||||
|
||||
static void _otacoap_upgrage_cb(void *coap_message, void *pcontext)
|
||||
{
|
||||
int ret_code = IOT_COAP_GetMessageCode(coap_message);
|
||||
|
||||
switch (ret_code) {
|
||||
case COAP_EVENT_RECEIVE_ACK:
|
||||
Log_i("received OTA message ACK, msgid: %d", IOT_COAP_GetMessageId(coap_message));
|
||||
break;
|
||||
case COAP_EVENT_RECEIVE_RESPCONTENT: {
|
||||
Log_i("received OTA message respconetent.");
|
||||
char *payload = NULL;
|
||||
int payload_len = 0;
|
||||
int ret = -1;
|
||||
ret = IOT_COAP_GetMessagePayload(coap_message, &payload, &payload_len);
|
||||
if (ret == QCLOUD_RET_SUCCESS) {
|
||||
OTA_CoAP_Struct_t *handle = (OTA_CoAP_Struct_t *)pcontext;
|
||||
if (NULL != handle->msg_callback) {
|
||||
handle->msg_callback(handle->context, payload, payload_len);
|
||||
}
|
||||
} else {
|
||||
Log_e("message received response, content error.");
|
||||
}
|
||||
} break;
|
||||
case COAP_EVENT_UNAUTHORIZED:
|
||||
Log_e("coap client auth token expired or invalid, msgid: %d", IOT_COAP_GetMessageId(coap_message));
|
||||
break;
|
||||
case COAP_EVENT_FORBIDDEN:
|
||||
Log_e("coap URI is invalid for this device, msgid: %d", IOT_COAP_GetMessageId(coap_message));
|
||||
break;
|
||||
case COAP_EVENT_INTERNAL_SERVER_ERROR:
|
||||
Log_e("coap server internal error, msgid: %d", IOT_COAP_GetMessageId(coap_message));
|
||||
break;
|
||||
case COAP_EVENT_ACK_TIMEOUT:
|
||||
Log_e("message receive ACK timeout, msgid: %d", IOT_COAP_GetMessageId(coap_message));
|
||||
break;
|
||||
case COAP_EVENT_SEPRESP_TIMEOUT:
|
||||
Log_i("message received ACK but receive response timeout, msgid: %d", IOT_COAP_GetMessageId(coap_message));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate topic name according to @OTATopicType, @productId, @deviceName */
|
||||
/* and then copy to @buf. */
|
||||
/* 0, successful; -1, failed */
|
||||
static int _otacoap_gen_topic_name(char *buf, size_t bufLen, const char *OTATopicType, const char *productId,
|
||||
const char *deviceName)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
int ret;
|
||||
|
||||
ret = HAL_Snprintf(buf, bufLen, "$ota/%s/%s/%s", OTATopicType, productId, deviceName);
|
||||
|
||||
if (ret >= bufLen)
|
||||
IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL);
|
||||
|
||||
if (ret < 0) {
|
||||
Log_e("HAL_Snprintf failed");
|
||||
IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
|
||||
}
|
||||
|
||||
/* report progress of OTA */
|
||||
static int _otacoap_publish(OTA_CoAP_Struct_t *handle, const char *topicType, const char *msg, bool needResp)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
int ret;
|
||||
char topic_name[OTA_MAX_TOPIC_LEN];
|
||||
|
||||
SendMsgParams send_params = DEFAULT_SENDMSG_PARAMS;
|
||||
send_params.pay_load = (void *)msg;
|
||||
send_params.pay_load_len = strlen(msg);
|
||||
send_params.resp_callback = _otacoap_upgrage_cb;
|
||||
send_params.need_resp = needResp;
|
||||
send_params.user_context = handle;
|
||||
|
||||
/* inform OTA to topic: "/ota/device/progress/$(product_id)/$(device_name)" */
|
||||
ret = _otacoap_gen_topic_name(topic_name, OTA_MAX_TOPIC_LEN, topicType, handle->product_id, handle->device_name);
|
||||
if (ret < 0) {
|
||||
Log_e("generate topic name of info failed");
|
||||
IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL);
|
||||
}
|
||||
|
||||
ret = IOT_COAP_SendMessage(handle->coap, topic_name, &send_params);
|
||||
if (ret < 0) {
|
||||
Log_e("publish failed");
|
||||
IOT_FUNC_EXIT_RC(IOT_OTA_ERR_OSC_FAILED);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(ret);
|
||||
}
|
||||
|
||||
void *qcloud_osc_init(const char *productId, const char *deviceName, void *channel, OnOTAMessageCallback callback,
|
||||
void *context)
|
||||
{
|
||||
OTA_CoAP_Struct_t *h_osc = NULL;
|
||||
|
||||
if (NULL == (h_osc = HAL_Malloc(sizeof(OTA_CoAP_Struct_t)))) {
|
||||
Log_e("allocate for h_osc failed");
|
||||
goto do_exit;
|
||||
}
|
||||
|
||||
memset(h_osc, 0, sizeof(OTA_CoAP_Struct_t));
|
||||
|
||||
h_osc->coap = channel;
|
||||
h_osc->product_id = productId;
|
||||
h_osc->device_name = deviceName;
|
||||
h_osc->msg_callback = callback;
|
||||
h_osc->context = context;
|
||||
|
||||
return h_osc;
|
||||
|
||||
do_exit:
|
||||
if (NULL != h_osc) {
|
||||
HAL_Free(h_osc);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int qcloud_osc_deinit(void *handle)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
if (NULL != handle) {
|
||||
HAL_Free(handle);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
|
||||
}
|
||||
|
||||
/* report progress of OTA */
|
||||
int qcloud_osc_report_progress(void *handle, const char *msg)
|
||||
{
|
||||
return _otacoap_publish(handle, "report", msg, false);
|
||||
}
|
||||
|
||||
/* report version of OTA firmware */
|
||||
int qcloud_osc_report_version(void *handle, const char *msg)
|
||||
{
|
||||
return _otacoap_publish(handle, "report", msg, true);
|
||||
}
|
||||
|
||||
/* report upgrade begin of OTA firmware */
|
||||
int qcloud_osc_report_upgrade_result(void *handle, const char *msg)
|
||||
{
|
||||
return _otacoap_publish(handle, "report", msg, false);
|
||||
}
|
||||
|
||||
/* OSC, OTA signal channel */
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
148
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/ota/ota_fetch.c
vendored
Normal file
148
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/ota/ota_fetch.c
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ota_fetch.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "qcloud_iot_ca.h"
|
||||
#include "qcloud_iot_export.h"
|
||||
#include "qcloud_iot_import.h"
|
||||
#include "utils_httpc.h"
|
||||
|
||||
#define OTA_HTTP_HEAD_CONTENT_LEN 256
|
||||
|
||||
/* ofc, OTA fetch channel */
|
||||
|
||||
typedef struct {
|
||||
const char * url;
|
||||
HTTPClient http; /* http client */
|
||||
HTTPClientData http_data; /* http client data */
|
||||
|
||||
} OTAHTTPStruct;
|
||||
|
||||
#ifdef OTA_USE_HTTPS
|
||||
static int is_begin_with(const char *str1, char *str2)
|
||||
{
|
||||
if (str1 == NULL || str2 == NULL)
|
||||
return -1;
|
||||
int len1 = strlen(str1);
|
||||
int len2 = strlen(str2);
|
||||
if ((len1 < len2) || (len1 == 0 || len2 == 0))
|
||||
return -1;
|
||||
char *p = str2;
|
||||
int i = 0;
|
||||
while (*p != '\0') {
|
||||
if (*p != str1[i])
|
||||
return 0;
|
||||
p++;
|
||||
i++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static char sg_head_content[OTA_HTTP_HEAD_CONTENT_LEN];
|
||||
void * ofc_Init(const char *url, uint32_t offset, uint32_t size)
|
||||
{
|
||||
OTAHTTPStruct *h_odc;
|
||||
|
||||
if (NULL == (h_odc = HAL_Malloc(sizeof(OTAHTTPStruct)))) {
|
||||
Log_e("allocate for h_odc failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(h_odc, 0, sizeof(OTAHTTPStruct));
|
||||
memset(sg_head_content, 0, OTA_HTTP_HEAD_CONTENT_LEN);
|
||||
HAL_Snprintf(sg_head_content, OTA_HTTP_HEAD_CONTENT_LEN,
|
||||
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
|
||||
"Accept-Encoding: gzip, deflate\r\n"
|
||||
"Range: bytes=%d-%d\r\n",
|
||||
offset, size);
|
||||
|
||||
Log_d("head_content:%s", sg_head_content);
|
||||
/* set http request-header parameter */
|
||||
h_odc->http.header = sg_head_content;
|
||||
h_odc->url = url;
|
||||
|
||||
return h_odc;
|
||||
}
|
||||
|
||||
int32_t qcloud_ofc_connect(void *handle)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
OTAHTTPStruct *h_odc = (OTAHTTPStruct *)handle;
|
||||
|
||||
int port = 80;
|
||||
const char *ca_crt = NULL;
|
||||
|
||||
#ifdef OTA_USE_HTTPS
|
||||
if (is_begin_with(h_odc->url, "https")) {
|
||||
port = 443;
|
||||
ca_crt = iot_https_ca_get();
|
||||
}
|
||||
#endif
|
||||
|
||||
int32_t rc = qcloud_http_client_common(&h_odc->http, h_odc->url, port, ca_crt, HTTP_GET, &h_odc->http_data);
|
||||
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
int32_t qcloud_ofc_fetch(void *handle, char *buf, uint32_t bufLen, uint32_t timeout_s)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
int diff;
|
||||
OTAHTTPStruct *h_odc = (OTAHTTPStruct *)handle;
|
||||
|
||||
h_odc->http_data.response_buf = buf;
|
||||
h_odc->http_data.response_buf_len = bufLen;
|
||||
diff = h_odc->http_data.response_content_len - h_odc->http_data.retrieve_len;
|
||||
|
||||
int rc = qcloud_http_recv_data(&h_odc->http, timeout_s * 1000, &h_odc->http_data);
|
||||
if (QCLOUD_RET_SUCCESS != rc) {
|
||||
if (rc == QCLOUD_ERR_HTTP_NOT_FOUND)
|
||||
IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FETCH_NOT_EXIST);
|
||||
|
||||
if (rc == QCLOUD_ERR_HTTP_AUTH)
|
||||
IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FETCH_AUTH_FAIL);
|
||||
|
||||
if (rc == QCLOUD_ERR_HTTP_TIMEOUT)
|
||||
IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FETCH_TIMEOUT);
|
||||
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(h_odc->http_data.response_content_len - h_odc->http_data.retrieve_len - diff);
|
||||
}
|
||||
|
||||
int qcloud_ofc_deinit(void *handle)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
if (NULL != handle) {
|
||||
HAL_Free(handle);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
318
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/ota/ota_lib.c
vendored
Normal file
318
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/ota/ota_lib.c
vendored
Normal file
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ota_lib.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lite-utils.h"
|
||||
#include "ota_client.h"
|
||||
#include "qcloud_iot_export.h"
|
||||
#include "qcloud_iot_import.h"
|
||||
#include "utils_md5.h"
|
||||
|
||||
/* Get the specific @key value, and copy to @dest */
|
||||
/* 0, successful; -1, failed */
|
||||
static int _qcloud_otalib_get_firmware_fixlen_para(const char *json_doc, const char *key, char *dest, size_t dest_len)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
int ret = QCLOUD_RET_SUCCESS;
|
||||
|
||||
char *key_bak = HAL_Malloc(strlen(key) + 1);
|
||||
if (key_bak == NULL) {
|
||||
Log_e("not enough memory for malloc key");
|
||||
ret = IOT_OTA_ERR_FAIL;
|
||||
IOT_FUNC_EXIT_RC(ret);
|
||||
}
|
||||
|
||||
char *json_doc_bak = HAL_Malloc(strlen(json_doc) + 1);
|
||||
if (json_doc_bak == NULL) {
|
||||
Log_e("not enough memory for malloc json");
|
||||
HAL_Free(key_bak);
|
||||
ret = IOT_OTA_ERR_FAIL;
|
||||
IOT_FUNC_EXIT_RC(ret);
|
||||
}
|
||||
|
||||
strcpy(key_bak, key);
|
||||
strcpy(json_doc_bak, json_doc);
|
||||
|
||||
char *value = LITE_json_value_of(key_bak, json_doc_bak);
|
||||
if (value == NULL) {
|
||||
Log_e("Not '%s' key in json doc of OTA", key);
|
||||
ret = IOT_OTA_ERR_FAIL;
|
||||
} else {
|
||||
uint32_t val_len = strlen(value);
|
||||
if (val_len > dest_len) {
|
||||
Log_e("value length of the key is too long");
|
||||
ret = IOT_OTA_ERR_FAIL;
|
||||
} else {
|
||||
memcpy(dest, value, val_len);
|
||||
ret = QCLOUD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
HAL_Free(value);
|
||||
}
|
||||
|
||||
if (key_bak != NULL) {
|
||||
HAL_Free(key_bak);
|
||||
}
|
||||
if (json_doc_bak != NULL) {
|
||||
HAL_Free(json_doc_bak);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(ret);
|
||||
}
|
||||
|
||||
/* Get variant length parameter of firmware, and copy to @dest */
|
||||
/* 0, successful; -1, failed */
|
||||
static int _qcloud_otalib_get_firmware_varlen_para(const char *json_doc, const char *key, char **dest)
|
||||
{
|
||||
#define OTA_FIRMWARE_JSON_VALUE_MAX_LENGTH (64)
|
||||
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
int ret = QCLOUD_RET_SUCCESS;
|
||||
|
||||
char *key_bak = HAL_Malloc(strlen(key) + 1);
|
||||
if (key_bak == NULL) {
|
||||
Log_e("not enough memory for malloc key");
|
||||
ret = IOT_OTA_ERR_FAIL;
|
||||
IOT_FUNC_EXIT_RC(ret);
|
||||
}
|
||||
|
||||
char *json_doc_bak = HAL_Malloc(strlen(json_doc) + 1);
|
||||
if (json_doc_bak == NULL) {
|
||||
Log_e("not enough memory for malloc json");
|
||||
HAL_Free(key_bak);
|
||||
ret = IOT_OTA_ERR_FAIL;
|
||||
IOT_FUNC_EXIT_RC(ret);
|
||||
}
|
||||
|
||||
strcpy(key_bak, key);
|
||||
strcpy(json_doc_bak, json_doc);
|
||||
|
||||
*dest = LITE_json_value_of(key_bak, json_doc_bak);
|
||||
if (*dest == NULL) {
|
||||
Log_e("Not '%s' key in json '%s' doc of OTA", key_bak, json_doc_bak);
|
||||
ret = IOT_OTA_ERR_FAIL;
|
||||
}
|
||||
|
||||
if (key_bak != NULL) {
|
||||
HAL_Free(key_bak);
|
||||
}
|
||||
if (json_doc_bak != NULL) {
|
||||
HAL_Free(json_doc_bak);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(ret);
|
||||
|
||||
#undef OTA_FIRMWARE_JSON_VALUE_MAX_LENGTH
|
||||
}
|
||||
|
||||
void *qcloud_otalib_md5_init(void)
|
||||
{
|
||||
iot_md5_context *ctx = HAL_Malloc(sizeof(iot_md5_context));
|
||||
if (NULL == ctx) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
utils_md5_init(ctx);
|
||||
utils_md5_starts(ctx);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void qcloud_otalib_md5_update(void *md5, const char *buf, size_t buf_len)
|
||||
{
|
||||
utils_md5_update(md5, (unsigned char *)buf, buf_len);
|
||||
}
|
||||
|
||||
void qcloud_otalib_md5_finalize(void *md5, char *output_str)
|
||||
{
|
||||
int i;
|
||||
unsigned char buf_out[16];
|
||||
utils_md5_finish(md5, buf_out);
|
||||
|
||||
for (i = 0; i < 16; ++i) {
|
||||
output_str[i * 2] = utils_hb2hex(buf_out[i] >> 4);
|
||||
output_str[i * 2 + 1] = utils_hb2hex(buf_out[i]);
|
||||
}
|
||||
output_str[32] = '\0';
|
||||
}
|
||||
|
||||
void qcloud_otalib_md5_deinit(void *md5)
|
||||
{
|
||||
if (NULL != md5) {
|
||||
HAL_Free(md5);
|
||||
}
|
||||
}
|
||||
|
||||
int qcloud_otalib_get_firmware_type(const char *json, char **type)
|
||||
{
|
||||
return _qcloud_otalib_get_firmware_varlen_para(json, TYPE_FIELD, type);
|
||||
}
|
||||
|
||||
int qcloud_otalib_get_report_version_result(const char *json)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
char *result_code = NULL;
|
||||
|
||||
int rc = _qcloud_otalib_get_firmware_varlen_para(json, RESULT_FIELD, &result_code);
|
||||
if (rc != QCLOUD_RET_SUCCESS || strcmp(result_code, "0") != 0) {
|
||||
if (NULL != result_code)
|
||||
HAL_Free(result_code);
|
||||
IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL);
|
||||
}
|
||||
|
||||
if (NULL != result_code)
|
||||
HAL_Free(result_code);
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
|
||||
}
|
||||
|
||||
int qcloud_otalib_get_params(const char *json, char **type, char **url, char **version, char *md5, uint32_t *fileSize)
|
||||
{
|
||||
#define OTA_FILESIZE_STR_LEN (16)
|
||||
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
char file_size_str[OTA_FILESIZE_STR_LEN + 1] = {0};
|
||||
|
||||
/* get type */
|
||||
if (0 != _qcloud_otalib_get_firmware_varlen_para(json, TYPE_FIELD, type)) {
|
||||
Log_e("get value of type key failed");
|
||||
IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL);
|
||||
}
|
||||
|
||||
/* get version */
|
||||
if (0 != _qcloud_otalib_get_firmware_varlen_para(json, VERSION_FIELD, version)) {
|
||||
Log_e("get value of version key failed");
|
||||
IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL);
|
||||
}
|
||||
|
||||
/* get URL */
|
||||
if (0 != _qcloud_otalib_get_firmware_varlen_para(json, URL_FIELD, url)) {
|
||||
Log_e("get value of url key failed");
|
||||
IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL);
|
||||
}
|
||||
|
||||
/* get md5 */
|
||||
if (0 != _qcloud_otalib_get_firmware_fixlen_para(json, MD5_FIELD, md5, 32)) {
|
||||
Log_e("get value of md5 key failed");
|
||||
IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL);
|
||||
}
|
||||
|
||||
/* get file size */
|
||||
if (0 != _qcloud_otalib_get_firmware_fixlen_para(json, FILESIZE_FIELD, file_size_str, OTA_FILESIZE_STR_LEN)) {
|
||||
Log_e("get value of size key failed");
|
||||
IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL);
|
||||
}
|
||||
|
||||
file_size_str[OTA_FILESIZE_STR_LEN] = '\0';
|
||||
*fileSize = atoi(file_size_str);
|
||||
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
|
||||
|
||||
#undef OTA_FILESIZE_STR_LEN
|
||||
}
|
||||
|
||||
int qcloud_otalib_gen_info_msg(char *buf, size_t bufLen, uint32_t id, const char *version)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
int ret;
|
||||
ret = HAL_Snprintf(buf, bufLen, "{\"type\": \"report_version\", \"report\":{\"version\":\"%s\"}}", version);
|
||||
|
||||
if (ret < 0) {
|
||||
Log_e("HAL_Snprintf failed");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
|
||||
}
|
||||
|
||||
int qcloud_otalib_gen_report_msg(char *buf, size_t bufLen, uint32_t id, const char *version, int progress,
|
||||
IOT_OTAReportType reportType)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
int ret;
|
||||
|
||||
switch (reportType) {
|
||||
/* report OTA download begin */
|
||||
case IOT_OTAR_DOWNLOAD_BEGIN:
|
||||
ret = HAL_Snprintf(buf, bufLen,
|
||||
"{\"type\": \"report_progress\", \"report\": {\"progress\": {\"state\":\"downloading\", "
|
||||
"\"percent\":\"0\", \"result_code\":\"0\", \"result_msg\":\"\"}, \"version\": \"%s\"}}",
|
||||
version);
|
||||
break;
|
||||
/* report OTA download progress */
|
||||
case IOT_OTAR_DOWNLOADING:
|
||||
ret = HAL_Snprintf(buf, bufLen,
|
||||
"{\"type\": \"report_progress\", \"report\": {\"progress\": {\"state\":\"downloading\", "
|
||||
"\"percent\":\"%d\", \"result_code\":\"0\", \"result_msg\":\"\"}, \"version\": \"%s\"}}",
|
||||
progress, version);
|
||||
break;
|
||||
case IOT_OTAR_DOWNLOAD_TIMEOUT:
|
||||
case IOT_OTAR_FILE_NOT_EXIST:
|
||||
case IOT_OTAR_MD5_NOT_MATCH:
|
||||
case IOT_OTAR_AUTH_FAIL:
|
||||
case IOT_OTAR_UPGRADE_FAIL:
|
||||
ret = HAL_Snprintf(buf, bufLen,
|
||||
"{\"type\": \"report_progress\", \"report\": {\"progress\": {\"state\":\"fail\", "
|
||||
"\"result_code\":\"%d\", \"result_msg\":\"time_out\"}, \"version\": \"%s\"}}",
|
||||
reportType, version);
|
||||
break;
|
||||
/* report OTA upgrade begin */
|
||||
case IOT_OTAR_UPGRADE_BEGIN:
|
||||
ret = HAL_Snprintf(buf, bufLen,
|
||||
"{\"type\": \"report_progress\", \"report\":{\"progress\":{\"state\":\"burning\", "
|
||||
"\"result_code\":\"0\", \"result_msg\":\"\"}, \"version\":\"%s\"}}",
|
||||
version);
|
||||
break;
|
||||
|
||||
/* report OTA upgrade finish */
|
||||
case IOT_OTAR_UPGRADE_SUCCESS:
|
||||
ret = HAL_Snprintf(buf, bufLen,
|
||||
"{\"type\": \"report_progress\", \"report\":{\"progress\":{\"state\":\"done\", "
|
||||
"\"result_code\":\"0\", \"result_msg\":\"\"}, \"version\":\"%s\"}}",
|
||||
version);
|
||||
break;
|
||||
|
||||
default:
|
||||
IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
Log_e("HAL_Snprintf failed");
|
||||
IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL);
|
||||
} else if (ret >= bufLen) {
|
||||
Log_e("msg is too long");
|
||||
IOT_FUNC_EXIT_RC(IOT_OTA_ERR_STR_TOO_LONG);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
242
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/ota/ota_mqtt.c
vendored
Normal file
242
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/ota/ota_mqtt.c
vendored
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "qcloud_iot_export.h"
|
||||
#include "qcloud_iot_import.h"
|
||||
|
||||
#ifdef OTA_MQTT_CHANNEL
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "ota_client.h"
|
||||
|
||||
/* OSC, OTA signal channel */
|
||||
typedef struct {
|
||||
void *mqtt; // MQTT cient
|
||||
|
||||
const char *product_id;
|
||||
const char *device_name;
|
||||
|
||||
char topic_upgrade[OTA_MAX_TOPIC_LEN]; // OTA MQTT Topic
|
||||
OnOTAMessageCallback msg_callback;
|
||||
|
||||
void *context;
|
||||
bool topic_ready;
|
||||
} OTA_MQTT_Struct_t;
|
||||
|
||||
/* Generate topic name according to @OTATopicType, @productId, @deviceName */
|
||||
/* and then copy to @buf. */
|
||||
/* 0, successful; -1, failed */
|
||||
static int _otamqtt_gen_topic_name(char *buf, size_t bufLen, const char *OTATopicType, const char *productId,
|
||||
const char *deviceName)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
int ret;
|
||||
|
||||
ret = HAL_Snprintf(buf, bufLen, "$ota/%s/%s/%s", OTATopicType, productId, deviceName);
|
||||
|
||||
if (ret >= bufLen)
|
||||
IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL);
|
||||
|
||||
if (ret < 0) {
|
||||
Log_e("HAL_Snprintf failed");
|
||||
IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
|
||||
}
|
||||
|
||||
/* report progress of OTA */
|
||||
static int _otamqtt_publish(OTA_MQTT_Struct_t *handle, const char *topicType, int qos, const char *msg)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
int ret;
|
||||
char topic_name[OTA_MAX_TOPIC_LEN];
|
||||
PublishParams pub_params = DEFAULT_PUB_PARAMS;
|
||||
|
||||
if (0 == qos) {
|
||||
pub_params.qos = QOS0;
|
||||
} else {
|
||||
pub_params.qos = QOS1;
|
||||
}
|
||||
pub_params.payload = (void *)msg;
|
||||
pub_params.payload_len = strlen(msg);
|
||||
|
||||
/* inform OTA to topic: "/ota/device/progress/$(product_id)/$(device_name)" */
|
||||
ret = _otamqtt_gen_topic_name(topic_name, OTA_MAX_TOPIC_LEN, topicType, handle->product_id, handle->device_name);
|
||||
if (ret < 0) {
|
||||
Log_e("generate topic name of info failed");
|
||||
IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL);
|
||||
}
|
||||
|
||||
ret = IOT_MQTT_Publish(handle->mqtt, topic_name, &pub_params);
|
||||
if (ret < 0) {
|
||||
Log_e("publish to topic: %s failed", topic_name);
|
||||
IOT_FUNC_EXIT_RC(IOT_OTA_ERR_OSC_FAILED);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(ret);
|
||||
}
|
||||
|
||||
/* callback after OTA topic is subscribed */
|
||||
/* Parse firmware info (version/URL/file size/MD5) from JSON text */
|
||||
static void _otamqtt_upgrage_cb(void *pClient, MQTTMessage *message, void *pcontext)
|
||||
{
|
||||
OTA_MQTT_Struct_t *handle = (OTA_MQTT_Struct_t *)pcontext;
|
||||
|
||||
Log_d("topic=%.*s", message->topic_len, message->ptopic);
|
||||
Log_i("len=%u, topic_msg=%.*s", message->payload_len, message->payload_len, (char *)message->payload);
|
||||
|
||||
if (NULL != handle->msg_callback) {
|
||||
handle->msg_callback(handle->context, message->payload, message->payload_len);
|
||||
}
|
||||
}
|
||||
|
||||
static void _otamqtt_event_callback(void *pclient, MQTTEventType event_type, void *user_data)
|
||||
{
|
||||
OTA_MQTT_Struct_t *h_osc = (OTA_MQTT_Struct_t *)user_data;
|
||||
|
||||
switch (event_type) {
|
||||
case MQTT_EVENT_SUBCRIBE_SUCCESS:
|
||||
Log_d("OTA topic subscribe success");
|
||||
h_osc->topic_ready = true;
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBCRIBE_TIMEOUT:
|
||||
Log_i("OTA topic subscribe timeout");
|
||||
h_osc->topic_ready = false;
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBCRIBE_NACK:
|
||||
Log_i("OTA topic subscribe NACK");
|
||||
h_osc->topic_ready = false;
|
||||
break;
|
||||
case MQTT_EVENT_UNSUBSCRIBE:
|
||||
Log_i("OTA topic has been unsubscribed");
|
||||
h_osc->topic_ready = false;
|
||||
;
|
||||
break;
|
||||
case MQTT_EVENT_CLIENT_DESTROY:
|
||||
Log_i("mqtt client has been destroyed");
|
||||
h_osc->topic_ready = false;
|
||||
;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void *qcloud_osc_init(const char *productId, const char *deviceName, void *channel, OnOTAMessageCallback callback,
|
||||
void *context)
|
||||
{
|
||||
int ret;
|
||||
OTA_MQTT_Struct_t *h_osc = NULL;
|
||||
|
||||
if (NULL == (h_osc = HAL_Malloc(sizeof(OTA_MQTT_Struct_t)))) {
|
||||
Log_e("allocate for h_osc failed");
|
||||
goto do_exit;
|
||||
}
|
||||
|
||||
memset(h_osc, 0, sizeof(OTA_MQTT_Struct_t));
|
||||
|
||||
/* subscribe the OTA topic: "$ota/update/$(product_id)/$(device_name)" */
|
||||
ret = _otamqtt_gen_topic_name(h_osc->topic_upgrade, OTA_MAX_TOPIC_LEN, "update", productId, deviceName);
|
||||
if (ret < 0) {
|
||||
Log_e("generate topic name of upgrade failed");
|
||||
goto do_exit;
|
||||
}
|
||||
|
||||
SubscribeParams sub_params = DEFAULT_SUB_PARAMS;
|
||||
sub_params.on_message_handler = _otamqtt_upgrage_cb;
|
||||
sub_params.on_sub_event_handler = _otamqtt_event_callback;
|
||||
sub_params.qos = QOS1;
|
||||
sub_params.user_data = h_osc;
|
||||
|
||||
ret = IOT_MQTT_Subscribe(channel, h_osc->topic_upgrade, &sub_params);
|
||||
if (ret < 0) {
|
||||
Log_e("ota mqtt subscribe failed!");
|
||||
goto do_exit;
|
||||
}
|
||||
|
||||
int wait_cnt = 10;
|
||||
while (!h_osc->topic_ready && (wait_cnt > 0)) {
|
||||
// wait for subscription result
|
||||
IOT_MQTT_Yield(channel, 200);
|
||||
wait_cnt--;
|
||||
}
|
||||
|
||||
if (wait_cnt == 0) {
|
||||
Log_e("ota mqtt subscribe timeout!");
|
||||
goto do_exit;
|
||||
}
|
||||
|
||||
h_osc->mqtt = channel;
|
||||
h_osc->product_id = productId;
|
||||
h_osc->device_name = deviceName;
|
||||
h_osc->msg_callback = callback;
|
||||
h_osc->context = context;
|
||||
|
||||
return h_osc;
|
||||
|
||||
do_exit:
|
||||
if (NULL != h_osc) {
|
||||
HAL_Free(h_osc);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int qcloud_osc_deinit(void *handle)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
if (NULL != handle) {
|
||||
OTA_MQTT_Struct_t *h_osc = (OTA_MQTT_Struct_t *)handle;
|
||||
IOT_MQTT_Unsubscribe(h_osc->mqtt, h_osc->topic_upgrade);
|
||||
HAL_Free(handle);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
|
||||
}
|
||||
|
||||
/* report progress of OTA */
|
||||
int qcloud_osc_report_progress(void *handle, const char *msg)
|
||||
{
|
||||
return _otamqtt_publish(handle, "report", QOS0, msg);
|
||||
}
|
||||
|
||||
/* report version of OTA firmware */
|
||||
int qcloud_osc_report_version(void *handle, const char *msg)
|
||||
{
|
||||
return _otamqtt_publish(handle, "report", QOS1, msg);
|
||||
}
|
||||
|
||||
/* report upgrade begin of OTA firmware */
|
||||
int qcloud_osc_report_upgrade_result(void *handle, const char *msg)
|
||||
{
|
||||
return _otamqtt_publish(handle, "report", QOS1, msg);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
897
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/shadow/shadow_client.c
vendored
Normal file
897
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/shadow/shadow_client.c
vendored
Normal file
@@ -0,0 +1,897 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "shadow_client.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "shadow_client_common.h"
|
||||
#include "shadow_client_json.h"
|
||||
#include "utils_param_check.h"
|
||||
|
||||
static void _init_request_params(RequestParams *pParams, Method method, OnRequestCallback callback, void *userContext,
|
||||
uint8_t timeout_sec)
|
||||
{
|
||||
pParams->method = method;
|
||||
pParams->user_context = userContext;
|
||||
pParams->timeout_sec = timeout_sec;
|
||||
pParams->request_callback = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief check return value of snprintf
|
||||
*
|
||||
* @param returnCode return value of snprintf
|
||||
* @param maxSizeOfWrite max size of write buffer
|
||||
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
|
||||
*/
|
||||
static inline int _check_snprintf_return(int32_t returnCode, size_t maxSizeOfWrite)
|
||||
{
|
||||
if (returnCode >= maxSizeOfWrite) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TRUNCATED;
|
||||
} else if (returnCode < 0) {
|
||||
return QCLOUD_ERR_JSON;
|
||||
}
|
||||
|
||||
return QCLOUD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static void _shadow_event_handler(void *pclient, void *context, MQTTEventMsg *msg)
|
||||
{
|
||||
uintptr_t packet_id = (uintptr_t)msg->msg;
|
||||
Qcloud_IoT_Shadow *shadow_client = (Qcloud_IoT_Shadow *)context;
|
||||
MQTTMessage * topic_info = (MQTTMessage *)msg->msg;
|
||||
|
||||
switch (msg->event_type) {
|
||||
case MQTT_EVENT_SUBCRIBE_SUCCESS:
|
||||
Log_d("shadow subscribe success, packet-id=%u", (unsigned int)packet_id);
|
||||
if (shadow_client->inner_data.sync_status > 0)
|
||||
shadow_client->inner_data.sync_status = 0;
|
||||
break;
|
||||
case MQTT_EVENT_SUBCRIBE_TIMEOUT:
|
||||
Log_d("shadow subscribe wait ack timeout, packet-id=%u", (unsigned int)packet_id);
|
||||
if (shadow_client->inner_data.sync_status > 0)
|
||||
shadow_client->inner_data.sync_status = -1;
|
||||
break;
|
||||
case MQTT_EVENT_SUBCRIBE_NACK:
|
||||
Log_d("shadow subscribe nack, packet-id=%u", (unsigned int)packet_id);
|
||||
if (shadow_client->inner_data.sync_status > 0)
|
||||
shadow_client->inner_data.sync_status = -1;
|
||||
break;
|
||||
case MQTT_EVENT_PUBLISH_RECVEIVED:
|
||||
Log_d("shadow topic message arrived but without any related handle: topic=%.*s, topic_msg=%.*s",
|
||||
topic_info->topic_len, topic_info->ptopic, topic_info->payload_len, topic_info->payload);
|
||||
break;
|
||||
default:
|
||||
/* Log_i("Should NOT arrive here."); */
|
||||
break;
|
||||
}
|
||||
if (shadow_client->event_handle.h_fp != NULL) {
|
||||
shadow_client->event_handle.h_fp(shadow_client, shadow_client->event_handle.context, msg);
|
||||
}
|
||||
}
|
||||
|
||||
static void _copy_shadow_init_params_to_mqtt(MQTTInitParams *pMqttInitParams, ShadowInitParams *shadowInitParams)
|
||||
{
|
||||
pMqttInitParams->device_name = shadowInitParams->device_name;
|
||||
pMqttInitParams->product_id = shadowInitParams->product_id;
|
||||
|
||||
#ifdef AUTH_MODE_CERT
|
||||
memcpy(pMqttInitParams->cert_file, shadowInitParams->cert_file, FILE_PATH_MAX_LEN);
|
||||
memcpy(pMqttInitParams->key_file, shadowInitParams->key_file, FILE_PATH_MAX_LEN);
|
||||
#else
|
||||
pMqttInitParams->device_secret = shadowInitParams->device_secret;
|
||||
#endif
|
||||
|
||||
pMqttInitParams->command_timeout = shadowInitParams->command_timeout;
|
||||
pMqttInitParams->keep_alive_interval_ms = shadowInitParams->keep_alive_interval_ms;
|
||||
pMqttInitParams->clean_session = shadowInitParams->clean_session;
|
||||
pMqttInitParams->auto_connect_enable = shadowInitParams->auto_connect_enable;
|
||||
}
|
||||
|
||||
static void _update_ack_cb(void *pClient, Method method, RequestAck requestAck, const char *pReceivedJsonDocument,
|
||||
void *pUserdata)
|
||||
{
|
||||
Log_d("requestAck=%d", requestAck);
|
||||
|
||||
if (NULL != pReceivedJsonDocument) {
|
||||
Log_d("Received Json Document=%s", pReceivedJsonDocument);
|
||||
} else {
|
||||
Log_d("Received Json Document is NULL");
|
||||
}
|
||||
|
||||
*((RequestAck *)pUserdata) = requestAck;
|
||||
}
|
||||
|
||||
void *IOT_Shadow_Construct(ShadowInitParams *pParams)
|
||||
{
|
||||
POINTER_SANITY_CHECK(pParams, NULL);
|
||||
|
||||
Qcloud_IoT_Shadow *shadow_client = NULL;
|
||||
if ((shadow_client = (Qcloud_IoT_Shadow *)HAL_Malloc(sizeof(Qcloud_IoT_Shadow))) == NULL) {
|
||||
Log_e("memory not enough to malloc ShadowClient");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MQTTInitParams mqtt_init_params;
|
||||
_copy_shadow_init_params_to_mqtt(&mqtt_init_params, pParams);
|
||||
|
||||
mqtt_init_params.event_handle.h_fp = _shadow_event_handler;
|
||||
mqtt_init_params.event_handle.context = shadow_client;
|
||||
|
||||
void *mqtt_client = NULL;
|
||||
if ((mqtt_client = IOT_MQTT_Construct(&mqtt_init_params)) == NULL) {
|
||||
HAL_Free(shadow_client);
|
||||
goto End;
|
||||
}
|
||||
|
||||
memset(shadow_client, 0, sizeof(Qcloud_IoT_Shadow));
|
||||
shadow_client->mqtt = mqtt_client;
|
||||
shadow_client->shadow_type = pParams->shadow_type;
|
||||
shadow_client->event_handle = pParams->event_handle;
|
||||
shadow_client->inner_data.result_topic = NULL;
|
||||
shadow_client->inner_data.token_num = 0;
|
||||
|
||||
int rc;
|
||||
|
||||
rc = qcloud_iot_shadow_init(shadow_client);
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
IOT_Shadow_Destroy(shadow_client);
|
||||
goto End;
|
||||
}
|
||||
|
||||
rc = subscribe_operation_result_to_cloud(shadow_client);
|
||||
if (rc < 0) {
|
||||
Log_e("Subcribe $shadow/operation/results fail!");
|
||||
} else {
|
||||
shadow_client->inner_data.sync_status = rc;
|
||||
while (rc == shadow_client->inner_data.sync_status) {
|
||||
IOT_Shadow_Yield(shadow_client, 100);
|
||||
}
|
||||
if (0 == shadow_client->inner_data.sync_status) {
|
||||
Log_i("Sync device data successfully");
|
||||
} else {
|
||||
Log_e("Sync device data failed");
|
||||
}
|
||||
}
|
||||
|
||||
return shadow_client;
|
||||
|
||||
End:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *IOT_Shadow_Get_Mqtt_Client(void *handle)
|
||||
{
|
||||
POINTER_SANITY_CHECK(handle, NULL);
|
||||
|
||||
Qcloud_IoT_Shadow *shadow = (Qcloud_IoT_Shadow *)handle;
|
||||
|
||||
return shadow->mqtt;
|
||||
}
|
||||
|
||||
int IOT_Shadow_Publish(void *handle, char *topicName, PublishParams *pParams)
|
||||
{
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Shadow *shadow = (Qcloud_IoT_Shadow *)handle;
|
||||
|
||||
return qcloud_iot_mqtt_publish(shadow->mqtt, topicName, pParams);
|
||||
}
|
||||
|
||||
int IOT_Shadow_Subscribe(void *handle, char *topicFilter, SubscribeParams *pParams)
|
||||
{
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Shadow *shadow = (Qcloud_IoT_Shadow *)handle;
|
||||
|
||||
return qcloud_iot_mqtt_subscribe(shadow->mqtt, topicFilter, pParams);
|
||||
}
|
||||
|
||||
int IOT_Shadow_Unsubscribe(void *handle, char *topicFilter)
|
||||
{
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Shadow *shadow = (Qcloud_IoT_Shadow *)handle;
|
||||
|
||||
return qcloud_iot_mqtt_unsubscribe(shadow->mqtt, topicFilter);
|
||||
}
|
||||
|
||||
bool IOT_Shadow_IsConnected(void *handle)
|
||||
{
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Shadow *pshadow = (Qcloud_IoT_Shadow *)handle;
|
||||
|
||||
IOT_FUNC_EXIT_RC(IOT_MQTT_IsConnected(pshadow->mqtt))
|
||||
}
|
||||
|
||||
int IOT_Shadow_Destroy(void *handle)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Shadow *shadow_client = (Qcloud_IoT_Shadow *)handle;
|
||||
qcloud_iot_shadow_reset(handle);
|
||||
|
||||
IOT_MQTT_Destroy(&shadow_client->mqtt);
|
||||
|
||||
if (NULL != shadow_client->mutex) {
|
||||
HAL_MutexDestroy(shadow_client->mutex);
|
||||
}
|
||||
|
||||
if (NULL != shadow_client->inner_data.result_topic) {
|
||||
HAL_Free(shadow_client->inner_data.result_topic);
|
||||
shadow_client->inner_data.result_topic = NULL;
|
||||
}
|
||||
|
||||
HAL_Free(handle);
|
||||
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS)
|
||||
}
|
||||
|
||||
int IOT_Shadow_Yield(void *handle, uint32_t timeout_ms)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
int rc;
|
||||
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
NUMBERIC_SANITY_CHECK(timeout_ms, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Shadow *pshadow = (Qcloud_IoT_Shadow *)handle;
|
||||
POINTER_SANITY_CHECK(pshadow, QCLOUD_ERR_INVAL);
|
||||
|
||||
handle_expired_request(pshadow);
|
||||
|
||||
rc = IOT_MQTT_Yield(pshadow->mqtt, timeout_ms);
|
||||
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
int IOT_Shadow_Register_Property(void *handle, DeviceProperty *pProperty, OnPropRegCallback callback)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Shadow *pshadow = (Qcloud_IoT_Shadow *)handle;
|
||||
int rc;
|
||||
|
||||
if (IOT_MQTT_IsConnected(pshadow->mqtt) == false) {
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
|
||||
}
|
||||
|
||||
if (shadow_common_check_property_existence(pshadow, pProperty))
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_SHADOW_PROPERTY_EXIST);
|
||||
|
||||
rc = shadow_common_register_property_on_delta(pshadow, pProperty, callback);
|
||||
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
int IOT_Shadow_UnRegister_Property(void *handle, DeviceProperty *pProperty)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
Qcloud_IoT_Shadow *pshadow = (Qcloud_IoT_Shadow *)handle;
|
||||
|
||||
if (IOT_MQTT_IsConnected(pshadow->mqtt) == false) {
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
|
||||
}
|
||||
|
||||
if (!shadow_common_check_property_existence(pshadow, pProperty)) {
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_SHADOW_NOT_PROPERTY_EXIST);
|
||||
}
|
||||
int rc = shadow_common_remove_property(pshadow, pProperty);
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
int IOT_Shadow_Update(void *handle, char *pJsonDoc, size_t sizeOfBuffer, OnRequestCallback callback, void *userContext,
|
||||
uint32_t timeout_ms)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
int rc;
|
||||
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(pJsonDoc, QCLOUD_ERR_INVAL);
|
||||
NUMBERIC_SANITY_CHECK(timeout_ms, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Shadow *shadow = (Qcloud_IoT_Shadow *)handle;
|
||||
|
||||
if (IOT_MQTT_IsConnected(shadow->mqtt) == false) {
|
||||
Log_e("shadow is disconnected");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
|
||||
}
|
||||
|
||||
// subscribe topic $shadow/operation/result if not subscribed yet
|
||||
if (shadow->inner_data.sync_status < 0) {
|
||||
subscribe_operation_result_to_cloud(shadow);
|
||||
}
|
||||
|
||||
Log_d("UPDATE Request Document: %s", pJsonDoc);
|
||||
|
||||
RequestParams request_params = DEFAULT_REQUEST_PARAMS;
|
||||
_init_request_params(&request_params, UPDATE, callback, userContext, timeout_ms / 1000);
|
||||
|
||||
rc = do_shadow_request(shadow, &request_params, pJsonDoc, sizeOfBuffer);
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
int IOT_Shadow_Update_Sync(void *handle, char *pJsonDoc, size_t sizeOfBuffer, uint32_t timeout_ms)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
int rc = QCLOUD_RET_SUCCESS;
|
||||
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(pJsonDoc, QCLOUD_ERR_INVAL);
|
||||
NUMBERIC_SANITY_CHECK(timeout_ms, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Shadow *shadow = (Qcloud_IoT_Shadow *)handle;
|
||||
|
||||
if (IOT_MQTT_IsConnected(shadow->mqtt) == false) {
|
||||
Log_e("shadow is disconnected");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
|
||||
}
|
||||
|
||||
RequestAck ack_update = ACK_NONE;
|
||||
rc = IOT_Shadow_Update(handle, pJsonDoc, sizeOfBuffer, _update_ack_cb, &ack_update, timeout_ms);
|
||||
if (rc != QCLOUD_RET_SUCCESS)
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
|
||||
while (ACK_NONE == ack_update) {
|
||||
IOT_Shadow_Yield(handle, 200);
|
||||
}
|
||||
|
||||
if (ACK_ACCEPTED == ack_update) {
|
||||
rc = QCLOUD_RET_SUCCESS;
|
||||
} else if (ACK_TIMEOUT == ack_update) {
|
||||
rc = QCLOUD_ERR_SHADOW_UPDATE_TIMEOUT;
|
||||
} else if (ACK_REJECTED == ack_update) {
|
||||
rc = QCLOUD_ERR_SHADOW_UPDATE_REJECTED;
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
int IOT_Shadow_Get(void *handle, OnRequestCallback callback, void *userContext, uint32_t timeout_ms)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
int rc;
|
||||
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(callback, QCLOUD_ERR_INVAL);
|
||||
NUMBERIC_SANITY_CHECK(timeout_ms, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Shadow *shadow = (Qcloud_IoT_Shadow *)handle;
|
||||
|
||||
if (IOT_MQTT_IsConnected(shadow->mqtt) == false) {
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
|
||||
}
|
||||
|
||||
// subscribe topic $shadow/operation/result if not subscribed yet
|
||||
if (shadow->inner_data.sync_status < 0) {
|
||||
subscribe_operation_result_to_cloud(shadow);
|
||||
}
|
||||
|
||||
char getRequestJsonDoc[MAX_SIZE_OF_JSON_WITH_CLIENT_TOKEN];
|
||||
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)shadow->mqtt;
|
||||
build_empty_json(&(shadow->inner_data.token_num), getRequestJsonDoc, mqtt_client->device_info.product_id);
|
||||
Log_d("GET Request Document: %s", getRequestJsonDoc);
|
||||
|
||||
RequestParams request_params = DEFAULT_REQUEST_PARAMS;
|
||||
_init_request_params(&request_params, GET, callback, userContext, timeout_ms / 1000);
|
||||
|
||||
rc = do_shadow_request(shadow, &request_params, getRequestJsonDoc, MAX_SIZE_OF_JSON_WITH_CLIENT_TOKEN);
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
int IOT_Shadow_Get_Sync(void *handle, uint32_t timeout_ms)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
int rc = QCLOUD_RET_SUCCESS;
|
||||
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
NUMBERIC_SANITY_CHECK(timeout_ms, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Shadow *shadow = (Qcloud_IoT_Shadow *)handle;
|
||||
|
||||
if (IOT_MQTT_IsConnected(shadow->mqtt) == false) {
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
|
||||
}
|
||||
|
||||
RequestAck ack_update = ACK_NONE;
|
||||
rc = IOT_Shadow_Get(handle, _update_ack_cb, &ack_update, timeout_ms);
|
||||
if (rc != QCLOUD_RET_SUCCESS)
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
|
||||
while (ACK_NONE == ack_update) {
|
||||
IOT_Shadow_Yield(handle, 200);
|
||||
}
|
||||
|
||||
if (ACK_ACCEPTED == ack_update) {
|
||||
rc = QCLOUD_RET_SUCCESS;
|
||||
} else if (ACK_TIMEOUT == ack_update) {
|
||||
rc = QCLOUD_ERR_SHADOW_GET_TIMEOUT;
|
||||
} else if (ACK_REJECTED == ack_update) {
|
||||
rc = QCLOUD_ERR_SHADOW_GET_REJECTED;
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Init a shadow JSON string, add the initial field of "{\"state\":{"
|
||||
*
|
||||
* @param jsonBuffer JSON string buffer
|
||||
* @param sizeOfBuffer buffer size
|
||||
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
|
||||
*/
|
||||
static int IOT_Shadow_JSON_Init(Qcloud_IoT_Shadow *pShadow, char *jsonBuffer, size_t sizeOfBuffer, bool overwrite)
|
||||
{
|
||||
if (jsonBuffer == NULL) {
|
||||
return QCLOUD_ERR_INVAL;
|
||||
}
|
||||
|
||||
int32_t rc_of_snprintf = 0;
|
||||
if (overwrite) {
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer, sizeOfBuffer, "{\"overwriteUpdate\":true, \"state\":{");
|
||||
} else {
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer, sizeOfBuffer, "{\"state\":{");
|
||||
}
|
||||
|
||||
return _check_snprintf_return(rc_of_snprintf, sizeOfBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finish a shadow JSON string, append the tail fields of clientToken and version
|
||||
*
|
||||
* @param jsonBuffer JSON string buffer
|
||||
* @param sizeOfBuffer buffer size
|
||||
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
|
||||
*/
|
||||
static int IOT_Shadow_JSON_Finalize(Qcloud_IoT_Shadow *pShadow, char *jsonBuffer, size_t sizeOfBuffer)
|
||||
{
|
||||
int rc;
|
||||
size_t remain_size = 0;
|
||||
int32_t rc_of_snprintf = 0;
|
||||
|
||||
if (jsonBuffer == NULL) {
|
||||
return QCLOUD_ERR_INVAL;
|
||||
}
|
||||
|
||||
if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer) - 1, remain_size, "}, \"%s\":\"", CLIENT_TOKEN_FIELD);
|
||||
rc = _check_snprintf_return(rc_of_snprintf, remain_size);
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pShadow->mqtt;
|
||||
rc_of_snprintf = generate_client_token(jsonBuffer + strlen(jsonBuffer), remain_size,
|
||||
&(pShadow->inner_data.token_num), mqtt_client->device_info.product_id);
|
||||
rc = _check_snprintf_return(rc_of_snprintf, remain_size);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "\"}");
|
||||
rc = _check_snprintf_return(rc_of_snprintf, remain_size);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int IOT_Shadow_JSON_ConstructReport(void *handle, char *jsonBuffer, size_t sizeOfBuffer, uint8_t count, ...)
|
||||
{
|
||||
Qcloud_IoT_Shadow *pshadow = (Qcloud_IoT_Shadow *)handle;
|
||||
POINTER_SANITY_CHECK(pshadow, QCLOUD_ERR_INVAL);
|
||||
|
||||
int rc = IOT_Shadow_JSON_Init(pshadow, jsonBuffer, sizeOfBuffer, false);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("shadow json init failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
size_t remain_size = 0;
|
||||
int32_t rc_of_snprintf = 0;
|
||||
int8_t i;
|
||||
|
||||
if (jsonBuffer == NULL) {
|
||||
return QCLOUD_ERR_INVAL;
|
||||
}
|
||||
|
||||
if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "\"reported\":{");
|
||||
rc = _check_snprintf_return(rc_of_snprintf, remain_size);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
va_list pArgs;
|
||||
va_start(pArgs, count);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
DeviceProperty *pJsonNode;
|
||||
pJsonNode = va_arg(pArgs, DeviceProperty *);
|
||||
if (pJsonNode != NULL && pJsonNode->key != NULL) {
|
||||
rc = put_json_node(jsonBuffer, remain_size, pJsonNode->key, pJsonNode->data, pJsonNode->type);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
va_end(pArgs);
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
va_end(pArgs);
|
||||
return QCLOUD_ERR_INVAL;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(pArgs);
|
||||
if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL;
|
||||
}
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer) - 1, remain_size, "},");
|
||||
rc = _check_snprintf_return(rc_of_snprintf, remain_size);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("shadow json add report failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = IOT_Shadow_JSON_Finalize(pshadow, jsonBuffer, sizeOfBuffer);
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("shadow json finalize failed: %d", rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int IOT_Shadow_JSON_ConstructReportArray(void *handle, char *jsonBuffer, size_t sizeOfBuffer, uint8_t count,
|
||||
DeviceProperty *pDeviceProperties[])
|
||||
{
|
||||
Qcloud_IoT_Shadow *pshadow = (Qcloud_IoT_Shadow *)handle;
|
||||
POINTER_SANITY_CHECK(pshadow, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(pDeviceProperties, QCLOUD_ERR_INVAL);
|
||||
|
||||
int rc = IOT_Shadow_JSON_Init(pshadow, jsonBuffer, sizeOfBuffer, false);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("shadow json init failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
size_t remain_size = 0;
|
||||
int32_t rc_of_snprintf = 0;
|
||||
int8_t i;
|
||||
|
||||
if (jsonBuffer == NULL) {
|
||||
return QCLOUD_ERR_INVAL;
|
||||
}
|
||||
|
||||
if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "\"reported\":{");
|
||||
rc = _check_snprintf_return(rc_of_snprintf, remain_size);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
DeviceProperty *pJsonNode = pDeviceProperties[i];
|
||||
if (pJsonNode != NULL && pJsonNode->key != NULL) {
|
||||
rc = put_json_node(jsonBuffer, remain_size, pJsonNode->key, pJsonNode->data, pJsonNode->type);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
return QCLOUD_ERR_INVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL;
|
||||
}
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer) - 1, remain_size, "},");
|
||||
rc = _check_snprintf_return(rc_of_snprintf, remain_size);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("shadow json add report failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = IOT_Shadow_JSON_Finalize(pshadow, jsonBuffer, sizeOfBuffer);
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("shadow json finalize failed: %d", rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int IOT_Shadow_JSON_Construct_OverwriteReport(void *handle, char *jsonBuffer, size_t sizeOfBuffer, uint8_t count, ...)
|
||||
{
|
||||
Qcloud_IoT_Shadow *pshadow = (Qcloud_IoT_Shadow *)handle;
|
||||
POINTER_SANITY_CHECK(pshadow, QCLOUD_ERR_INVAL);
|
||||
|
||||
int rc = IOT_Shadow_JSON_Init(pshadow, jsonBuffer, sizeOfBuffer, true);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("shadow json init failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
size_t remain_size = 0;
|
||||
int32_t rc_of_snprintf = 0;
|
||||
int8_t i;
|
||||
|
||||
if (jsonBuffer == NULL) {
|
||||
return QCLOUD_ERR_INVAL;
|
||||
}
|
||||
|
||||
if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "\"reported\":{");
|
||||
rc = _check_snprintf_return(rc_of_snprintf, remain_size);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
va_list pArgs;
|
||||
va_start(pArgs, count);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
DeviceProperty *pJsonNode;
|
||||
pJsonNode = va_arg(pArgs, DeviceProperty *);
|
||||
if (pJsonNode != NULL && pJsonNode->key != NULL) {
|
||||
rc = put_json_node(jsonBuffer, remain_size, pJsonNode->key, pJsonNode->data, pJsonNode->type);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
va_end(pArgs);
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
va_end(pArgs);
|
||||
return QCLOUD_ERR_INVAL;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(pArgs);
|
||||
if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL;
|
||||
}
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer) - 1, remain_size, "},");
|
||||
rc = _check_snprintf_return(rc_of_snprintf, remain_size);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("shadow json add report failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = IOT_Shadow_JSON_Finalize(pshadow, jsonBuffer, sizeOfBuffer);
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("shadow json finalize failed: %d", rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int IOT_Shadow_JSON_ConstructReportAndDesireAllNull(void *handle, char *jsonBuffer, size_t sizeOfBuffer, uint8_t count,
|
||||
...)
|
||||
{
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
Qcloud_IoT_Shadow *pshadow = (Qcloud_IoT_Shadow *)handle;
|
||||
|
||||
int rc = IOT_Shadow_JSON_Init(pshadow, jsonBuffer, sizeOfBuffer, false);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("shadow json init failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
size_t remain_size = 0;
|
||||
int32_t rc_of_snprintf = 0;
|
||||
int8_t i;
|
||||
|
||||
if (jsonBuffer == NULL) {
|
||||
return QCLOUD_ERR_INVAL;
|
||||
}
|
||||
|
||||
if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "\"reported\":{");
|
||||
rc = _check_snprintf_return(rc_of_snprintf, remain_size);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
va_list pArgs;
|
||||
va_start(pArgs, count);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
DeviceProperty *pJsonNode;
|
||||
pJsonNode = va_arg(pArgs, DeviceProperty *);
|
||||
if (pJsonNode != NULL && pJsonNode->key != NULL) {
|
||||
rc = put_json_node(jsonBuffer, remain_size, pJsonNode->key, pJsonNode->data, pJsonNode->type);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
va_end(pArgs);
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
va_end(pArgs);
|
||||
return QCLOUD_ERR_INVAL;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(pArgs);
|
||||
if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL;
|
||||
}
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer) - 1, remain_size, "},");
|
||||
rc = _check_snprintf_return(rc_of_snprintf, remain_size);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("shadow json add report failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "\"desired\": null ");
|
||||
rc = _check_snprintf_return(rc_of_snprintf, remain_size);
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = IOT_Shadow_JSON_Finalize(pshadow, jsonBuffer, sizeOfBuffer);
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("shadow json finalize failed: %d", rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int IOT_Shadow_JSON_ConstructDesireAllNull(void *handle, char *jsonBuffer, size_t sizeOfBuffer)
|
||||
{
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
Qcloud_IoT_Shadow *shadow = (Qcloud_IoT_Shadow *)handle;
|
||||
|
||||
int rc = IOT_Shadow_JSON_Init(shadow, jsonBuffer, sizeOfBuffer, false);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("shadow json init failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
size_t remain_size = 0;
|
||||
int32_t rc_of_snprintf = 0;
|
||||
|
||||
if (jsonBuffer == NULL) {
|
||||
return QCLOUD_ERR_INVAL;
|
||||
}
|
||||
|
||||
if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "\"desired\": null ");
|
||||
rc = _check_snprintf_return(rc_of_snprintf, remain_size);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = IOT_Shadow_JSON_Finalize(shadow, jsonBuffer, sizeOfBuffer);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int IOT_Shadow_JSON_ConstructDesirePropNull(void *handle, char *jsonBuffer, size_t sizeOfBuffer, uint8_t count, ...)
|
||||
{
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
Qcloud_IoT_Shadow *shadow = (Qcloud_IoT_Shadow *)handle;
|
||||
|
||||
int rc = IOT_Shadow_JSON_Init(shadow, jsonBuffer, sizeOfBuffer, false);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("shadow json init failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
size_t remain_size = 0;
|
||||
int32_t rc_of_snprintf = 0;
|
||||
int8_t i;
|
||||
|
||||
if (jsonBuffer == NULL) {
|
||||
return QCLOUD_ERR_INVAL;
|
||||
}
|
||||
|
||||
if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "\"desired\":{");
|
||||
rc = _check_snprintf_return(rc_of_snprintf, remain_size);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
va_list pArgs;
|
||||
va_start(pArgs, count);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
DeviceProperty *pJsonNode;
|
||||
pJsonNode = va_arg(pArgs, DeviceProperty *);
|
||||
if (pJsonNode != NULL && pJsonNode->key != NULL) {
|
||||
rc = put_json_node(jsonBuffer, remain_size, pJsonNode->key, pJsonNode->data, pJsonNode->type);
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
va_end(pArgs);
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
va_end(pArgs);
|
||||
return QCLOUD_ERR_INVAL;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(pArgs);
|
||||
if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL;
|
||||
}
|
||||
// strlen(jsonBuffer) - 1 to remove last comma
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer) - 1, remain_size, "},");
|
||||
rc = _check_snprintf_return(rc_of_snprintf, remain_size);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("shadow json add desired failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = IOT_Shadow_JSON_Finalize(shadow, jsonBuffer, sizeOfBuffer);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
100
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/shadow/shadow_client_common.c
vendored
Normal file
100
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/shadow/shadow_client_common.c
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "shadow_client_common.h"
|
||||
|
||||
#include "qcloud_iot_import.h"
|
||||
|
||||
static int _add_property_handle_to_list(Qcloud_IoT_Shadow *pShadow, DeviceProperty *pProperty,
|
||||
OnPropRegCallback callback)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
PropertyHandler *property_handle = (PropertyHandler *)HAL_Malloc(sizeof(PropertyHandler));
|
||||
if (NULL == property_handle) {
|
||||
Log_e("run memory malloc is error!");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
|
||||
property_handle->callback = callback;
|
||||
property_handle->property = pProperty;
|
||||
|
||||
ListNode *node = list_node_new(property_handle);
|
||||
if (NULL == node) {
|
||||
Log_e("run list_node_new is error!");
|
||||
HAL_Free(property_handle);
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
list_rpush(pShadow->inner_data.property_handle_list, node);
|
||||
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
|
||||
}
|
||||
|
||||
int shadow_common_check_property_existence(Qcloud_IoT_Shadow *pshadow, DeviceProperty *pProperty)
|
||||
{
|
||||
ListNode *node;
|
||||
|
||||
HAL_MutexLock(pshadow->mutex);
|
||||
node = list_find(pshadow->inner_data.property_handle_list, pProperty);
|
||||
HAL_MutexUnlock(pshadow->mutex);
|
||||
|
||||
return (NULL != node);
|
||||
}
|
||||
|
||||
int shadow_common_remove_property(Qcloud_IoT_Shadow *pshadow, DeviceProperty *pProperty)
|
||||
{
|
||||
int rc = QCLOUD_RET_SUCCESS;
|
||||
|
||||
ListNode *node;
|
||||
HAL_MutexLock(pshadow->mutex);
|
||||
node = list_find(pshadow->inner_data.property_handle_list, pProperty);
|
||||
if (NULL == node) {
|
||||
rc = QCLOUD_ERR_SHADOW_NOT_PROPERTY_EXIST;
|
||||
Log_e("Try to remove a non-existent property.");
|
||||
} else {
|
||||
list_remove(pshadow->inner_data.property_handle_list, node);
|
||||
}
|
||||
HAL_MutexUnlock(pshadow->mutex);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int shadow_common_register_property_on_delta(Qcloud_IoT_Shadow *pShadow, DeviceProperty *pProperty,
|
||||
OnPropRegCallback callback)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
POINTER_SANITY_CHECK(pShadow, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(callback, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(pProperty, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(pProperty->key, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(pProperty->data, QCLOUD_ERR_INVAL);
|
||||
|
||||
int rc;
|
||||
|
||||
HAL_MutexLock(pShadow->mutex);
|
||||
rc = _add_property_handle_to_list(pShadow, pProperty, callback);
|
||||
HAL_MutexUnlock(pShadow->mutex);
|
||||
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
324
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/shadow/shadow_client_json.c
vendored
Normal file
324
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/shadow/shadow_client_json.c
vendored
Normal file
@@ -0,0 +1,324 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "shadow_client_json.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lite-utils.h"
|
||||
#include "qcloud_iot_device.h"
|
||||
#include "shadow_client.h"
|
||||
|
||||
static int _direct_update_value(char *value, DeviceProperty *pProperty)
|
||||
{
|
||||
int rc = QCLOUD_RET_SUCCESS;
|
||||
|
||||
if (pProperty->type == JBOOL) {
|
||||
rc = LITE_get_boolean(pProperty->data, value);
|
||||
} else if (pProperty->type == JINT32) {
|
||||
rc = LITE_get_int32(pProperty->data, value);
|
||||
} else if (pProperty->type == JINT16) {
|
||||
rc = LITE_get_int16(pProperty->data, value);
|
||||
} else if (pProperty->type == JINT8) {
|
||||
rc = LITE_get_int8(pProperty->data, value);
|
||||
} else if (pProperty->type == JUINT32) {
|
||||
rc = LITE_get_uint32(pProperty->data, value);
|
||||
} else if (pProperty->type == JUINT16) {
|
||||
rc = LITE_get_uint16(pProperty->data, value);
|
||||
} else if (pProperty->type == JUINT8) {
|
||||
rc = LITE_get_uint8(pProperty->data, value);
|
||||
} else if (pProperty->type == JFLOAT) {
|
||||
rc = LITE_get_float(pProperty->data, value);
|
||||
} else if (pProperty->type == JDOUBLE) {
|
||||
rc = LITE_get_double(pProperty->data, value);
|
||||
} else if (pProperty->type == JSTRING) {
|
||||
// Log_d("string type wait to be deal,%s",value);
|
||||
} else if (pProperty->type == JOBJECT) {
|
||||
// Log_d("Json type wait to be deal,%s",value);
|
||||
} else {
|
||||
Log_e("pProperty type unknow,%d", pProperty->type);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief check return value of snprintf
|
||||
*
|
||||
* @param returnCode return value of snprintf
|
||||
* @param maxSizeOfWrite max size of write buffer
|
||||
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
|
||||
*/
|
||||
static inline int _check_snprintf_return(int32_t returnCode, size_t maxSizeOfWrite)
|
||||
{
|
||||
if (returnCode >= maxSizeOfWrite) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TRUNCATED;
|
||||
} else if (returnCode < 0) {
|
||||
return QCLOUD_ERR_JSON;
|
||||
}
|
||||
|
||||
return QCLOUD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
int put_json_node(char *jsonBuffer, size_t sizeOfBuffer, const char *pKey, void *pData, JsonDataType type)
|
||||
{
|
||||
int rc;
|
||||
int32_t rc_of_snprintf = 0;
|
||||
size_t remain_size = 0;
|
||||
|
||||
if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "\"%s\":", pKey);
|
||||
rc = _check_snprintf_return(rc_of_snprintf, remain_size);
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
if (pData == NULL) {
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "null,");
|
||||
} else {
|
||||
if (type == JINT32) {
|
||||
rc_of_snprintf =
|
||||
HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%" PRIi32 ",", *(int32_t *)(pData));
|
||||
} else if (type == JINT16) {
|
||||
rc_of_snprintf =
|
||||
HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%" PRIi16 ",", *(int16_t *)(pData));
|
||||
} else if (type == JINT8) {
|
||||
rc_of_snprintf =
|
||||
HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%" PRIi8 ",", *(int8_t *)(pData));
|
||||
} else if (type == JUINT32) {
|
||||
rc_of_snprintf =
|
||||
HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%" PRIu32 ",", *(uint32_t *)(pData));
|
||||
} else if (type == JUINT16) {
|
||||
rc_of_snprintf =
|
||||
HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%" PRIu16 ",", *(uint16_t *)(pData));
|
||||
} else if (type == JUINT8) {
|
||||
rc_of_snprintf =
|
||||
HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%" PRIu8 ",", *(uint8_t *)(pData));
|
||||
} else if (type == JDOUBLE) {
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%f,", *(double *)(pData));
|
||||
} else if (type == JFLOAT) {
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%f,", *(float *)(pData));
|
||||
} else if (type == JBOOL) {
|
||||
rc_of_snprintf =
|
||||
HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%s,", *(bool *)(pData) ? "true" : "false");
|
||||
} else if (type == JSTRING) {
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "\"%s\",", (char *)(pData));
|
||||
} else if (type == JOBJECT) {
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%s,", (char *)(pData));
|
||||
}
|
||||
}
|
||||
|
||||
rc = _check_snprintf_return(rc_of_snprintf, remain_size);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int event_put_json_node(char *jsonBuffer, size_t sizeOfBuffer, const char *pKey, void *pData, JsonDataType type)
|
||||
{
|
||||
int rc;
|
||||
int32_t rc_of_snprintf = 0;
|
||||
size_t remain_size = 0;
|
||||
|
||||
if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "\"%s\":", pKey);
|
||||
rc = _check_snprintf_return(rc_of_snprintf, remain_size);
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
if (pData == NULL) {
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "null,");
|
||||
} else {
|
||||
if (type == JINT32) {
|
||||
rc_of_snprintf =
|
||||
HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%" PRIi32 ",", *(int32_t *)(pData));
|
||||
} else if (type == JINT16) {
|
||||
rc_of_snprintf =
|
||||
HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%" PRIi16 ",", *(int16_t *)(pData));
|
||||
} else if (type == JINT8) {
|
||||
rc_of_snprintf =
|
||||
HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%" PRIi8 ",", *(int8_t *)(pData));
|
||||
} else if (type == JUINT32) {
|
||||
rc_of_snprintf =
|
||||
HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%" PRIu32 ",", *(uint32_t *)(pData));
|
||||
} else if (type == JUINT16) {
|
||||
rc_of_snprintf =
|
||||
HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%" PRIu16 ",", *(uint16_t *)(pData));
|
||||
} else if (type == JUINT8) {
|
||||
rc_of_snprintf =
|
||||
HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%" PRIu8 ",", *(uint8_t *)(pData));
|
||||
} else if (type == JDOUBLE) {
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%f,", *(double *)(pData));
|
||||
} else if (type == JFLOAT) {
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%f,", *(float *)(pData));
|
||||
} else if (type == JBOOL) {
|
||||
rc_of_snprintf =
|
||||
HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%u,", *(bool *)(pData) ? 1 : 0);
|
||||
} else if (type == JSTRING) {
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "\"%s\",", (char *)(pData));
|
||||
} else if (type == JOBJECT) {
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%s,", (char *)(pData));
|
||||
}
|
||||
}
|
||||
|
||||
rc = _check_snprintf_return(rc_of_snprintf, remain_size);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int generate_client_token(char *pStrBuffer, size_t sizeOfBuffer, uint32_t *tokenNumber, char *product_id)
|
||||
{
|
||||
return HAL_Snprintf(pStrBuffer, sizeOfBuffer, "%s-%u", product_id, (*tokenNumber)++);
|
||||
}
|
||||
|
||||
void build_empty_json(uint32_t *tokenNumber, char *pJsonBuffer, char *product_id)
|
||||
{
|
||||
HAL_Snprintf(pJsonBuffer, MAX_SIZE_OF_JSON_WITH_CLIENT_TOKEN, "{\"clientToken\":\"%s-%u\"}", product_id,
|
||||
(*tokenNumber)++);
|
||||
}
|
||||
|
||||
bool parse_client_token(char *pJsonDoc, char **pClientToken)
|
||||
{
|
||||
*pClientToken = LITE_json_value_of(CLIENT_TOKEN_FIELD, pJsonDoc);
|
||||
return *pClientToken == NULL ? false : true;
|
||||
}
|
||||
|
||||
bool parse_version_num(char *pJsonDoc, uint32_t *pVersionNumber)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
char *version_num = LITE_json_value_of(PAYLOAD_VERSION, pJsonDoc);
|
||||
if (version_num == NULL)
|
||||
return false;
|
||||
|
||||
if (sscanf(version_num, "%" SCNu32, pVersionNumber) != 1) {
|
||||
Log_e("parse shadow version failed, errCode: %d", QCLOUD_ERR_JSON_PARSE);
|
||||
} else {
|
||||
ret = true;
|
||||
}
|
||||
|
||||
HAL_Free(version_num);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool parse_shadow_state(char *pJsonDoc, char **pState)
|
||||
{
|
||||
*pState = LITE_json_value_of(PAYLOAD_VERSION, pJsonDoc);
|
||||
return *pState == NULL ? false : true;
|
||||
}
|
||||
|
||||
bool parse_code_return(char *pJsonDoc, int32_t *pCode)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
char *code = LITE_json_value_of(REPLY_CODE, pJsonDoc);
|
||||
if (code == NULL)
|
||||
return false;
|
||||
|
||||
if (sscanf(code, "%" SCNi32, pCode) != 1) {
|
||||
Log_e("parse code failed, errCode: %d", QCLOUD_ERR_JSON_PARSE);
|
||||
} else {
|
||||
ret = true;
|
||||
}
|
||||
|
||||
HAL_Free(code);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool parse_status_return(char *pJsonDoc, char **pStatus)
|
||||
{
|
||||
*pStatus = LITE_json_value_of(REPLY_STATUS, pJsonDoc);
|
||||
return *pStatus == NULL ? false : true;
|
||||
}
|
||||
|
||||
bool parse_shadow_operation_type(char *pJsonDoc, char **pType)
|
||||
{
|
||||
*pType = LITE_json_value_of(TYPE_FIELD, pJsonDoc);
|
||||
return *pType == NULL ? false : true;
|
||||
}
|
||||
|
||||
bool parse_shadow_operation_result_code(char *pJsonDoc, int16_t *pResultCode)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
char *result_code = LITE_json_value_of(RESULT_FIELD, pJsonDoc);
|
||||
if (result_code == NULL)
|
||||
return false;
|
||||
|
||||
if (sscanf(result_code, "%" SCNi16, pResultCode) != 1) {
|
||||
Log_e("parse shadow result_code failed, errCode: %d", QCLOUD_ERR_JSON_PARSE);
|
||||
} else {
|
||||
ret = true;
|
||||
}
|
||||
|
||||
HAL_Free(result_code);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool parse_shadow_operation_delta(char *pJsonDoc, char **pDelta)
|
||||
{
|
||||
*pDelta = LITE_json_value_of(PAYLOAD_STATE, pJsonDoc);
|
||||
return *pDelta == NULL ? false : true;
|
||||
}
|
||||
|
||||
bool parse_shadow_operation_get(char *pJsonDoc, char **pDelta)
|
||||
{
|
||||
*pDelta = LITE_json_value_of(PAYLOAD_STATE_DELTA, pJsonDoc);
|
||||
return *pDelta == NULL ? false : true;
|
||||
}
|
||||
|
||||
bool update_value_if_key_match(char *pJsonDoc, DeviceProperty *pProperty)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
char *property_data = LITE_json_value_of(pProperty->key, pJsonDoc);
|
||||
if ((property_data == NULL) || !(strncmp(property_data, "null", 4)) || !(strncmp(property_data, "NULL", 4))) {
|
||||
} else {
|
||||
_direct_update_value(property_data, pProperty);
|
||||
ret = true;
|
||||
HAL_Free(property_data);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
569
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/shadow/shadow_client_manager.c
vendored
Normal file
569
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/shadow/shadow_client_manager.c
vendored
Normal file
@@ -0,0 +1,569 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "qcloud_iot_import.h"
|
||||
#include "shadow_client.h"
|
||||
#include "shadow_client_json.h"
|
||||
#include "utils_list.h"
|
||||
#include "utils_param_check.h"
|
||||
|
||||
/**
|
||||
* @brief type for document request
|
||||
*/
|
||||
typedef struct {
|
||||
char client_token[MAX_SIZE_OF_CLIENT_TOKEN]; // clientToken
|
||||
Method method; // method type
|
||||
|
||||
void *user_context; // user context
|
||||
Timer timer; // timer for timeout
|
||||
|
||||
OnRequestCallback callback; // request response callback
|
||||
} Request;
|
||||
|
||||
typedef void (*TraverseHandle)(Qcloud_IoT_Shadow *pShadow, ListNode **node, List *list, const char *pClientToken,
|
||||
const char *pType);
|
||||
|
||||
static void _on_operation_result_handler(void *pClient, MQTTMessage *message, void *pUserdata);
|
||||
|
||||
static void _handle_delta(Qcloud_IoT_Shadow *pShadow, char *delta_str);
|
||||
|
||||
static int _set_shadow_json_type(char *pJsonDoc, size_t sizeOfBuffer, Method method);
|
||||
|
||||
static int _publish_operation_to_cloud(Qcloud_IoT_Shadow *pShadow, Method method, char *pJsonDoc);
|
||||
|
||||
static int _add_request_to_list(Qcloud_IoT_Shadow *pShadow, const char *pClientToken, RequestParams *pParams);
|
||||
|
||||
static int _unsubscribe_operation_result_to_cloud(Qcloud_IoT_Shadow *pShadow);
|
||||
|
||||
static void _traverse_list(Qcloud_IoT_Shadow *pShadow, List *list, const char *pClientToken, const char *pType,
|
||||
TraverseHandle traverseHandle);
|
||||
|
||||
static void _handle_request_callback(Qcloud_IoT_Shadow *pShadow, ListNode **node, List *list, const char *pClientToken,
|
||||
const char *pType);
|
||||
|
||||
static void _handle_expired_request_callback(Qcloud_IoT_Shadow *pShadow, ListNode **node, List *list,
|
||||
const char *pClientToken, const char *pType);
|
||||
|
||||
int qcloud_iot_shadow_init(Qcloud_IoT_Shadow *pShadow)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
POINTER_SANITY_CHECK(pShadow, QCLOUD_ERR_INVAL);
|
||||
|
||||
pShadow->mutex = HAL_MutexCreate();
|
||||
if (pShadow->mutex == NULL)
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
|
||||
pShadow->inner_data.property_handle_list = list_new();
|
||||
if (pShadow->inner_data.property_handle_list) {
|
||||
pShadow->inner_data.property_handle_list->free = HAL_Free;
|
||||
} else {
|
||||
Log_e("no memory to allocate property_handle_list");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
|
||||
pShadow->inner_data.request_list = list_new();
|
||||
if (pShadow->inner_data.request_list) {
|
||||
pShadow->inner_data.request_list->free = HAL_Free;
|
||||
} else {
|
||||
Log_e("no memory to allocate request_list");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
|
||||
}
|
||||
|
||||
void qcloud_iot_shadow_reset(void *pClient)
|
||||
{
|
||||
POINTER_SANITY_CHECK_RTN(pClient);
|
||||
|
||||
Qcloud_IoT_Shadow *shadow_client = (Qcloud_IoT_Shadow *)pClient;
|
||||
if (shadow_client->inner_data.property_handle_list) {
|
||||
list_destroy(shadow_client->inner_data.property_handle_list);
|
||||
}
|
||||
|
||||
_unsubscribe_operation_result_to_cloud(shadow_client);
|
||||
|
||||
if (shadow_client->inner_data.request_list) {
|
||||
list_destroy(shadow_client->inner_data.request_list);
|
||||
}
|
||||
}
|
||||
|
||||
void handle_expired_request(Qcloud_IoT_Shadow *pShadow)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
_traverse_list(pShadow, pShadow->inner_data.request_list, NULL, NULL, _handle_expired_request_callback);
|
||||
|
||||
IOT_FUNC_EXIT;
|
||||
}
|
||||
|
||||
int do_shadow_request(Qcloud_IoT_Shadow *pShadow, RequestParams *pParams, char *pJsonDoc, size_t sizeOfBuffer)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
int rc = QCLOUD_RET_SUCCESS;
|
||||
|
||||
POINTER_SANITY_CHECK(pShadow, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(pJsonDoc, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(pParams, QCLOUD_ERR_INVAL);
|
||||
|
||||
char *client_token = NULL;
|
||||
|
||||
if (!parse_client_token(pJsonDoc, &client_token)) {
|
||||
Log_e("fail to parse client token!");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
|
||||
}
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS)
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
|
||||
rc = _set_shadow_json_type(pJsonDoc, sizeOfBuffer, pParams->method);
|
||||
if (rc != QCLOUD_RET_SUCCESS)
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
|
||||
if (rc == QCLOUD_RET_SUCCESS) {
|
||||
rc = _publish_operation_to_cloud(pShadow, pParams->method, pJsonDoc);
|
||||
}
|
||||
|
||||
if (rc >= 0) {
|
||||
rc = _add_request_to_list(pShadow, client_token, pParams);
|
||||
}
|
||||
|
||||
HAL_Free(client_token);
|
||||
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
int subscribe_operation_result_to_cloud(Qcloud_IoT_Shadow *pShadow)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
int rc;
|
||||
int size;
|
||||
|
||||
if (pShadow->inner_data.result_topic == NULL) {
|
||||
char *operation_result_topic = (char *)HAL_Malloc(MAX_SIZE_OF_CLOUD_TOPIC * sizeof(char));
|
||||
if (operation_result_topic == NULL)
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
|
||||
memset(operation_result_topic, 0x0, MAX_SIZE_OF_CLOUD_TOPIC);
|
||||
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pShadow->mqtt;
|
||||
if (eTEMPLATE == pShadow->shadow_type) {
|
||||
size = HAL_Snprintf(operation_result_topic, MAX_SIZE_OF_CLOUD_TOPIC, "$template/operation/result/%s/%s",
|
||||
mqtt_client->device_info.product_id, mqtt_client->device_info.device_name);
|
||||
} else {
|
||||
size = HAL_Snprintf(operation_result_topic, MAX_SIZE_OF_CLOUD_TOPIC, "$shadow/operation/result/%s/%s",
|
||||
mqtt_client->device_info.product_id, mqtt_client->device_info.device_name);
|
||||
}
|
||||
if (size < 0 || size > MAX_SIZE_OF_CLOUD_TOPIC - 1) {
|
||||
Log_e("buf size < topic length!");
|
||||
HAL_Free(operation_result_topic);
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
pShadow->inner_data.result_topic = operation_result_topic;
|
||||
}
|
||||
|
||||
SubscribeParams subscribe_params = DEFAULT_SUB_PARAMS;
|
||||
subscribe_params.on_message_handler = _on_operation_result_handler;
|
||||
subscribe_params.qos = QOS0;
|
||||
|
||||
rc = IOT_MQTT_Subscribe(pShadow->mqtt, pShadow->inner_data.result_topic, &subscribe_params);
|
||||
if (rc < 0) {
|
||||
Log_e("subscribe topic: %s failed: %d.", pShadow->inner_data.result_topic, rc);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief publish operation to server
|
||||
*
|
||||
* @param pClient Qcloud_IoT_Client
|
||||
* @param method method type
|
||||
* @param pJsonDoc JSON to publish
|
||||
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
|
||||
*/
|
||||
static int _publish_operation_to_cloud(Qcloud_IoT_Shadow *pShadow, Method method, char *pJsonDoc)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
int rc = QCLOUD_RET_SUCCESS;
|
||||
|
||||
char topic[MAX_SIZE_OF_CLOUD_TOPIC] = {0};
|
||||
int size;
|
||||
|
||||
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pShadow->mqtt;
|
||||
if (eTEMPLATE == pShadow->shadow_type) {
|
||||
size = HAL_Snprintf(topic, MAX_SIZE_OF_CLOUD_TOPIC, "$template/operation/%s/%s",
|
||||
mqtt_client->device_info.product_id, mqtt_client->device_info.device_name);
|
||||
} else {
|
||||
size = HAL_Snprintf(topic, MAX_SIZE_OF_CLOUD_TOPIC, "$shadow/operation/%s/%s",
|
||||
mqtt_client->device_info.product_id, mqtt_client->device_info.device_name);
|
||||
}
|
||||
|
||||
if (size < 0 || size > MAX_SIZE_OF_CLOUD_TOPIC - 1) {
|
||||
Log_e("buf size < topic length!");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
|
||||
PublishParams pubParams = DEFAULT_PUB_PARAMS;
|
||||
pubParams.qos = QOS0;
|
||||
pubParams.payload_len = strlen(pJsonDoc);
|
||||
pubParams.payload = (char *)pJsonDoc;
|
||||
|
||||
rc = IOT_MQTT_Publish(pShadow->mqtt, topic, &pubParams);
|
||||
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief callback when msg of operation result arrives
|
||||
*/
|
||||
static void _on_operation_result_handler(void *pClient, MQTTMessage *message, void *pUserdata)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
POINTER_SANITY_CHECK_RTN(pClient);
|
||||
POINTER_SANITY_CHECK_RTN(message);
|
||||
|
||||
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
|
||||
Qcloud_IoT_Shadow *shadow_client = (Qcloud_IoT_Shadow *)mqtt_client->event_handle.context;
|
||||
|
||||
const char *topic = message->ptopic;
|
||||
size_t topic_len = message->topic_len;
|
||||
if (NULL == topic || topic_len <= 0) {
|
||||
IOT_FUNC_EXIT;
|
||||
}
|
||||
|
||||
char *client_token = NULL;
|
||||
char *type_str = NULL;
|
||||
|
||||
if (message->payload_len > CLOUD_IOT_JSON_RX_BUF_LEN) {
|
||||
Log_e("The length of the received message exceeds the specified length!");
|
||||
goto End;
|
||||
}
|
||||
|
||||
int cloud_rcv_len = Min(CLOUD_IOT_JSON_RX_BUF_LEN - 1, message->payload_len);
|
||||
memcpy(shadow_client->shadow_recv_buf, message->payload, cloud_rcv_len + 1);
|
||||
shadow_client->shadow_recv_buf[cloud_rcv_len] = '\0'; // jsmn_parse relies on a string
|
||||
if (!parse_shadow_operation_type(shadow_client->shadow_recv_buf, &type_str)) {
|
||||
Log_e("Fail to parse type!");
|
||||
goto End;
|
||||
}
|
||||
Log_d("type: %s", type_str);
|
||||
|
||||
// non-delta msg push is triggered by device side, parse client token first
|
||||
if (strcmp(type_str, OPERATION_DELTA) && !parse_client_token(shadow_client->shadow_recv_buf, &client_token)) {
|
||||
Log_e("Fail to parse client token! Json=%s", shadow_client->shadow_recv_buf);
|
||||
goto End;
|
||||
}
|
||||
|
||||
if (!strcmp(type_str, OPERATION_DELTA)) {
|
||||
HAL_MutexLock(shadow_client->mutex);
|
||||
char *delta_str = NULL;
|
||||
if (parse_shadow_operation_delta(shadow_client->shadow_recv_buf, &delta_str)) {
|
||||
Log_d("delta string: %s", delta_str);
|
||||
_handle_delta(shadow_client, delta_str);
|
||||
HAL_Free(delta_str);
|
||||
}
|
||||
|
||||
HAL_MutexUnlock(shadow_client->mutex);
|
||||
goto End;
|
||||
}
|
||||
|
||||
if (shadow_client != NULL)
|
||||
_traverse_list(shadow_client, shadow_client->inner_data.request_list, client_token, type_str,
|
||||
_handle_request_callback);
|
||||
|
||||
End:
|
||||
HAL_Free(type_str);
|
||||
HAL_Free(client_token);
|
||||
|
||||
IOT_FUNC_EXIT;
|
||||
}
|
||||
|
||||
static void _handle_delta(Qcloud_IoT_Shadow *pShadow, char *delta_str)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
if (pShadow->inner_data.property_handle_list->len) {
|
||||
ListIterator * iter;
|
||||
ListNode * node = NULL;
|
||||
PropertyHandler *property_handle = NULL;
|
||||
|
||||
if (NULL == (iter = list_iterator_new(pShadow->inner_data.property_handle_list, LIST_TAIL))) {
|
||||
HAL_MutexUnlock(pShadow->mutex);
|
||||
IOT_FUNC_EXIT;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
node = list_iterator_next(iter);
|
||||
if (NULL == node) {
|
||||
break;
|
||||
}
|
||||
|
||||
property_handle = (PropertyHandler *)(node->val);
|
||||
if (NULL == property_handle) {
|
||||
Log_e("node's value is invalid!");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (property_handle->property != NULL) {
|
||||
if (update_value_if_key_match(delta_str, property_handle->property)) {
|
||||
if (property_handle->callback != NULL) {
|
||||
property_handle->callback(pShadow, delta_str, strlen(delta_str), property_handle->property);
|
||||
}
|
||||
node = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list_iterator_destroy(iter);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT;
|
||||
}
|
||||
|
||||
static void _insert(char *str, char *pch, int pos)
|
||||
{
|
||||
int len = strlen(str);
|
||||
int nlen = strlen(pch);
|
||||
int i;
|
||||
for (i = len - 1; i >= pos; --i) {
|
||||
*(str + i + nlen) = *(str + i);
|
||||
}
|
||||
|
||||
int n;
|
||||
for (n = 0; n < nlen; n++) *(str + pos + n) = *pch++;
|
||||
*(str + len + nlen) = 0;
|
||||
}
|
||||
|
||||
static int _set_shadow_json_type(char *pJsonDoc, size_t sizeOfBuffer, Method method)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
int rc = QCLOUD_RET_SUCCESS;
|
||||
|
||||
POINTER_SANITY_CHECK(pJsonDoc, QCLOUD_ERR_INVAL);
|
||||
char *type_str = NULL;
|
||||
switch (method) {
|
||||
case GET:
|
||||
type_str = OPERATION_GET;
|
||||
break;
|
||||
case UPDATE:
|
||||
type_str = OPERATION_UPDATE;
|
||||
break;
|
||||
default:
|
||||
Log_e("unexpected method!");
|
||||
rc = QCLOUD_ERR_INVAL;
|
||||
break;
|
||||
}
|
||||
if (rc != QCLOUD_RET_SUCCESS)
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
|
||||
size_t json_len = strlen(pJsonDoc);
|
||||
size_t remain_size = sizeOfBuffer - json_len;
|
||||
|
||||
char json_node_str[64] = {0};
|
||||
HAL_Snprintf(json_node_str, 64, "\"type\":\"%s\", ", type_str);
|
||||
|
||||
size_t json_node_len = strlen(json_node_str);
|
||||
if (json_node_len >= remain_size - 1) {
|
||||
rc = QCLOUD_ERR_INVAL;
|
||||
} else {
|
||||
_insert(pJsonDoc, json_node_str, 1);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief unsubsribe topic: $shadow/operation/result/{ProductId}/{DeviceName}
|
||||
*/
|
||||
static int _unsubscribe_operation_result_to_cloud(Qcloud_IoT_Shadow *pShadow)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
int rc = QCLOUD_RET_SUCCESS;
|
||||
|
||||
if (pShadow->inner_data.result_topic == NULL)
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
|
||||
rc = IOT_MQTT_Unsubscribe(pShadow->mqtt, pShadow->inner_data.result_topic);
|
||||
if (rc < 0) {
|
||||
Log_e("unsubscribe topic: %s failed: %d.", pShadow->inner_data.result_topic, rc);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
static int _add_request_to_list(Qcloud_IoT_Shadow *pShadow, const char *pClientToken, RequestParams *pParams)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
HAL_MutexLock(pShadow->mutex);
|
||||
if (pShadow->inner_data.request_list->len >= MAX_APPENDING_REQUEST_AT_ANY_GIVEN_TIME) {
|
||||
HAL_MutexUnlock(pShadow->mutex);
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MAX_APPENDING_REQUEST);
|
||||
}
|
||||
|
||||
Request *request = (Request *)HAL_Malloc(sizeof(Request));
|
||||
if (NULL == request) {
|
||||
HAL_MutexUnlock(pShadow->mutex);
|
||||
Log_e("run memory malloc is error!");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
|
||||
request->callback = pParams->request_callback;
|
||||
strncpy(request->client_token, pClientToken, MAX_SIZE_OF_CLIENT_TOKEN);
|
||||
|
||||
request->user_context = pParams->user_context;
|
||||
request->method = pParams->method;
|
||||
|
||||
InitTimer(&(request->timer));
|
||||
countdown(&(request->timer), pParams->timeout_sec);
|
||||
|
||||
ListNode *node = list_node_new(request);
|
||||
if (NULL == node) {
|
||||
HAL_MutexUnlock(pShadow->mutex);
|
||||
Log_e("run list_node_new is error!");
|
||||
HAL_Free(request);
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
|
||||
list_rpush(pShadow->inner_data.request_list, node);
|
||||
|
||||
HAL_MutexUnlock(pShadow->mutex);
|
||||
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief iterator list and call traverseHandle for each node
|
||||
*/
|
||||
static void _traverse_list(Qcloud_IoT_Shadow *pShadow, List *list, const char *pClientToken, const char *pType,
|
||||
TraverseHandle traverseHandle)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
HAL_MutexLock(pShadow->mutex);
|
||||
|
||||
if (list->len) {
|
||||
ListIterator *iter;
|
||||
ListNode * node = NULL;
|
||||
|
||||
if (NULL == (iter = list_iterator_new(list, LIST_TAIL))) {
|
||||
HAL_MutexUnlock(pShadow->mutex);
|
||||
IOT_FUNC_EXIT;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
node = list_iterator_next(iter);
|
||||
if (NULL == node) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (NULL == node->val) {
|
||||
Log_e("node's value is invalid!");
|
||||
continue;
|
||||
}
|
||||
|
||||
traverseHandle(pShadow, &node, list, pClientToken, pType);
|
||||
}
|
||||
|
||||
list_iterator_destroy(iter);
|
||||
}
|
||||
HAL_MutexUnlock(pShadow->mutex);
|
||||
|
||||
IOT_FUNC_EXIT;
|
||||
}
|
||||
|
||||
static void _handle_request_callback(Qcloud_IoT_Shadow *pShadow, ListNode **node, List *list, const char *pClientToken,
|
||||
const char *pType)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
Request *request = (Request *)(*node)->val;
|
||||
if (NULL == request)
|
||||
IOT_FUNC_EXIT;
|
||||
|
||||
if (strcmp(request->client_token, pClientToken) == 0) {
|
||||
RequestAck status = ACK_NONE;
|
||||
|
||||
// result field in payload tell us if operation success or not
|
||||
// result = 0 for success, result != 0 for fail
|
||||
int16_t result_code = 0;
|
||||
|
||||
bool parse_success = parse_shadow_operation_result_code(pShadow->shadow_recv_buf, &result_code);
|
||||
if (parse_success) {
|
||||
if (result_code == 0) {
|
||||
status = ACK_ACCEPTED;
|
||||
} else {
|
||||
status = ACK_REJECTED;
|
||||
}
|
||||
|
||||
if ((strcmp(pType, "get") == 0 && status == ACK_ACCEPTED) ||
|
||||
(strcmp(pType, "update") && status == ACK_REJECTED)) {
|
||||
char *delta_str = NULL;
|
||||
if (parse_shadow_operation_get(pShadow->shadow_recv_buf, &delta_str)) {
|
||||
_handle_delta(pShadow, delta_str);
|
||||
HAL_Free(delta_str);
|
||||
}
|
||||
}
|
||||
|
||||
if (request->callback != NULL) {
|
||||
request->callback(pShadow, request->method, status, pShadow->shadow_recv_buf, request->user_context);
|
||||
}
|
||||
} else {
|
||||
Log_e("parse shadow operation result code failed.");
|
||||
}
|
||||
|
||||
list_remove(list, *node);
|
||||
*node = NULL;
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT;
|
||||
}
|
||||
|
||||
static void _handle_expired_request_callback(Qcloud_IoT_Shadow *pShadow, ListNode **node, List *list,
|
||||
const char *pClientToken, const char *pType)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
Request *request = (Request *)(*node)->val;
|
||||
if (NULL == request)
|
||||
IOT_FUNC_EXIT;
|
||||
|
||||
if (expired(&request->timer)) {
|
||||
if (request->callback != NULL) {
|
||||
request->callback(pShadow, request->method, ACK_TIMEOUT, pShadow->shadow_recv_buf, request->user_context);
|
||||
}
|
||||
|
||||
list_remove(list, *node);
|
||||
*node = NULL;
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
200
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/system/system_mqtt.c
vendored
Normal file
200
components/connectivity/qcloud-iot-hub-sdk/3rdparty/sdk_src/services/system/system_mqtt.c
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "qcloud_iot_export.h"
|
||||
#include "qcloud_iot_import.h"
|
||||
|
||||
#ifdef SYSTEM_COMM
|
||||
#include <string.h>
|
||||
|
||||
#include "lite-utils.h"
|
||||
#include "mqtt_client.h"
|
||||
#include "qcloud_iot_device.h"
|
||||
#include "qcloud_iot_export_system.h"
|
||||
|
||||
static void _system_mqtt_message_callback(void *pClient, MQTTMessage *message, void *pUserData)
|
||||
{
|
||||
#define MAX_RECV_LEN (512)
|
||||
|
||||
POINTER_SANITY_CHECK_RTN(message);
|
||||
|
||||
static char rcv_buf[MAX_RECV_LEN + 1];
|
||||
size_t len = (message->payload_len > MAX_RECV_LEN) ? MAX_RECV_LEN : (message->payload_len);
|
||||
|
||||
if (message->payload_len > MAX_RECV_LEN) {
|
||||
Log_e("payload len oversize");
|
||||
}
|
||||
memcpy(rcv_buf, message->payload, len);
|
||||
rcv_buf[len] = '\0'; // jsmn_parse relies on a string
|
||||
SysMQTTState *state = (SysMQTTState *)pUserData;
|
||||
|
||||
Log_d("Recv Msg Topic:%s, payload:%s", message->ptopic, rcv_buf);
|
||||
|
||||
char *value = LITE_json_value_of("time", rcv_buf);
|
||||
if (value != NULL)
|
||||
state->time = atol(value);
|
||||
|
||||
state->result_recv_ok = true;
|
||||
HAL_Free(value);
|
||||
return;
|
||||
}
|
||||
|
||||
static void _system_mqtt_sub_event_handler(void *pclient, MQTTEventType event_type, void *pUserData)
|
||||
{
|
||||
SysMQTTState *state = (SysMQTTState *)pUserData;
|
||||
|
||||
switch (event_type) {
|
||||
case MQTT_EVENT_SUBCRIBE_SUCCESS:
|
||||
Log_d("mqtt sys topic subscribe success");
|
||||
state->topic_sub_ok = true;
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBCRIBE_TIMEOUT:
|
||||
Log_i("mqtt sys topic subscribe timeout");
|
||||
state->topic_sub_ok = false;
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBCRIBE_NACK:
|
||||
Log_i("mqtt sys topic subscribe NACK");
|
||||
state->topic_sub_ok = false;
|
||||
break;
|
||||
case MQTT_EVENT_UNSUBSCRIBE:
|
||||
Log_i("mqtt sys topic has been unsubscribed");
|
||||
state->topic_sub_ok = false;
|
||||
;
|
||||
break;
|
||||
case MQTT_EVENT_CLIENT_DESTROY:
|
||||
Log_i("mqtt client has been destroyed");
|
||||
state->topic_sub_ok = false;
|
||||
;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int _iot_system_info_get_publish(void *pClient)
|
||||
{
|
||||
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
|
||||
DeviceInfo * dev_info = &mqtt_client->device_info;
|
||||
POINTER_SANITY_CHECK(dev_info, QCLOUD_ERR_INVAL);
|
||||
|
||||
char topic_name[128] = {0};
|
||||
char payload_content[128] = {0};
|
||||
|
||||
HAL_Snprintf(topic_name, sizeof(topic_name), "$sys/operation/%s/%s", dev_info->product_id, dev_info->device_name);
|
||||
HAL_Snprintf(payload_content, sizeof(payload_content), "{\"type\": \"get\", \"resource\": [\"time\"]}");
|
||||
|
||||
PublishParams pub_params = DEFAULT_PUB_PARAMS;
|
||||
pub_params.qos = QOS0;
|
||||
pub_params.payload = payload_content;
|
||||
pub_params.payload_len = strlen(payload_content);
|
||||
|
||||
return IOT_MQTT_Publish(mqtt_client, topic_name, &pub_params);
|
||||
}
|
||||
|
||||
static int _iot_system_info_result_subscribe(void *pClient)
|
||||
{
|
||||
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
|
||||
DeviceInfo * dev_info = &mqtt_client->device_info;
|
||||
SysMQTTState * sys_state = &mqtt_client->sys_state;
|
||||
|
||||
char topic_name[128] = {0};
|
||||
int size = HAL_Snprintf(topic_name, sizeof(topic_name), "$sys/operation/result/%s/%s", dev_info->product_id,
|
||||
dev_info->device_name);
|
||||
if (size < 0 || size > sizeof(topic_name) - 1) {
|
||||
Log_e("topic content length not enough! content size:%d buf size:%d", size, (int)sizeof(topic_name));
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
SubscribeParams sub_params = DEFAULT_SUB_PARAMS;
|
||||
sub_params.on_message_handler = _system_mqtt_message_callback;
|
||||
sub_params.on_sub_event_handler = _system_mqtt_sub_event_handler;
|
||||
sub_params.user_data = (void *)sys_state;
|
||||
sub_params.qos = QOS0;
|
||||
|
||||
return IOT_MQTT_Subscribe(pClient, topic_name, &sub_params);
|
||||
}
|
||||
|
||||
int IOT_Get_SysTime(void *pClient, long *time)
|
||||
{
|
||||
int ret = 0;
|
||||
int cntSub = 0;
|
||||
int cntRev = 0;
|
||||
|
||||
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
|
||||
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
|
||||
|
||||
SysMQTTState *sys_state = &mqtt_client->sys_state;
|
||||
// subscribe sys topic: $sys/operation/get/${productid}/${devicename}
|
||||
// skip this if the subscription is done and valid
|
||||
if (!sys_state->topic_sub_ok) {
|
||||
for (cntSub = 0; cntSub < 3; cntSub++) {
|
||||
ret = _iot_system_info_result_subscribe(mqtt_client);
|
||||
if (ret < 0) {
|
||||
Log_w("_iot_system_info_result_subscribe failed: %d, cnt: %d", ret, cntSub);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* wait for sub ack */
|
||||
ret = qcloud_iot_mqtt_yield_mt((Qcloud_IoT_Client *)pClient, 100);
|
||||
if (ret || sys_state->topic_sub_ok) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return failure if subscribe failed
|
||||
if (!sys_state->topic_sub_ok) {
|
||||
Log_e("Subscribe sys topic failed!");
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
sys_state->result_recv_ok = false;
|
||||
// publish msg to get system timestamp
|
||||
ret = _iot_system_info_get_publish(mqtt_client);
|
||||
if (ret < 0) {
|
||||
Log_e("client publish sys topic failed :%d.", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
do {
|
||||
ret = qcloud_iot_mqtt_yield_mt((Qcloud_IoT_Client *)pClient, 100);
|
||||
cntRev++;
|
||||
} while (!ret && !sys_state->result_recv_ok && cntRev < 20);
|
||||
|
||||
if (sys_state->result_recv_ok) {
|
||||
*time = sys_state->time;
|
||||
ret = QCLOUD_RET_SUCCESS;
|
||||
} else {
|
||||
*time = 0;
|
||||
ret = QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user