add new qloud-c-sdk component
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
file(GLOB src_log_upload ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c)
|
||||
set(inc_log_upload ${CMAKE_CURRENT_SOURCE_DIR}/inc/)
|
||||
|
||||
set(src_services ${src_services} ${src_log_upload} PARENT_SCOPE)
|
||||
set(inc_services ${inc_services} ${inc_log_upload} PARENT_SCOPE)
|
||||
|
||||
file(GLOB src_log_upload_sample ${CMAKE_CURRENT_SOURCE_DIR}/sample/log_upload_sample.c)
|
||||
add_executable(log_upload_sample ${src_log_upload_sample})
|
||||
target_link_libraries(log_upload_sample ${libsdk})
|
||||
|
||||
if( ${CONFIG_IOT_TEST} STREQUAL "ON")
|
||||
file(GLOB src_unit_test ${CMAKE_CURRENT_SOURCE_DIR}/test/*.cc)
|
||||
set(src_test ${src_test} ${src_unit_test} PARENT_SCOPE)
|
||||
endif()
|
@@ -0,0 +1,215 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2021 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.
|
||||
*
|
||||
* @file mqtt_client.h
|
||||
* @brief mqtt client internel api
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2021-05-31
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2021-05-31 <td>1.0 <td>fancyxu <td>first commit
|
||||
* <tr><td>2021-07-08 <td>1.1 <td>fancyxu <td>fix code standard of IotReturnCode and QcloudIotClient
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#ifndef IOT_HUB_DEVICE_C_SDK_SERVICES_COMMON_LOG_UPLOAD_INC_LOG_UPLOAD_H_
|
||||
#define IOT_HUB_DEVICE_C_SDK_SERVICES_COMMON_LOG_UPLOAD_INC_LOG_UPLOAD_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "qcloud_iot_log_upload.h"
|
||||
|
||||
#include "utils_list.h"
|
||||
#include "utils_base64.h"
|
||||
#include "utils_hmac.h"
|
||||
|
||||
/**
|
||||
* @brief To check log http server return msg or not
|
||||
*
|
||||
*/
|
||||
#define LOG_CHECK_HTTP_RET_CODE
|
||||
|
||||
/**
|
||||
* @brief enable log upload debug or not
|
||||
*
|
||||
*/
|
||||
// #define LOG_UPLOAD_DEBUG
|
||||
|
||||
/**
|
||||
* @brief http recv length
|
||||
*
|
||||
*/
|
||||
#define HTTP_RET_JSON_LENGTH 256
|
||||
|
||||
/**
|
||||
* @brief wait http recv time out
|
||||
*
|
||||
*/
|
||||
#define HTTP_WAIT_RET_TIMEOUT_MS 1000
|
||||
|
||||
/**
|
||||
* @brief 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)
|
||||
|
||||
/**
|
||||
* @brief sing key length
|
||||
*
|
||||
*/
|
||||
#define SIGN_KEY_SIZE (24)
|
||||
|
||||
#ifdef LOG_UPLOAD_DEBUG
|
||||
#define UPLOAD_DBG(fmt, ...) HAL_Printf(">>LOG-DBG>>%s(%d): " fmt "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__)
|
||||
#else
|
||||
#define UPLOAD_DBG(...)
|
||||
#endif
|
||||
#define UPLOAD_ERR(fmt, ...) HAL_Printf(">>LOG-ERR>>%s(%d): " fmt "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief clear log upload buffer
|
||||
*
|
||||
*/
|
||||
void log_upload_clear_buffer(void);
|
||||
|
||||
/**
|
||||
* @brief set log upload in comm err state
|
||||
*
|
||||
* @param state true or false
|
||||
*/
|
||||
void log_upload_set_upload_log_in_comm_err(bool state);
|
||||
|
||||
/**
|
||||
* @brief change log upload level
|
||||
*
|
||||
* @param level
|
||||
*/
|
||||
void log_upload_set_log_upload_level(LogLevel level);
|
||||
|
||||
/**
|
||||
* @brief get log upload level
|
||||
*
|
||||
* @return LogLevel
|
||||
*/
|
||||
LogLevel log_upload_get_log_upload_level(void);
|
||||
|
||||
/**
|
||||
* @brief log upload buffer init
|
||||
*
|
||||
* @param init_params @see LogUploadInitParams
|
||||
* @return void* if success return @see LogUploadBuffer
|
||||
*/
|
||||
void *log_upload_buffer_init(LogUploadInitParams *init_params);
|
||||
/**
|
||||
* @brief deinit log buffer handle
|
||||
*
|
||||
* @param upload_buffer_handle
|
||||
*/
|
||||
void log_upload_buffer_deinit(void *upload_buffer_handle);
|
||||
/**
|
||||
* @brief Get the log buffer write index object
|
||||
*
|
||||
* @param log_upload_buffer_handle
|
||||
* @return uint32_t
|
||||
*/
|
||||
uint32_t get_log_buffer_write_index(void *log_upload_buffer_handle);
|
||||
/**
|
||||
* @brief Get the log buffer head len object
|
||||
*
|
||||
* @param log_upload_buffer_handle
|
||||
* @return uint32_t
|
||||
*/
|
||||
uint32_t get_log_buffer_head_len(void *log_upload_buffer_handle);
|
||||
/**
|
||||
* @brief check log buffer is empty or not
|
||||
*
|
||||
* @param log_upload_buffer_handle
|
||||
* @return true empty
|
||||
* @return false not empty
|
||||
*/
|
||||
bool have_data_need_update(void *log_upload_buffer_handle);
|
||||
/**
|
||||
* @brief When a new log appears during the reporting period, move the log to the specified position in the buffer
|
||||
*
|
||||
*/
|
||||
void remove_log_from_buffer(void *log_upload_buffer_handle, uint32_t need_remove_size);
|
||||
/**
|
||||
* @brief copy log buffer head
|
||||
*
|
||||
* @param[out] dst Destination address
|
||||
* @param log_upload_buffer_handle
|
||||
*/
|
||||
void copy_log_buffer_header(char *dst, void *log_upload_buffer_handle);
|
||||
|
||||
/**
|
||||
* @brief lock log buffer
|
||||
*
|
||||
*/
|
||||
void log_buffer_lock(void);
|
||||
|
||||
/**
|
||||
* @brief unlock log buffer
|
||||
*
|
||||
*/
|
||||
void log_buffer_unlock(void);
|
||||
|
||||
/**
|
||||
* @brief post data to tencent cloud over http
|
||||
*
|
||||
* @param[in] post_buf need post data buffer
|
||||
* @param[in] post_size need post data buffer length
|
||||
* @return @see IotReturnCode
|
||||
*/
|
||||
int post_one_http_to_server(void *handle, char *post_buf, size_t post_size);
|
||||
|
||||
/**
|
||||
* @brief Get the log buffer object
|
||||
*
|
||||
* @param log_upload_buffer_handle
|
||||
* @return char*
|
||||
*/
|
||||
char *get_log_buffer(void *log_upload_buffer_handle);
|
||||
|
||||
/**
|
||||
* @brief push data to log buffer
|
||||
*
|
||||
* @param[in] log_content need push data
|
||||
* @return int if 0 success else QCLOUD_ERR_FAILURE
|
||||
*/
|
||||
int append_data_to_log_buffer(const char *log_content);
|
||||
/**
|
||||
* @brief init log upload module
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @return @see IotReturnCode
|
||||
*/
|
||||
int log_upload_init(void *client);
|
||||
/**
|
||||
* @brief Get the log buffer size object
|
||||
*
|
||||
* @return uint32_t log buffer size
|
||||
*/
|
||||
uint32_t get_log_buffer_size(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // IOT_HUB_DEVICE_C_SDK_SERVICES_COMMON_LOG_UPLOAD_INC_LOG_UPLOAD_H_
|
@@ -0,0 +1,220 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2021 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.
|
||||
*
|
||||
* @file broadcast_sample.c
|
||||
* @brief
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2021-07-18
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2021-07-18 <td>1.0 <td>fancyxu <td>first commit
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "qcloud_iot_common.h"
|
||||
|
||||
#include "utils_log.h"
|
||||
|
||||
/**
|
||||
* @brief MQTT event callback, @see MQTTEventHandleFun
|
||||
*
|
||||
* @param[in] client pointer to mqtt client
|
||||
* @param[in] handle_context context
|
||||
* @param[in] msg msg
|
||||
*/
|
||||
static void _mqtt_event_handler(void *client, void *handle_context, MQTTEventMsg *msg)
|
||||
{
|
||||
MQTTMessage *mqtt_message = (MQTTMessage *)msg->msg;
|
||||
uintptr_t packet_id = (uintptr_t)msg->msg;
|
||||
|
||||
switch (msg->event_type) {
|
||||
case MQTT_EVENT_UNDEF:
|
||||
Log_i("undefined event occur.");
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_DISCONNECT:
|
||||
Log_i("MQTT disconnect.");
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_RECONNECT:
|
||||
Log_i("MQTT reconnect.");
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_PUBLISH_RECEIVED:
|
||||
Log_i("topic message arrived but without any related handle: topic=%.*s, topic_msg=%.*s",
|
||||
mqtt_message->topic_len, STRING_PTR_PRINT_SANITY_CHECK(mqtt_message->topic_name),
|
||||
mqtt_message->payload_len, STRING_PTR_PRINT_SANITY_CHECK((char *)mqtt_message->payload));
|
||||
break;
|
||||
case MQTT_EVENT_SUBSCRIBE_SUCCESS:
|
||||
Log_i("subscribe success, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBSCRIBE_TIMEOUT:
|
||||
Log_i("subscribe wait ack timeout, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBSCRIBE_NACK:
|
||||
Log_i("subscribe nack, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_UNSUBSCRIBE_SUCCESS:
|
||||
Log_i("unsubscribe success, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_UNSUBSCRIBE_TIMEOUT:
|
||||
Log_i("unsubscribe timeout, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_UNSUBSCRIBE_NACK:
|
||||
Log_i("unsubscribe nack, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_PUBLISH_SUCCESS:
|
||||
Log_i("publish success, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_PUBLISH_TIMEOUT:
|
||||
Log_i("publish timeout, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_PUBLISH_NACK:
|
||||
Log_i("publish nack, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
default:
|
||||
Log_i("Should NOT arrive here.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Setup MQTT construct parameters.
|
||||
*
|
||||
* @param[in,out] initParams @see MQTTInitParams
|
||||
* @param[in] device_info @see DeviceInfo
|
||||
*/
|
||||
static void _setup_connect_init_params(MQTTInitParams *init_params, DeviceInfo *device_info)
|
||||
{
|
||||
init_params->device_info = device_info;
|
||||
init_params->command_timeout = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
|
||||
init_params->keep_alive_interval_ms = QCLOUD_IOT_MQTT_KEEP_ALIVE_INTERNAL;
|
||||
init_params->auto_connect_enable = 1;
|
||||
init_params->event_handle.h_fp = _mqtt_event_handler;
|
||||
init_params->event_handle.context = NULL;
|
||||
}
|
||||
|
||||
static void _setup_log_upload_init_params(LogUploadInitParams *init_params, DeviceInfo *device_info)
|
||||
{
|
||||
init_params->device_name = device_info->device_name;
|
||||
init_params->product_id = device_info->product_id;
|
||||
init_params->sign_key = device_info->device_secret;
|
||||
|
||||
init_params->log_buffer_size = LOG_UPLOAD_BUFFER_SIZE;
|
||||
init_params->save_log_filename = "./tmp/upload-fail-save.log";
|
||||
init_params->read_func = HAL_File_Read;
|
||||
init_params->save_func = HAL_File_Save;
|
||||
init_params->del_func = HAL_File_Del;
|
||||
init_params->get_size_func = HAL_File_Get_Size;
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
// Main
|
||||
// ----------------------------------------------------------------------------
|
||||
static int sg_main_exit = 0;
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void _main_exit(int sig)
|
||||
{
|
||||
Log_e("demo exit by signal:%d\n", sig);
|
||||
sg_main_exit = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#ifdef __linux__
|
||||
signal(SIGINT, _main_exit);
|
||||
#endif
|
||||
|
||||
int rc;
|
||||
int loop_cnt = 5;
|
||||
// init log level
|
||||
LogHandleFunc func = {0};
|
||||
|
||||
func.log_malloc = HAL_Malloc;
|
||||
func.log_free = HAL_Free;
|
||||
func.log_get_current_time_str = HAL_Timer_Current;
|
||||
func.log_printf = HAL_Printf;
|
||||
func.log_upload = IOT_Log_Upload_AppendToUploadBuffer;
|
||||
|
||||
utils_log_init(func, LOG_LEVEL_DEBUG, 2048);
|
||||
|
||||
DeviceInfo device_info;
|
||||
|
||||
rc = HAL_GetDevInfo((void *)&device_info);
|
||||
if (rc) {
|
||||
Log_e("get device info failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
// init connection
|
||||
MQTTInitParams init_params = DEFAULT_MQTT_INIT_PARAMS;
|
||||
_setup_connect_init_params(&init_params, &device_info);
|
||||
// init log upload
|
||||
LogUploadInitParams log_upload_init_params = DEFAULT_LOG_UPLOAD_INIT_PARAMS;
|
||||
|
||||
_setup_log_upload_init_params(&log_upload_init_params, &device_info);
|
||||
|
||||
IOT_Log_Upload_InitPre(&log_upload_init_params);
|
||||
// create MQTT client and connect with server
|
||||
void *client = IOT_MQTT_Construct(&init_params);
|
||||
if (client) {
|
||||
Log_i("Cloud Device Construct Success");
|
||||
rc = IOT_Log_Upload_Init(client);
|
||||
if (rc) {
|
||||
Log_e("Log upload init failed: %d", rc);
|
||||
}
|
||||
IOT_Log_Upload(true);
|
||||
} else {
|
||||
Log_e("MQTT Construct failed!");
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
do {
|
||||
Log_d("log upload test debug %d...", loop_cnt);
|
||||
Log_i("log upload test info %d...", loop_cnt);
|
||||
Log_w("log upload test waring %d...", loop_cnt);
|
||||
Log_e("log upload test error %d...", loop_cnt);
|
||||
rc = IOT_MQTT_Yield(client, 200);
|
||||
IOT_Log_Upload(rc ? true : false);
|
||||
} while (loop_cnt--);
|
||||
// If you have to report some urgent messages, you can call this function
|
||||
IOT_Log_Upload(true);
|
||||
rc = IOT_MQTT_Destroy(&client);
|
||||
IOT_Log_Upload_Deinit();
|
||||
utils_log_deinit();
|
||||
return rc;
|
||||
}
|
@@ -0,0 +1,741 @@
|
||||
/**
|
||||
* @file log_buffer.c
|
||||
* @author {hubert} ({hubertxxu@tencent.com})
|
||||
* @brief
|
||||
* @version 1.0
|
||||
* @date 2022-01-23
|
||||
*
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2021 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.
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* Date Version Author Description
|
||||
* 2022-01-23 1.0 hubertxxu first commit
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#include "log_upload.h"
|
||||
|
||||
typedef struct {
|
||||
void *lock_buf;
|
||||
char *log_buffer;
|
||||
const char *host;
|
||||
uint32_t log_buffer_size;
|
||||
uint32_t log_buffer_head_len;
|
||||
uint32_t write_index;
|
||||
char sign_key[SIGN_KEY_SIZE + 1];
|
||||
} LogUploadBuffer;
|
||||
|
||||
static LogUploadBuffer *sg_log_upload_buffer_handle = NULL;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Common
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief reset log upload buffer
|
||||
*
|
||||
* @param[in,out] log_upload_buffer_handle handle of log upload buffer
|
||||
*/
|
||||
static void _reset_log_buffer(LogUploadBuffer *log_upload_buffer_handle)
|
||||
{
|
||||
log_upload_buffer_handle->write_index = log_upload_buffer_handle->log_buffer_head_len;
|
||||
memset(log_upload_buffer_handle->log_buffer + log_upload_buffer_handle->log_buffer_head_len, 0,
|
||||
log_upload_buffer_handle->log_buffer_size - log_upload_buffer_handle->log_buffer_head_len);
|
||||
}
|
||||
|
||||
static LogUploadBuffer *_log_upload_buffer_init_pre(LogUploadInitParams *init_params)
|
||||
{
|
||||
LogUploadBuffer *handle = (LogUploadBuffer *)HAL_Malloc(sizeof(LogUploadBuffer));
|
||||
if (!handle) {
|
||||
UPLOAD_ERR("log upload buffer handle malloc error.");
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
memset(handle, 0, sizeof(LogUploadBuffer));
|
||||
|
||||
handle->lock_buf = HAL_MutexCreate();
|
||||
if (!handle->lock_buf) {
|
||||
UPLOAD_ERR("mutex create failed");
|
||||
goto err_exit;
|
||||
}
|
||||
handle->log_buffer_size = init_params->log_buffer_size;
|
||||
handle->log_buffer = HAL_Malloc(handle->log_buffer_size);
|
||||
if (!handle->log_buffer) {
|
||||
UPLOAD_ERR("malloc log buffer failed");
|
||||
goto err_exit;
|
||||
}
|
||||
memset(handle->log_buffer, 0, handle->log_buffer_size);
|
||||
|
||||
/*init sign key*/
|
||||
int key_len = strlen(init_params->sign_key);
|
||||
if (!key_len) {
|
||||
UPLOAD_ERR("invalid sign key length");
|
||||
goto err_exit;
|
||||
}
|
||||
memcpy(handle->sign_key, init_params->sign_key, key_len > SIGN_KEY_SIZE ? SIGN_KEY_SIZE : key_len);
|
||||
|
||||
sg_log_upload_buffer_handle = handle;
|
||||
return handle;
|
||||
err_exit:
|
||||
if (handle) {
|
||||
HAL_MutexDestroy(handle->lock_buf);
|
||||
HAL_Free(handle);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief deinit log buffer handle
|
||||
*
|
||||
* @param upload_buffer_handle
|
||||
*/
|
||||
void log_upload_buffer_deinit(void *upload_buffer_handle)
|
||||
{
|
||||
LogUploadBuffer *handle = (LogUploadBuffer *)upload_buffer_handle;
|
||||
if (!handle) {
|
||||
return;
|
||||
}
|
||||
HAL_MutexLock(handle->lock_buf);
|
||||
_reset_log_buffer(handle);
|
||||
HAL_Free(handle->log_buffer);
|
||||
handle->log_buffer = NULL;
|
||||
HAL_MutexUnlock(handle->lock_buf);
|
||||
HAL_MutexDestroy(handle->lock_buf);
|
||||
handle->lock_buf = NULL;
|
||||
HAL_Free(handle);
|
||||
sg_log_upload_buffer_handle = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the log buffer write index object
|
||||
*
|
||||
* @param log_upload_buffer_handle
|
||||
* @return uint32_t
|
||||
*/
|
||||
uint32_t get_log_buffer_write_index(void *log_upload_buffer_handle)
|
||||
{
|
||||
LogUploadBuffer *handle = (LogUploadBuffer *)log_upload_buffer_handle;
|
||||
HAL_MutexLock(handle->lock_buf);
|
||||
uint32_t write_index = handle->write_index;
|
||||
HAL_MutexUnlock(handle->lock_buf);
|
||||
return write_index;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the log buffer object
|
||||
*
|
||||
* @param log_upload_buffer_handle
|
||||
* @return char*
|
||||
*/
|
||||
char *get_log_buffer(void *log_upload_buffer_handle)
|
||||
{
|
||||
LogUploadBuffer *handle = (LogUploadBuffer *)log_upload_buffer_handle;
|
||||
return handle->log_buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the log buffer head len object
|
||||
*
|
||||
* @param log_upload_buffer_handle
|
||||
* @return uint32_t
|
||||
*/
|
||||
uint32_t get_log_buffer_head_len(void *log_upload_buffer_handle)
|
||||
{
|
||||
LogUploadBuffer *handle = (LogUploadBuffer *)log_upload_buffer_handle;
|
||||
return handle->log_buffer_head_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief check log buffer is empty or not
|
||||
*
|
||||
* @param log_upload_buffer_handle
|
||||
* @return true empty
|
||||
* @return false not empty
|
||||
*/
|
||||
bool have_data_need_update(void *log_upload_buffer_handle)
|
||||
{
|
||||
LogUploadBuffer *handle = (LogUploadBuffer *)log_upload_buffer_handle;
|
||||
return handle->write_index == handle->log_buffer_head_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief When a new log appears during the reporting period, move the log to the specified position in the buffer
|
||||
*
|
||||
*/
|
||||
void remove_log_from_buffer(void *log_upload_buffer_handle, uint32_t need_remove_size)
|
||||
{
|
||||
LogUploadBuffer *handle = (LogUploadBuffer *)log_upload_buffer_handle;
|
||||
if (need_remove_size > handle->write_index || need_remove_size > handle->log_buffer_size) {
|
||||
return;
|
||||
}
|
||||
HAL_MutexLock(handle->lock_buf);
|
||||
memmove(handle->log_buffer + handle->log_buffer_head_len, handle->log_buffer + need_remove_size,
|
||||
handle->write_index - need_remove_size);
|
||||
handle->write_index = handle->write_index - need_remove_size + handle->log_buffer_head_len;
|
||||
memset(handle->log_buffer + handle->write_index, 0, handle->log_buffer_size - handle->write_index);
|
||||
HAL_MutexUnlock(handle->lock_buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief copy log buffer head
|
||||
*
|
||||
* @param[out] dst Destination address
|
||||
* @param log_upload_buffer_handle
|
||||
*/
|
||||
void copy_log_buffer_header(char *dst, void *log_upload_buffer_handle)
|
||||
{
|
||||
LogUploadBuffer *handle = (LogUploadBuffer *)log_upload_buffer_handle;
|
||||
memcpy(dst, handle->log_buffer, handle->log_buffer_head_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief clear log upload buffer
|
||||
*
|
||||
*/
|
||||
void log_upload_clear_buffer(void)
|
||||
{
|
||||
if (!sg_log_upload_buffer_handle) {
|
||||
UPLOAD_ERR("log upload buffer not init.");
|
||||
return;
|
||||
}
|
||||
HAL_MutexLock(sg_log_upload_buffer_handle->lock_buf);
|
||||
_reset_log_buffer(sg_log_upload_buffer_handle);
|
||||
HAL_MutexUnlock(sg_log_upload_buffer_handle->lock_buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the log buffer size object
|
||||
*
|
||||
* @return uint32_t log buffer size
|
||||
*/
|
||||
uint32_t get_log_buffer_size(void)
|
||||
{
|
||||
if (!sg_log_upload_buffer_handle) {
|
||||
UPLOAD_ERR("log upload buffer not init.");
|
||||
return 0;
|
||||
}
|
||||
return sg_log_upload_buffer_handle->log_buffer_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
void log_buffer_lock(void)
|
||||
{
|
||||
HAL_MutexLock(sg_log_upload_buffer_handle->lock_buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
void log_buffer_unlock(void)
|
||||
{
|
||||
HAL_MutexUnlock(sg_log_upload_buffer_handle->lock_buf);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// New log fromat by json
|
||||
// ----------------------------------------------------------------------------
|
||||
#ifdef LOG_UPLOAD_TYPE_JSON
|
||||
/**
|
||||
* @brief log upload buffer init
|
||||
*
|
||||
* @param init_params @see LogUploadInitParams
|
||||
* @return void* if success return @see LogUploadBuffer
|
||||
*/
|
||||
void *log_upload_buffer_init(LogUploadInitParams *init_params)
|
||||
{
|
||||
LogUploadBuffer *handle = _log_upload_buffer_init_pre(init_params);
|
||||
if (!handle) {
|
||||
return NULL;
|
||||
}
|
||||
handle->log_buffer_head_len = HAL_Snprintf(handle->log_buffer, handle->log_buffer_size,
|
||||
"{\"DeviceName\":\"%s\",\"ProductId\":\"%s\",\"Message\":[",
|
||||
init_params->device_name, init_params->product_id);
|
||||
handle->write_index = handle->log_buffer_head_len;
|
||||
handle->host = init_params->host;
|
||||
_reset_log_buffer(handle);
|
||||
return handle;
|
||||
}
|
||||
|
||||
#ifdef LOG_CHECK_HTTP_RET_CODE
|
||||
/**
|
||||
* @brief get http respose result
|
||||
*
|
||||
* @param[in] json http response buffer
|
||||
* @param[in] json_len http response buffer length
|
||||
* @return true log report success
|
||||
* @return false log report error
|
||||
*/
|
||||
static bool _get_json_ret_code(char *json, size_t json_len)
|
||||
{
|
||||
int rc = 0;
|
||||
UtilsJsonValue resposse;
|
||||
// get response
|
||||
rc = utils_json_value_get("Response.Error", strlen("Response.Error"), json, json_len, &resposse);
|
||||
if (rc) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief when upload. append endchar in the upload buffer ending
|
||||
*
|
||||
* @param[in,out] log_buf upload buffer
|
||||
* @param[in] log_size upload buffer index
|
||||
*/
|
||||
static void _append_endchar_to_upload_buffer(char *log_buf, size_t log_size)
|
||||
{
|
||||
log_buf[log_size - 2] = ']';
|
||||
log_buf[log_size - 1] = '}';
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief when upload. remove endchar in the upload buffer ending
|
||||
*
|
||||
* @param[in,out] log_buf upload buffer
|
||||
* @param[in] log_size upload buffer index
|
||||
*/
|
||||
static void _remove_endchar_from_upload_buffer(char *log_buf, size_t log_size)
|
||||
{
|
||||
log_buf[log_size - 2] = ',';
|
||||
log_buf[log_size - 1] = ' ';
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief post data to tencent cloud over http
|
||||
*
|
||||
* @param[in] post_buf need post data buffer
|
||||
* @param[in] post_size need post data buffer length
|
||||
* @return @see IotReturnCode
|
||||
*/
|
||||
int post_one_http_to_server(void *log_upload_buffer_handle, char *post_buf, size_t post_size)
|
||||
{
|
||||
int rc = 0;
|
||||
LogUploadBuffer *handle = (LogUploadBuffer *)log_upload_buffer_handle;
|
||||
if (!post_size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_append_endchar_to_upload_buffer(post_buf, post_size);
|
||||
|
||||
HttpSignedParams params = {
|
||||
.host = handle->host ? handle->host : LOG_UPLOAD_SERVER_URL,
|
||||
.uri = LOG_UPLOAD_URI_PATH,
|
||||
.secretkey = handle->sign_key,
|
||||
#ifdef LOG_CHECK_HTTP_RET_CODE
|
||||
.need_recv = true,
|
||||
.recv_timeout_ms = HTTP_WAIT_RET_TIMEOUT_MS,
|
||||
#else
|
||||
.need_recv = false,
|
||||
.recv_timeout_ms = 0,
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef LOG_CHECK_HTTP_RET_CODE
|
||||
char buf[HTTP_RET_JSON_LENGTH] = {0};
|
||||
rc = IOT_HTTP_Signed_Request(¶ms, post_buf, post_size, (uint8_t *)buf, HTTP_RET_JSON_LENGTH);
|
||||
if (rc < 0) {
|
||||
UPLOAD_ERR("IOT_HTTP_Signed_Request failed, rc = %d", rc);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
UPLOAD_ERR("HTTP Recv length = %d", rc);
|
||||
rc = QCLOUD_ERR_HTTP;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
buf[rc - 1] = '\0'; // json_parse relies on a string
|
||||
if (strlen(buf) > 0 && _get_json_ret_code(buf, rc)) {
|
||||
UPLOAD_DBG("Log server return SUCCESS: %s", buf);
|
||||
rc = QCLOUD_RET_SUCCESS;
|
||||
} else {
|
||||
UPLOAD_ERR("Log server return FAIL: %s", buf);
|
||||
rc = QCLOUD_ERR_HTTP;
|
||||
}
|
||||
|
||||
#else
|
||||
rc = IOT_HTTP_Signed_Request(¶ms, post_buf, post_size, NULL, 0);
|
||||
#endif
|
||||
|
||||
exit:
|
||||
_remove_endchar_from_upload_buffer(post_buf, post_size);
|
||||
UPLOAD_DBG("%ld data have be post to server. rc : %d", post_size, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief push data to log buffer
|
||||
*
|
||||
* @param[in] log_content need push data
|
||||
* @return int if 0 success else QCLOUD_ERR_FAILURE
|
||||
*/
|
||||
int append_data_to_log_buffer(const char *log_content)
|
||||
{
|
||||
uint16_t log_size = strlen(log_content);
|
||||
if (HAL_MutexTryLock(sg_log_upload_buffer_handle->lock_buf) != 0) {
|
||||
UPLOAD_ERR("trylock buffer failed!");
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
if ((sg_log_upload_buffer_handle->write_index + log_size + 5) > sg_log_upload_buffer_handle->log_buffer_size) {
|
||||
HAL_MutexUnlock(sg_log_upload_buffer_handle->lock_buf);
|
||||
UPLOAD_ERR("log upload buffer is not enough!");
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
sg_log_upload_buffer_handle->log_buffer[sg_log_upload_buffer_handle->write_index++] = '\"';
|
||||
int index = 0;
|
||||
while (index < (log_size - 2)) {
|
||||
// replace may overflow buffer size
|
||||
if ((sg_log_upload_buffer_handle->write_index + 5) > sg_log_upload_buffer_handle->log_buffer_size) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (log_content[index]) {
|
||||
case '\"':
|
||||
sg_log_upload_buffer_handle->log_buffer[sg_log_upload_buffer_handle->write_index++] = '\\';
|
||||
sg_log_upload_buffer_handle->log_buffer[sg_log_upload_buffer_handle->write_index++] = '\"';
|
||||
break;
|
||||
case '\\':
|
||||
sg_log_upload_buffer_handle->log_buffer[sg_log_upload_buffer_handle->write_index++] = '\\';
|
||||
sg_log_upload_buffer_handle->log_buffer[sg_log_upload_buffer_handle->write_index++] = '\\';
|
||||
break;
|
||||
case '/':
|
||||
sg_log_upload_buffer_handle->log_buffer[sg_log_upload_buffer_handle->write_index++] = '\\';
|
||||
sg_log_upload_buffer_handle->log_buffer[sg_log_upload_buffer_handle->write_index++] = '/';
|
||||
break;
|
||||
case '\b':
|
||||
sg_log_upload_buffer_handle->log_buffer[sg_log_upload_buffer_handle->write_index++] = '\\';
|
||||
sg_log_upload_buffer_handle->log_buffer[sg_log_upload_buffer_handle->write_index++] = 'b';
|
||||
break;
|
||||
case '\f':
|
||||
sg_log_upload_buffer_handle->log_buffer[sg_log_upload_buffer_handle->write_index++] = '\\';
|
||||
sg_log_upload_buffer_handle->log_buffer[sg_log_upload_buffer_handle->write_index++] = 'f';
|
||||
break;
|
||||
case '\n':
|
||||
sg_log_upload_buffer_handle->log_buffer[sg_log_upload_buffer_handle->write_index++] = '\\';
|
||||
sg_log_upload_buffer_handle->log_buffer[sg_log_upload_buffer_handle->write_index++] = 'n';
|
||||
break;
|
||||
case '\r':
|
||||
sg_log_upload_buffer_handle->log_buffer[sg_log_upload_buffer_handle->write_index++] = '\\';
|
||||
sg_log_upload_buffer_handle->log_buffer[sg_log_upload_buffer_handle->write_index++] = 'r';
|
||||
break;
|
||||
case '\t':
|
||||
sg_log_upload_buffer_handle->log_buffer[sg_log_upload_buffer_handle->write_index++] = '\\';
|
||||
sg_log_upload_buffer_handle->log_buffer[sg_log_upload_buffer_handle->write_index++] = 't';
|
||||
break;
|
||||
default:
|
||||
sg_log_upload_buffer_handle->log_buffer[sg_log_upload_buffer_handle->write_index++] =
|
||||
log_content[index];
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
/* replace \r\n to \", add as delimiter */
|
||||
sg_log_upload_buffer_handle->log_buffer[sg_log_upload_buffer_handle->write_index++] = '\"';
|
||||
sg_log_upload_buffer_handle->log_buffer[sg_log_upload_buffer_handle->write_index++] = ',';
|
||||
sg_log_upload_buffer_handle->log_buffer[sg_log_upload_buffer_handle->write_index++] = ' ';
|
||||
|
||||
HAL_MutexUnlock(sg_log_upload_buffer_handle->lock_buf);
|
||||
return QCLOUD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
#else
|
||||
// ----------------------------------------------------------------------------
|
||||
// Old log format by text
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/* 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)
|
||||
|
||||
#ifdef LOG_UPLOAD_AES_ENCRYPT_POST
|
||||
#include "mbedtls/aes.h"
|
||||
|
||||
/**
|
||||
* @brief header of encrypt
|
||||
*
|
||||
*/
|
||||
static char sg_head_content[128] = {0};
|
||||
|
||||
/**
|
||||
* @brief log data encrypt by aes cbc
|
||||
*
|
||||
* @param handle
|
||||
* @param buf need encrypt data
|
||||
* @param datalen need encrypt data length
|
||||
* @return int
|
||||
*/
|
||||
static int _log_aes_cbc_encrypt(LogUploadBuffer *handle, uint8_t *buf, uint32_t datalen)
|
||||
{
|
||||
int ret = QCLOUD_RET_SUCCESS;
|
||||
|
||||
mbedtls_aes_context ctx;
|
||||
|
||||
unsigned char iv[16];
|
||||
memset(iv, '0', 16);
|
||||
|
||||
mbedtls_aes_init(&ctx);
|
||||
|
||||
ret = mbedtls_aes_setkey_enc(&ctx, (uint8_t *)handle->sign_key, 128);
|
||||
if (ret) {
|
||||
UPLOAD_ERR("Set encry key err,ret:%d", ret);
|
||||
ret = QCLOUD_ERR_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, datalen, iv, buf, buf);
|
||||
if (ret) {
|
||||
Log_e("encrypt err,ret:%d", ret);
|
||||
ret = QCLOUD_ERR_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
mbedtls_aes_free(&ctx);
|
||||
return QCLOUD_RET_SUCCESS;
|
||||
|
||||
exit:
|
||||
mbedtls_aes_free(&ctx);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief log upload buffer init
|
||||
*
|
||||
* @param init_params @see LogUploadInitParams
|
||||
* @return void* if success return @see LogUploadBuffer
|
||||
*/
|
||||
void *log_upload_buffer_init(LogUploadInitParams *init_params)
|
||||
{
|
||||
LogUploadBuffer *handle = _log_upload_buffer_init_pre(init_params);
|
||||
if (!handle) {
|
||||
return NULL;
|
||||
}
|
||||
handle->log_buffer_head_len = LOG_BUF_FIXED_HEADER_SIZE;
|
||||
memset(handle->log_buffer, '#', handle->log_buffer_head_len);
|
||||
handle->log_buffer[SIGNATURE_SIZE] = 'P';
|
||||
memcpy(handle->log_buffer + SIGNATURE_SIZE + CTRL_BYTES_SIZE, init_params->product_id, MAX_SIZE_OF_PRODUCT_ID);
|
||||
memcpy(handle->log_buffer + SIGNATURE_SIZE + CTRL_BYTES_SIZE + MAX_SIZE_OF_PRODUCT_ID, init_params->device_name,
|
||||
strlen(init_params->device_name));
|
||||
handle->write_index = handle->log_buffer_head_len;
|
||||
handle->host = init_params->host;
|
||||
_reset_log_buffer(handle);
|
||||
|
||||
#ifdef LOG_UPLOAD_AES_ENCRYPT_POST
|
||||
HAL_Snprintf(sg_head_content, 128,
|
||||
"Accept:application/json;*/*\r\n"
|
||||
"X-TC-IotEncryType:%c\r\n"
|
||||
"X-TC-IotCid:%s%s\r\n",
|
||||
handle->log_buffer[SIGNATURE_SIZE], init_params->product_id, init_params->device_name);
|
||||
#endif
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
#ifdef LOG_CHECK_HTTP_RET_CODE
|
||||
/**
|
||||
* @brief get http respose result
|
||||
*
|
||||
* @param[in] json http response buffer
|
||||
* @param[in] json_len http response buffer length
|
||||
* @return true log report success
|
||||
* @return false log report error
|
||||
*/
|
||||
static bool _get_json_ret_code(char *json, size_t json_len)
|
||||
{
|
||||
int rc = 0;
|
||||
uint32_t ret_code;
|
||||
rc = utils_json_get_uint32("Retcode", strlen("Retcode"), json, json_len, &ret_code);
|
||||
if (!rc) {
|
||||
if (!ret_code) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief update timestamp add signature post buffer
|
||||
*
|
||||
*/
|
||||
static void _update_time_and_signature(LogUploadBuffer *handle, char *post_buf, size_t post_size)
|
||||
{
|
||||
char timestamp[TIMESTAMP_SIZE + 1] = {0};
|
||||
char signature[SIGNATURE_SIZE + 1] = {0};
|
||||
uint32_t now_time = HAL_Timer_CurrentSec();
|
||||
|
||||
/* record the timestamp for this log uploading */
|
||||
HAL_Snprintf(timestamp, TIMESTAMP_SIZE + 1, "%010d", now_time);
|
||||
memcpy(post_buf + sg_log_upload_buffer_handle->log_buffer_head_len - TIMESTAMP_SIZE, timestamp, strlen(timestamp));
|
||||
|
||||
/* signature of this log uploading */
|
||||
utils_hmac_sha1(post_buf + SIGNATURE_SIZE, post_size - SIGNATURE_SIZE, (uint8_t *)handle->sign_key,
|
||||
strlen(handle->sign_key), signature);
|
||||
memcpy(post_buf, signature, SIGNATURE_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief post data to tencent cloud over http
|
||||
*
|
||||
* @param[in] post_buf need post data buffer
|
||||
* @param[in] post_size need post data buffer length
|
||||
* @return @see IotReturnCode
|
||||
*/
|
||||
int post_one_http_to_server(void *log_upload_buffer_handle, char *post_buf, size_t post_size)
|
||||
{
|
||||
int rc = 0;
|
||||
#ifdef LOG_UPLOAD_AES_ENCRYPT_POST
|
||||
char *log_encrypt_buffer = NULL;
|
||||
#endif
|
||||
LogUploadBuffer *handle = (LogUploadBuffer *)log_upload_buffer_handle;
|
||||
_update_time_and_signature(handle, post_buf, post_size);
|
||||
void *http_client = IOT_HTTP_Init();
|
||||
if (!http_client) {
|
||||
UPLOAD_ERR("http client init error");
|
||||
goto exit;
|
||||
}
|
||||
IotHTTPConnectParams connect_params = {
|
||||
.url = handle->host ? handle->host : LOG_UPLOAD_OLD_SERVER_URL,
|
||||
.port = LOG_UPLOAD_OLD_SERVER_PORT,
|
||||
.ca_crt = NULL, // TODO: support cert
|
||||
};
|
||||
|
||||
rc = IOT_HTTP_Connect(http_client, &connect_params);
|
||||
if (rc) {
|
||||
UPLOAD_ERR("http connect error.");
|
||||
goto exit;
|
||||
}
|
||||
IotHTTPRequestParams request = {
|
||||
.url = handle->host ? handle->host : LOG_UPLOAD_OLD_SERVER_URL,
|
||||
.method = IOT_HTTP_METHOD_POST,
|
||||
.content_length = post_size,
|
||||
.content_type = "text/plain;charset=utf-8",
|
||||
.content = post_buf,
|
||||
.header = "Accept:application/json;*/*\r\n",
|
||||
};
|
||||
|
||||
#ifdef LOG_UPLOAD_AES_ENCRYPT_POST
|
||||
/*ANSI X.923: zero-padding with last byte as padlen */
|
||||
int padlen = 16 - post_size % 16;
|
||||
int datalen = post_size + padlen;
|
||||
log_encrypt_buffer = HAL_Malloc(datalen + 1);
|
||||
if (!log_encrypt_buffer) {
|
||||
UPLOAD_ERR("malloc log encrypt buffer error. malloc length : %d", datalen);
|
||||
rc = QCLOUD_ERR_MALLOC;
|
||||
goto exit;
|
||||
}
|
||||
memset(log_encrypt_buffer, 0, datalen + 1);
|
||||
memcpy(log_encrypt_buffer, post_buf, post_size);
|
||||
log_encrypt_buffer[datalen - 1] = padlen;
|
||||
|
||||
// aes cbc
|
||||
rc = _log_aes_cbc_encrypt(handle, (uint8_t *)log_encrypt_buffer, datalen);
|
||||
if (QCLOUD_RET_SUCCESS != rc) {
|
||||
UPLOAD_ERR("log encrypt failed, ret = %d", rc);
|
||||
goto exit;
|
||||
}
|
||||
request.header = sg_head_content;
|
||||
request.content_type = "application/octet-stream";
|
||||
request.content_length = datalen;
|
||||
request.content = log_encrypt_buffer;
|
||||
#endif
|
||||
|
||||
rc = IOT_HTTP_Request(http_client, &request);
|
||||
// 2. check rc
|
||||
if (rc) {
|
||||
UPLOAD_ERR("http post error.");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
#ifdef LOG_CHECK_HTTP_RET_CODE
|
||||
char buf[HTTP_RET_JSON_LENGTH] = {0};
|
||||
rc = IOT_HTTP_Recv(http_client, (uint8_t *)buf, HTTP_RET_JSON_LENGTH, HTTP_WAIT_RET_TIMEOUT_MS);
|
||||
if (rc < 0) {
|
||||
UPLOAD_ERR("qcloud_http_recv_data failed, rc = %d", rc);
|
||||
} else if (rc == 0) {
|
||||
UPLOAD_ERR("HTTP Recv length == %d", rc);
|
||||
rc = QCLOUD_ERR_HTTP_TIMEOUT;
|
||||
} else {
|
||||
buf[rc - 1] = '\0'; // json_parse relies on a string
|
||||
if (strlen(buf) > 0 && _get_json_ret_code(buf, rc)) {
|
||||
UPLOAD_DBG("Log server return SUCCESS: %s", buf);
|
||||
rc = QCLOUD_RET_SUCCESS;
|
||||
} else {
|
||||
UPLOAD_ERR("Log server return FAIL: %s", buf);
|
||||
rc = QCLOUD_ERR_HTTP;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
exit:
|
||||
if (http_client) {
|
||||
IOT_HTTP_Disconnect(http_client);
|
||||
IOT_HTTP_Deinit(http_client);
|
||||
}
|
||||
#ifdef LOG_UPLOAD_AES_ENCRYPT_POST
|
||||
if (log_encrypt_buffer) {
|
||||
HAL_Free(log_encrypt_buffer);
|
||||
log_encrypt_buffer = NULL;
|
||||
}
|
||||
#endif
|
||||
UPLOAD_DBG("%ld data have be post to server. rc : %d", post_size, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief push data to log buffer
|
||||
*
|
||||
* @param[in] log_content need push data
|
||||
* @return int if 0 success else QCLOUD_ERR_FAILURE
|
||||
*/
|
||||
int append_data_to_log_buffer(const char *log_content)
|
||||
{
|
||||
uint16_t log_size = strlen(log_content);
|
||||
if (HAL_MutexTryLock(sg_log_upload_buffer_handle->lock_buf) != 0) {
|
||||
UPLOAD_ERR("trylock buffer failed!");
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
if ((sg_log_upload_buffer_handle->write_index + log_size + 1) > sg_log_upload_buffer_handle->log_buffer_size) {
|
||||
HAL_MutexUnlock(sg_log_upload_buffer_handle->lock_buf);
|
||||
UPLOAD_ERR("log upload buffer is not enough! remain : %d, need upload length: %d",
|
||||
sg_log_upload_buffer_handle->log_buffer_size - sg_log_upload_buffer_handle->write_index, log_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(sg_log_upload_buffer_handle->log_buffer + sg_log_upload_buffer_handle->write_index, log_content, log_size);
|
||||
sg_log_upload_buffer_handle->write_index += log_size;
|
||||
|
||||
/* replace \r\n to \n\f as delimiter */
|
||||
sg_log_upload_buffer_handle->log_buffer[sg_log_upload_buffer_handle->write_index - 1] = '\f';
|
||||
sg_log_upload_buffer_handle->log_buffer[sg_log_upload_buffer_handle->write_index - 2] = '\n';
|
||||
|
||||
HAL_MutexUnlock(sg_log_upload_buffer_handle->lock_buf);
|
||||
return QCLOUD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
@@ -0,0 +1,183 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2021 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.
|
||||
*
|
||||
* @file log_mqtt.c
|
||||
* @brief
|
||||
* @author hubertxxu (hubertxxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2022-01-05
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2022-01-05 <td>1.0 <td>hubertxxu <td>first commit
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#include "log_upload.h"
|
||||
|
||||
/**
|
||||
* @brief LogLevelResultInfo handle
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
bool result_recv_ok;
|
||||
uint32_t log_level;
|
||||
} LogLevelResultInfo;
|
||||
|
||||
/**
|
||||
* @brief MQTTLogUploadHandle handle
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
void *mqtt_client;
|
||||
Timer time_update_timer;
|
||||
} MQTTLogUploadHandle;
|
||||
|
||||
static MQTTLogUploadHandle sg_mqtt_log_upload_handle;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] message message from topic
|
||||
* @param[in,out] usr_data pointer to @see LogLevelResultInfo
|
||||
*/
|
||||
static void _log_mqtt_message_callback(void *client, const MQTTMessage *message, void *usr_data)
|
||||
{
|
||||
int rc;
|
||||
LogLevelResultInfo *result = (LogLevelResultInfo *)usr_data;
|
||||
Log_d("Receive log result message:%.*s", message->payload_len, message->payload_str);
|
||||
// get log level
|
||||
rc = utils_json_get_uint32("log_level", strlen("log_level"), message->payload_str, message->payload_len,
|
||||
&result->log_level);
|
||||
if (rc) {
|
||||
return;
|
||||
}
|
||||
switch (result->log_level) {
|
||||
case LOG_LEVEL_DISABLE:
|
||||
log_upload_clear_buffer();
|
||||
log_upload_set_upload_log_in_comm_err(true);
|
||||
#ifdef LOG_UPLOAD_AES_ENCRYPT_POST
|
||||
// when use aes encrypt. no need report log
|
||||
log_upload_set_log_upload_level(LOG_LEVEL_DISABLE);
|
||||
UPLOAD_DBG("disable log upload.");
|
||||
#else
|
||||
log_upload_set_log_upload_level(LOG_LEVEL_ERROR);
|
||||
UPLOAD_DBG("Upload log level change to: %d", LOG_LEVEL_ERROR);
|
||||
#endif
|
||||
|
||||
break;
|
||||
case LOG_LEVEL_ERROR:
|
||||
case LOG_LEVEL_WARN:
|
||||
case LOG_LEVEL_INFO:
|
||||
case LOG_LEVEL_DEBUG:
|
||||
if (result->log_level < log_upload_get_log_upload_level()) {
|
||||
log_upload_clear_buffer();
|
||||
}
|
||||
log_upload_set_upload_log_in_comm_err(false);
|
||||
log_upload_set_log_upload_level((LogLevel)result->log_level);
|
||||
UPLOAD_DBG("Upload log level change to: %d", result->log_level);
|
||||
break;
|
||||
|
||||
default:
|
||||
UPLOAD_ERR("Invalid log level: %d", result->log_level);
|
||||
break;
|
||||
}
|
||||
|
||||
result->result_recv_ok = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check and subscribe log result topic.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @return @see IotReturnCode
|
||||
*/
|
||||
static int _log_upload_topic_check_and_sub(void *client, const char *topic)
|
||||
{
|
||||
int rc = 0;
|
||||
SubscribeParams sub_params = DEFAULT_SUB_PARAMS;
|
||||
LogLevelResultInfo *log_level_info = (LogLevelResultInfo *)HAL_Malloc(sizeof(LogLevelResultInfo));
|
||||
if (!log_level_info) {
|
||||
return QCLOUD_ERR_MALLOC;
|
||||
}
|
||||
log_level_info->result_recv_ok = false;
|
||||
sub_params.on_message_handler = _log_mqtt_message_callback;
|
||||
sub_params.qos = QOS1;
|
||||
sub_params.user_data = log_level_info;
|
||||
sub_params.user_data_free = HAL_Free;
|
||||
|
||||
rc = IOT_MQTT_SubscribeSync(client, topic, &sub_params);
|
||||
if (rc) {
|
||||
HAL_Free(log_level_info);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Publish get log level message to log topic.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @return >= 0 for success
|
||||
*/
|
||||
static int _mqtt_get_log_level_publish(void *client)
|
||||
{
|
||||
static int sg_get_log_level_token_count = 0;
|
||||
char topic_name[MAX_SIZE_OF_CLOUD_TOPIC];
|
||||
char payload[128] = {0};
|
||||
|
||||
HAL_Snprintf(topic_name, sizeof(topic_name), "$log/operation/%s/%s",
|
||||
STRING_PTR_PRINT_SANITY_CHECK(IOT_MQTT_GetDeviceInfo(client)->product_id),
|
||||
STRING_PTR_PRINT_SANITY_CHECK(IOT_MQTT_GetDeviceInfo(client)->device_name));
|
||||
|
||||
HAL_Snprintf(payload, sizeof(payload), "{\"type\": \"get_log_level\",\"clientToken\": \"get_log_level-%u\"}",
|
||||
sg_get_log_level_token_count++);
|
||||
|
||||
PublishParams pub_params = DEFAULT_PUB_PARAMS;
|
||||
pub_params.qos = QOS0;
|
||||
pub_params.payload = payload;
|
||||
pub_params.payload_len = strlen(payload);
|
||||
return IOT_MQTT_Publish(client, topic_name, &pub_params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief init log upload module
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @return @see IotReturnCode
|
||||
*/
|
||||
int log_upload_init(void *client)
|
||||
{
|
||||
int rc = 0;
|
||||
char log_upload_topic[MAX_SIZE_OF_CLOUD_TOPIC];
|
||||
/* subscribe the log topic: "$log/operation/result/${productId}/${deviceName}" */
|
||||
HAL_Snprintf(log_upload_topic, MAX_SIZE_OF_CLOUD_TOPIC, "$log/operation/result/%s/%s",
|
||||
STRING_PTR_PRINT_SANITY_CHECK(IOT_MQTT_GetDeviceInfo(client)->product_id),
|
||||
STRING_PTR_PRINT_SANITY_CHECK(IOT_MQTT_GetDeviceInfo(client)->device_name));
|
||||
|
||||
rc = _log_upload_topic_check_and_sub(client, log_upload_topic);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = _mqtt_get_log_level_publish(client);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
sg_mqtt_log_upload_handle.mqtt_client = client;
|
||||
return rc;
|
||||
}
|
@@ -0,0 +1,539 @@
|
||||
/**
|
||||
* @file log_upload.c
|
||||
* @author {hubert} ({hubertxxu@tencent.com})
|
||||
* @brief
|
||||
* @version 1.0
|
||||
* @date 2022-01-24
|
||||
*
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2021 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.
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* Date Version Author Description
|
||||
* 2022-01-24 1.0 hubertxxu first commit
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#include "log_upload.h"
|
||||
|
||||
#ifdef LOG_UPLOAD_TYPE_JSON
|
||||
#define LOG_DELIMITER "\", "
|
||||
#else
|
||||
#define LOG_DELIMITER "\n\f"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief data structure for log upload
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
bool upload_only_in_comm_err;
|
||||
LogLevel log_level;
|
||||
Timer upload_timer;
|
||||
void *upload_buffer_handle;
|
||||
|
||||
const char *save_log_filename;
|
||||
LogSaveFunc save_func;
|
||||
LogReadFunc read_func;
|
||||
LogDelFunc del_func;
|
||||
LogGetSizeFunc get_size_func;
|
||||
|
||||
bool log_save_enabled;
|
||||
bool log_client_init_done;
|
||||
} QcloudIoTLogUpload;
|
||||
|
||||
static QcloudIoTLogUpload *sg_log_uploader_client;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Internal API
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @return QcloudIoTLogUpload* @see QcloudIoTLogUpload
|
||||
*/
|
||||
static QcloudIoTLogUpload *_get_log_uploader_client(void)
|
||||
{
|
||||
if (!sg_log_uploader_client) {
|
||||
return NULL;
|
||||
}
|
||||
if (!sg_log_uploader_client->log_client_init_done) {
|
||||
return NULL;
|
||||
}
|
||||
return sg_log_uploader_client;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param client @see QcloudIoTLogUpload
|
||||
*/
|
||||
static void _set_log_uploader_client(void *client)
|
||||
{
|
||||
sg_log_uploader_client = client;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief set log upload in comm err state
|
||||
*
|
||||
* @param state true or false
|
||||
*/
|
||||
void log_upload_set_upload_log_in_comm_err(bool state)
|
||||
{
|
||||
QcloudIoTLogUpload *log_uploader_handle = _get_log_uploader_client();
|
||||
POINTER_SANITY_CHECK_RTN(log_uploader_handle);
|
||||
log_uploader_handle->upload_only_in_comm_err = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief change log upload level
|
||||
*
|
||||
* @param level
|
||||
*/
|
||||
void log_upload_set_log_upload_level(LogLevel level)
|
||||
{
|
||||
QcloudIoTLogUpload *log_uploader_handle = _get_log_uploader_client();
|
||||
POINTER_SANITY_CHECK_RTN(log_uploader_handle);
|
||||
log_uploader_handle->log_level = level;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get log upload level
|
||||
*
|
||||
* @return LogLevel
|
||||
*/
|
||||
LogLevel log_upload_get_log_upload_level(void)
|
||||
{
|
||||
QcloudIoTLogUpload *log_uploader_handle = _get_log_uploader_client();
|
||||
POINTER_SANITY_CHECK(log_uploader_handle, LOG_LEVEL_DISABLE);
|
||||
return log_uploader_handle->log_level;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief check if need force upload
|
||||
*
|
||||
* @param[in] force_upload
|
||||
* @return true need force upload
|
||||
* @return false not needed force upload
|
||||
*/
|
||||
static bool _check_force_upload(bool force_upload)
|
||||
{
|
||||
QcloudIoTLogUpload *log_uploader_handle = _get_log_uploader_client();
|
||||
if (!log_uploader_handle) {
|
||||
return false;
|
||||
}
|
||||
/* 1: check if have data to upload */
|
||||
if (have_data_need_update(log_uploader_handle->upload_buffer_handle)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t write_index = get_log_buffer_write_index(log_uploader_handle->upload_buffer_handle);
|
||||
bool is_low_buffer = (get_log_buffer_size() - write_index) < LOG_LOW_BUFFER_THRESHOLD ? true : false;
|
||||
|
||||
/* 2. check if upload only in comm err */
|
||||
if (!force_upload && log_uploader_handle->upload_only_in_comm_err) {
|
||||
/* buffer is low but we couldn't upload now, reset buffer */
|
||||
if (is_low_buffer) {
|
||||
log_upload_clear_buffer();
|
||||
}
|
||||
HAL_Timer_CountdownMs(&log_uploader_handle->upload_timer, LOG_UPLOAD_INTERVAL_MS);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 3: force upload is true, handle it right now */
|
||||
if (force_upload) {
|
||||
return true;
|
||||
}
|
||||
/* 4 : check if buffer is low */
|
||||
if (is_low_buffer) {
|
||||
/* buffer is low, handle it right now */
|
||||
return true;
|
||||
}
|
||||
/*5: check if timeout, handle it right now*/
|
||||
return HAL_Timer_Expired(&log_uploader_handle->upload_timer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief save log to file or flash
|
||||
*
|
||||
* @param[in] log_buf need saved buffer
|
||||
* @param[in] log_size need saved buffer length
|
||||
* @return @see IotReturnCode
|
||||
*/
|
||||
static int _save_log(char *log_buf, size_t log_size)
|
||||
{
|
||||
int rc = 0;
|
||||
size_t write_size, current_size;
|
||||
QcloudIoTLogUpload *log_uploader_handle = _get_log_uploader_client();
|
||||
POINTER_SANITY_CHECK(log_uploader_handle, QCLOUD_ERR_INVAL);
|
||||
if (!log_size) {
|
||||
UPLOAD_ERR("nothing need to save. log_size : %ld", log_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
current_size = log_uploader_handle->get_size_func(log_uploader_handle->save_log_filename);
|
||||
|
||||
/* 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. %ld", current_size);
|
||||
rc = log_uploader_handle->del_func(log_uploader_handle->save_log_filename);
|
||||
if (rc) {
|
||||
Log_e("fail to delete previous log");
|
||||
}
|
||||
}
|
||||
UPLOAD_DBG("saved data [%ld]", log_size);
|
||||
write_size = log_uploader_handle->save_func(log_uploader_handle->save_log_filename, log_buf, log_size);
|
||||
if (write_size != log_size) {
|
||||
Log_e("fail to save log. RC %ld - log size %ld", write_size, log_size);
|
||||
}
|
||||
|
||||
return write_size != log_size ? -1 : 0;
|
||||
}
|
||||
|
||||
static uint32_t _buffer_get_at_most_message(char *post_buf)
|
||||
{
|
||||
uint32_t possible_size = 0;
|
||||
char *next_log_buf = NULL;
|
||||
size_t delimiter_len = strlen(LOG_DELIMITER);
|
||||
while (possible_size < MAX_HTTP_LOG_POST_SIZE) {
|
||||
/* locate the delimiter */
|
||||
next_log_buf = strstr(post_buf + possible_size, LOG_DELIMITER);
|
||||
if (!next_log_buf) {
|
||||
return 0;
|
||||
}
|
||||
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) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return possible_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief report these to the server
|
||||
*
|
||||
* @param post_buf
|
||||
* @param post_size
|
||||
* @param is_log_buffer
|
||||
* @return int
|
||||
*/
|
||||
static int _post_log_buffer_to_cloud(QcloudIoTLogUpload *log_uploader_handle, char *post_buf, size_t post_size,
|
||||
bool is_log_buffer)
|
||||
{
|
||||
int rc = 0;
|
||||
uint32_t log_buffer_head_len = get_log_buffer_head_len(log_uploader_handle->upload_buffer_handle);
|
||||
|
||||
size_t orig_post_size = post_size;
|
||||
size_t post_payload, possible_size, actual_post_payload = 0;
|
||||
do {
|
||||
// 1. get message in buffer
|
||||
possible_size = _buffer_get_at_most_message(post_buf);
|
||||
if (!possible_size) {
|
||||
UPLOAD_ERR("Upload size should not be 0! Total sent: %ld. Left: %ld",
|
||||
actual_post_payload + log_buffer_head_len, post_size);
|
||||
if (is_log_buffer) {
|
||||
log_upload_clear_buffer();
|
||||
}
|
||||
return QCLOUD_RET_SUCCESS;
|
||||
}
|
||||
if (is_log_buffer && (possible_size > get_log_buffer_size() || possible_size > orig_post_size ||
|
||||
possible_size <= log_buffer_head_len)) {
|
||||
log_upload_clear_buffer();
|
||||
UPLOAD_ERR("possible size (%ld) is too large.", possible_size);
|
||||
return QCLOUD_RET_SUCCESS;
|
||||
}
|
||||
// 2. post to server
|
||||
rc = post_one_http_to_server(log_uploader_handle->upload_buffer_handle, post_buf, possible_size);
|
||||
if (rc) {
|
||||
UPLOAD_ERR("Send log failed. Total sent: %ld. Left: %ld", actual_post_payload + log_buffer_head_len,
|
||||
post_size);
|
||||
// when send failed save log in file.
|
||||
if (log_uploader_handle->log_save_enabled && is_log_buffer) {
|
||||
_save_log(post_buf + log_buffer_head_len, possible_size - log_buffer_head_len);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. remove have be post message
|
||||
memmove(post_buf + log_buffer_head_len, post_buf + possible_size, post_size - possible_size);
|
||||
post_payload = possible_size - log_buffer_head_len;
|
||||
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 ", possible_size,
|
||||
actual_post_payload + log_buffer_head_len, post_size);
|
||||
} while (post_size > log_buffer_head_len);
|
||||
|
||||
if (is_log_buffer) {
|
||||
remove_log_from_buffer(log_uploader_handle->upload_buffer_handle, orig_post_size);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief handle log to save flash or file
|
||||
*
|
||||
* @return @see IotReturnCode
|
||||
*/
|
||||
static int _handle_saved_log(void)
|
||||
{
|
||||
int rc = QCLOUD_RET_SUCCESS;
|
||||
QcloudIoTLogUpload *log_uploader_handle = _get_log_uploader_client();
|
||||
if (!log_uploader_handle) {
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
size_t whole_log_size = log_uploader_handle->get_size_func(log_uploader_handle->save_log_filename);
|
||||
if (!whole_log_size) {
|
||||
return rc;
|
||||
}
|
||||
uint32_t log_buffer_head_len = get_log_buffer_head_len(log_uploader_handle->upload_buffer_handle);
|
||||
size_t buf_size = whole_log_size + log_buffer_head_len + 1;
|
||||
char *log_buf = HAL_Malloc(buf_size);
|
||||
if (!log_buf) {
|
||||
UPLOAD_ERR("Malloc failed, size: %ld", buf_size);
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
/* read the whole log to buffer */
|
||||
size_t read_len = log_uploader_handle->read_func(log_uploader_handle->save_log_filename,
|
||||
log_buf + log_buffer_head_len, whole_log_size);
|
||||
if (read_len != whole_log_size) {
|
||||
Log_e("fail to read whole saved log. Size: %ld - read: %ld", whole_log_size, read_len);
|
||||
rc = QCLOUD_ERR_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* copy header from global log buffer */
|
||||
size_t upload_size = whole_log_size + log_buffer_head_len;
|
||||
copy_log_buffer_header(log_buf, log_uploader_handle->upload_buffer_handle);
|
||||
log_buf[buf_size - 1] = 0;
|
||||
|
||||
/* post server */
|
||||
rc = _post_log_buffer_to_cloud(log_uploader_handle, log_buf, upload_size, false);
|
||||
if (rc == QCLOUD_RET_SUCCESS || rc == QCLOUD_ERR_INVAL || rc == QCLOUD_ERR_HTTP) {
|
||||
UPLOAD_DBG("handle saved log done! Size: %ld. ", whole_log_size);
|
||||
log_uploader_handle->del_func(log_uploader_handle->save_log_filename);
|
||||
}
|
||||
exit:
|
||||
HAL_Free(log_buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief append need report log to log upload buffer
|
||||
*
|
||||
* @param[in] log_content data of need to report
|
||||
*/
|
||||
static void _log_upload_append_to_log_buffer(int log_level, const char *log_content)
|
||||
{
|
||||
int rc = 0;
|
||||
QcloudIoTLogUpload *log_uploader_handle = _get_log_uploader_client();
|
||||
// POINTER_SANITY_CHECK_RTN(log_uploader_handle);
|
||||
if (!log_uploader_handle) {
|
||||
return;
|
||||
}
|
||||
// if not necessary. just give up upload.
|
||||
if (log_level > log_uploader_handle->log_level) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t log_size = strlen(log_content);
|
||||
if (!log_size) {
|
||||
UPLOAD_ERR("log_size is not 0!");
|
||||
return;
|
||||
}
|
||||
rc = append_data_to_log_buffer(log_content);
|
||||
if (rc) {
|
||||
/* log buffer is full. upload data right now */
|
||||
HAL_Timer_CountdownMs(&log_uploader_handle->upload_timer, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief upload data to tencent cloud
|
||||
*
|
||||
* @param force_upload if necessary
|
||||
* @return @see IotReturnCode
|
||||
*/
|
||||
static int _do_log_upload(bool force_upload)
|
||||
{
|
||||
int rc;
|
||||
static bool sg_need_handle_saved_log = true;
|
||||
|
||||
QcloudIoTLogUpload *log_uploader_handle = _get_log_uploader_client();
|
||||
POINTER_SANITY_CHECK(log_uploader_handle, QCLOUD_ERR_INVAL);
|
||||
|
||||
/* step1: handle previously saved log */
|
||||
if (log_uploader_handle->log_save_enabled && sg_need_handle_saved_log) {
|
||||
rc = _handle_saved_log();
|
||||
if (!rc) {
|
||||
sg_need_handle_saved_log = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* step2: check if have data to upload */
|
||||
if (!_check_force_upload(force_upload)) {
|
||||
return QCLOUD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
// log_buffer_lock();
|
||||
|
||||
/* step3: post log buffer data to cloud */
|
||||
uint32_t upload_log_size = get_log_buffer_write_index(log_uploader_handle->upload_buffer_handle);
|
||||
rc = _post_log_buffer_to_cloud(log_uploader_handle, get_log_buffer(log_uploader_handle->upload_buffer_handle),
|
||||
upload_log_size, true);
|
||||
if (rc) {
|
||||
sg_need_handle_saved_log = true;
|
||||
}
|
||||
|
||||
HAL_Timer_CountdownMs(&log_uploader_handle->upload_timer, LOG_UPLOAD_INTERVAL_MS);
|
||||
|
||||
// log_buffer_unlock();
|
||||
return QCLOUD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief init log upload previously
|
||||
*
|
||||
* @param[in] init_params @see LogUploadInitParams
|
||||
* @return @see IotReturnCode
|
||||
*/
|
||||
static int log_upload_init_pre(LogUploadInitParams *init_params)
|
||||
{
|
||||
if (_get_log_uploader_client()) {
|
||||
UPLOAD_DBG("log upload initialized.");
|
||||
return QCLOUD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
QcloudIoTLogUpload *log_uploader_handle = HAL_Malloc(sizeof(QcloudIoTLogUpload));
|
||||
if (!log_uploader_handle) {
|
||||
UPLOAD_ERR("allocate for log client failed");
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
log_uploader_handle->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 && init_params->read_func && init_params->del_func && init_params->get_size_func &&
|
||||
init_params->save_log_filename) {
|
||||
log_uploader_handle->save_log_filename = init_params->save_log_filename;
|
||||
log_uploader_handle->save_func = init_params->save_func;
|
||||
log_uploader_handle->read_func = init_params->read_func;
|
||||
log_uploader_handle->del_func = init_params->del_func;
|
||||
log_uploader_handle->get_size_func = init_params->get_size_func;
|
||||
log_uploader_handle->log_save_enabled = true;
|
||||
} else {
|
||||
log_uploader_handle->log_save_enabled = false;
|
||||
}
|
||||
|
||||
log_uploader_handle->upload_buffer_handle = log_upload_buffer_init(init_params);
|
||||
if (!log_uploader_handle->upload_buffer_handle) {
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
_set_log_uploader_client(log_uploader_handle);
|
||||
log_uploader_handle->log_level = LOG_LEVEL_DEBUG;
|
||||
log_uploader_handle->log_client_init_done = true;
|
||||
return QCLOUD_RET_SUCCESS;
|
||||
|
||||
err_exit:
|
||||
if (log_uploader_handle) {
|
||||
log_upload_buffer_deinit(log_uploader_handle->upload_buffer_handle);
|
||||
HAL_Free(log_uploader_handle);
|
||||
log_uploader_handle = NULL;
|
||||
}
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief stop log upload add release resources
|
||||
*
|
||||
* @return @see IotReturnCode
|
||||
*/
|
||||
static int log_upload_deinit(void)
|
||||
{
|
||||
QcloudIoTLogUpload *log_uploader_handle = _get_log_uploader_client();
|
||||
POINTER_SANITY_CHECK(log_uploader_handle, QCLOUD_ERR_INVAL);
|
||||
log_upload_buffer_deinit(log_uploader_handle->upload_buffer_handle);
|
||||
HAL_Free(log_uploader_handle);
|
||||
log_uploader_handle = NULL;
|
||||
return QCLOUD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// External API
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief init log upload previously
|
||||
*
|
||||
* @param[in] init_params @see LogUploadInitParams
|
||||
* @return @see IotReturnCode
|
||||
*/
|
||||
int IOT_Log_Upload_InitPre(LogUploadInitParams *init_params)
|
||||
{
|
||||
POINTER_SANITY_CHECK(init_params, QCLOUD_ERR_INVAL);
|
||||
STRING_PTR_SANITY_CHECK(init_params->product_id, QCLOUD_ERR_INVAL);
|
||||
STRING_PTR_SANITY_CHECK(init_params->device_name, QCLOUD_ERR_INVAL);
|
||||
STRING_PTR_SANITY_CHECK(init_params->sign_key, QCLOUD_ERR_INVAL);
|
||||
return log_upload_init_pre(init_params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief init log upload module
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @return @see IotReturnCode
|
||||
*/
|
||||
int IOT_Log_Upload_Init(void *client)
|
||||
{
|
||||
POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
return log_upload_init(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief stop log upload add release resources
|
||||
*
|
||||
* @return @see IotReturnCode
|
||||
*/
|
||||
int IOT_Log_Upload_Deinit(void)
|
||||
{
|
||||
return log_upload_deinit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief do log upload
|
||||
*
|
||||
* @param force_upload if necessary
|
||||
* @return @see IotReturnCode
|
||||
*/
|
||||
int IOT_Log_Upload(bool force_upload)
|
||||
{
|
||||
return _do_log_upload(force_upload);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief append need report log to log upload buffer
|
||||
*
|
||||
* @param[in] log_content data of need to report
|
||||
*/
|
||||
void IOT_Log_Upload_AppendToUploadBuffer(int log_level, const char *log_content)
|
||||
{
|
||||
POINTER_SANITY_CHECK_RTN(log_content);
|
||||
_log_upload_append_to_log_buffer(log_level, log_content);
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
ColumnLimit: 120
|
||||
DerivePointerAlignment: true
|
||||
PointerAlignment: Left
|
||||
SortIncludes: true
|
||||
IncludeBlocks: Preserve
|
||||
IndentPPDirectives: AfterHash
|
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2021 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.
|
||||
*
|
||||
* @file test_broadcast.cc
|
||||
* @brief
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2021-07-18
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2021-07-18 <td>1.0 <td>fancyxu <td>first commit
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "mqtt_client_test.h"
|
||||
#include "qcloud_iot_common.h"
|
||||
|
||||
namespace mqtt_client_unittest {
|
||||
|
||||
/**
|
||||
* @brief Test log upload
|
||||
*
|
||||
*/
|
||||
TEST_F(MqttClientTest, log_upload_test) {
|
||||
LogHandleFunc func = {0};
|
||||
func.log_malloc = HAL_Malloc;
|
||||
func.log_free = HAL_Free;
|
||||
func.log_get_current_time_str = HAL_Timer_Current;
|
||||
func.log_printf = HAL_Printf;
|
||||
func.log_upload = IOT_Log_Upload_AppendToUploadBuffer;
|
||||
utils_log_init(func, LOG_LEVEL_DEBUG, 2048);
|
||||
|
||||
LogUploadInitParams log_upload_init_params = DEFAULT_LOG_UPLOAD_INIT_PARAMS;
|
||||
log_upload_init_params.device_name = device_info.device_name;
|
||||
log_upload_init_params.product_id = device_info.product_id;
|
||||
log_upload_init_params.sign_key = device_info.device_secret;
|
||||
|
||||
log_upload_init_params.log_buffer_size = LOG_UPLOAD_BUFFER_SIZE;
|
||||
log_upload_init_params.save_log_filename = "./tmp/upload-fail-save.log";
|
||||
log_upload_init_params.read_func = HAL_File_Read;
|
||||
log_upload_init_params.save_func = HAL_File_Save;
|
||||
log_upload_init_params.del_func = HAL_File_Del;
|
||||
log_upload_init_params.get_size_func = HAL_File_Get_Size;
|
||||
|
||||
ASSERT_EQ(IOT_Log_Upload_InitPre(&log_upload_init_params), 0);
|
||||
|
||||
uint32_t loop_cnt = 10;
|
||||
int rc = 0;
|
||||
do {
|
||||
Log_d("log upload test debug %d...", loop_cnt);
|
||||
Log_i("log upload test info %d...", loop_cnt);
|
||||
Log_w("log upload test waring %d...", loop_cnt);
|
||||
Log_e("log upload test error %d...", loop_cnt);
|
||||
rc = IOT_MQTT_Yield(client, 200);
|
||||
ASSERT_EQ(IOT_Log_Upload(rc ? true : false), 0);
|
||||
} while (loop_cnt--);
|
||||
|
||||
ASSERT_EQ(IOT_Log_Upload_Deinit(), 0);
|
||||
|
||||
func.log_upload = NULL;
|
||||
utils_log_init(func, LOG_LEVEL_DEBUG, 2048);
|
||||
}
|
||||
|
||||
} // namespace mqtt_client_unittest
|
Reference in New Issue
Block a user