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:
daishengdong
2020-05-07 11:11:04 +08:00
parent c8e39739d3
commit 3e631cd96a
594 changed files with 47287 additions and 44165 deletions

View File

@@ -0,0 +1,103 @@
# UTILS
file(GLOB src_utils ${CMAKE_CURRENT_SOURCE_DIR}/utils/*.c)
set(src_sdk ${src_utils})
# MQTT
if(${FEATURE_MQTT_COMM_ENABLED} STREQUAL "ON")
# mqtt
file(GLOB src_mqtt ${CMAKE_CURRENT_SOURCE_DIR}/protocol/mqtt/*.c)
list(APPEND src_sdk ${src_mqtt})
# shadow
if(${FEATURE_MQTT_DEVICE_SHADOW} STREQUAL "ON")
file(GLOB src_shadow ${CMAKE_CURRENT_SOURCE_DIR}/services/shadow/*.c)
list(APPEND src_sdk ${src_shadow})
endif()
# ota mqtt
if(${FEATURE_OTA_COMM_ENABLED} STREQUAL "ON" AND ${FEATURE_OTA_SIGNAL_CHANNEL} STREQUAL "MQTT")
file(GLOB src_mqtt_ota
${CMAKE_CURRENT_SOURCE_DIR}/services/ota/ota_client.c
${CMAKE_CURRENT_SOURCE_DIR}/services/ota/ota_fetch.c
${CMAKE_CURRENT_SOURCE_DIR}/services/ota/ota_lib.c
${CMAKE_CURRENT_SOURCE_DIR}/services/ota/ota_mqtt.c)
list(APPEND src_sdk ${src_mqtt_ota})
endif()
# gateway
if(${FEATURE_GATEWAY_ENABLED} STREQUAL "ON")
file(GLOB src_gateway ${CMAKE_CURRENT_SOURCE_DIR}/services/gateway/*.c)
list(APPEND src_sdk ${src_gateway})
endif()
endif()
# COAP
if(${FEATURE_COAP_COMM_ENABLED} STREQUAL "ON")
# coap
file(GLOB src_coap ${CMAKE_CURRENT_SOURCE_DIR}/protocol/coap/*.c)
list(APPEND src_sdk ${src_coap})
# ota coap
if(${FEATURE_OTA_COMM_ENABLED} STREQUAL "ON" AND ${FEATURE_OTA_SIGNAL_CHANNEL} STREQUAL "COAP")
file(GLOB src_coap_ota
${CMAKE_CURRENT_SOURCE_DIR}/services/ota/ota_client.c
${CMAKE_CURRENT_SOURCE_DIR}/services/ota/ota_fetch.c
${CMAKE_CURRENT_SOURCE_DIR}/services/ota/ota_lib.c
${CMAKE_CURRENT_SOURCE_DIR}/services/ota/ota_coap.c)
list(APPEND src_sdk ${src_coap_ota})
endif()
endif()
# HTTP
if(${FEATURE_OTA_COMM_ENABLED} STREQUAL "ON" OR ${FEATURE_DEV_DYN_REG_ENABLED} STREQUAL "ON" OR ${FEATURE_LOG_UPLOAD_ENABLED} STREQUAL "ON")
# http
file(GLOB src_http ${CMAKE_CURRENT_SOURCE_DIR}/protocol/http/*.c)
list(APPEND src_sdk ${src_http})
endif()
# AT OR TCP
if(${FEATURE_AT_TCP_ENABLED} STREQUAL "ON")
# at
file(GLOB src_at_socket ${CMAKE_CURRENT_SOURCE_DIR}/network/at_socket/*.c)
list(APPEND src_sdk ${src_at_socket})
endif()
# TLS
if(${FEATURE_AUTH_WITH_NOTLS} STREQUAL "OFF")
file(GLOB src_tls ${CMAKE_CURRENT_SOURCE_DIR}/network/tls/*.c)
list(APPEND src_sdk ${src_tls})
endif()
# NETWORK
# tcp
file(GLOB src_socket ${CMAKE_CURRENT_SOURCE_DIR}/network/socket/*.c)
list(APPEND src_sdk ${src_socket})
# interface
file(GLOB src_network ${CMAKE_CURRENT_SOURCE_DIR}/network/*.c)
list(APPEND src_sdk ${src_network})
# OTHRE SERVICES
if(${FEATURE_LOG_UPLOAD_ENABLED} STREQUAL "ON")
file(GLOB src_log_upload ${CMAKE_CURRENT_SOURCE_DIR}/services/log/*.c)
list(APPEND src_sdk ${src_log_upload})
endif()
if(${FEATURE_DEV_DYN_REG_ENABLED} STREQUAL "ON")
file(GLOB src_dyn_reg ${CMAKE_CURRENT_SOURCE_DIR}/services/dynreg/*.c)
list(APPEND src_sdk ${src_dyn_reg})
endif()
if(${FEATURE_SYSTEM_COMM_ENABLED} STREQUAL "ON")
file(GLOB src_system ${CMAKE_CURRENT_SOURCE_DIR}/services/system/*.c)
list(APPEND src_sdk ${src_system})
endif()
if(${EXTRACT_SRC} STREQUAL "ON")
file(COPY ${src_sdk} DESTINATION ${PROJECT_SOURCE_DIR}/output/qcloud_iot_c_sdk/sdk_src/)
endif()
set(service_target "iot_sdk")
SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/output/${BUILD_TYPE}/lib/)
add_library(${service_target} STATIC ${src_sdk})

View File

@@ -0,0 +1,160 @@
/*
* 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.
*
*/
#ifndef __AT_CLIENT_H__
#define __AT_CLIENT_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "config.h"
#include "stddef.h"
#include "utils_ringbuff.h"
#define AT_FRAME_VERSION "1.0.0"
#define AT_CMD_NAME_LEN 16
#define AT_END_MARK_LEN 4
#define CLINET_BUFF_LEN (1024)
#define RING_BUFF_LEN CLINET_BUFF_LEN // uart ring buffer len
#define GET_CHAR_TIMEOUT_MS (5000)
#define CMD_RESPONSE_INTERVAL_MS (100)
typedef void (*ParserFunc)(void *userContex);
typedef enum {
AT_STATUS_UNINITIALIZED = 0,
AT_STATUS_INITIALIZED = 0x55,
AT_STATUS_BUSY = 0xaa,
} at_status;
enum at_resp_status {
AT_RESP_OK = 0, /* AT response end is OK */
AT_RESP_ERROR = -1, /* AT response end is ERROR */
AT_RESP_TIMEOUT = -2, /* AT response is timeout */
AT_RESP_BUFF_FULL = -3, /* AT response buffer is full */
};
typedef enum at_resp_status at_resp_status_t;
typedef struct _at_response_ {
/* response buffer */
char *buf;
/* the maximum response buffer size */
int buf_size;
/* the number of setting response lines
* == 0: the response data will auto return when received 'OK' or 'ERROR'
* != 0: the response data will return when received setting lines number data */
int line_num;
/* the count of received response lines */
int line_counts;
/* the maximum response time */
uint32_t timeout;
} at_response;
typedef at_response *at_response_t;
/* URC(Unsolicited Result Code) object, such as: 'RING', 'READY' request by AT server */
typedef struct _at_urc_ {
const char *cmd_prefix;
const char *cmd_suffix;
void (*func)(const char *data, size_t size);
} at_urc;
typedef at_urc *at_urc_t;
typedef struct _at_client_ {
at_status status;
char end_sign;
ring_buff_t pRingBuff;
char * recv_buffer;
uint32_t recv_bufsz;
uint32_t cur_recv_len;
void * lock; // pre cmd take the lock wait for resp , another cmd need wait for unlock
at_response_t resp;
at_resp_status_t resp_status;
const at_urc *urc_table;
uint16_t urc_table_size;
#ifdef AT_OS_USED
void * resp_sem; // resp received, send sem to notic ack wait
ParserFunc parser; // RX parser
#else
// bool resp_notice;
#endif
} at_client;
typedef at_client *at_client_t;
/* AT client initialize and start*/
int at_client_init(at_client_t *pClient);
/* AT client deinitial*/
int at_client_deinit(at_client_t pClient);
/* get AT client handle*/
at_client_t at_client_get(void);
/*AT connect detect*/
int at_client_wait_connect(uint32_t timeout);
/*wrapper for os and nonos delay*/
void at_delayms(uint32_t delayms);
void at_setFlag(uint32_t flag);
void at_clearFlag(uint32_t flag);
uint32_t at_getFlag(void);
bool at_waitFlag(uint32_t flag, uint32_t timeout);
/* ========================== multiple AT client function ============================ */
/* set AT client a line end sign */
void at_set_end_sign(char ch);
/* Set URC(Unsolicited Result Code) table */
void at_set_urc_table(at_client_t client, const at_urc_t table, uint32_t size);
/* AT client send or receive data */
int at_client_send(at_client_t client, const char *buf, int size, uint32_t timeout);
int at_client_obj_recv(char *buf, int size, int timeout);
/* AT client send commands to AT server and waiter response */
int at_obj_exec_cmd(at_response_t resp, const char *cmd_expr, ...);
#define at_exec_cmd(resp, ...) at_obj_exec_cmd(resp, __VA_ARGS__)
#define at_client_recv(buf, size, timeout) at_client_obj_recv(buf, size, timeout)
/* AT response object create and delete */
at_response_t at_create_resp(uint32_t buf_size, uint32_t line_num, uint32_t timeout);
void at_delete_resp(at_response_t resp);
/* AT response line buffer get and parse response buffer arguments */
const char *at_resp_get_line(at_response_t resp, uint32_t resp_line);
const char *at_resp_get_line_by_kw(at_response_t resp, const char *keyword);
int at_resp_parse_line_args(at_response_t resp, uint32_t resp_line, const char *resp_expr, ...);
int at_resp_parse_line_args_by_kw(at_response_t resp, const char *keyword, const char *resp_expr, ...);
/* ========================== single AT client function ============================ */
void at_client_yeild(at_urc *expect_urc, uint32_t timeout);
#ifdef __cplusplus
}
#endif
#endif /* __AT_H__ */

View File

@@ -0,0 +1,87 @@
/*
* 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.
*
*/
#ifndef _AT_SOCKET_INF_H_
#define _AT_SOCKET_INF_H_
#include <stdint.h>
#include <stdio.h>
#include "utils_list.h"
#define UNUSED_SOCKET (-1)
#define MAX_AT_SOCKET_NUM (5)
#define AT_SOCKET_SEND_TIMEOUT_MS (1000)
#define AT_SOCKET_RECV_TIMEOUT_MS (1000)
#define IPV4_STR_MAX_LEN (16)
typedef enum { eNET_TCP = 6, eNET_UDP = 17, eNET_DEFAULT = 0xff } eNetProto;
typedef enum { eSOCKET_ALLOCED = 0, eSOCKET_CONNECTED, eSOCKET_CLOSED } eSocketState;
/* AT receive package list structure */
typedef struct at_recv_pkt {
List list;
size_t bfsz_totle;
size_t bfsz_index;
char * buff;
} at_recv_pkt;
typedef enum {
AT_SOCKET_EVT_RECV = 0,
AT_SOCKET_EVT_CLOSED,
} at_socket_evt_t;
typedef void (*at_evt_cb_t)(int fd, at_socket_evt_t event, char *buff, size_t bfsz);
/*at device driver ops, use at_device_op_register register to at socket*/
typedef struct {
int (*init)(void);
int (*get_local_mac)(char *macbuff, size_t bufflen);
int (*get_local_ip)(char *ip, size_t iplen, char *gw, size_t gwlen, char *mask, size_t masklen);
int (*parse_domain)(const char *host_name, char *host_ip, size_t host_ip_len);
int (*connect)(const char *ip, uint16_t port, eNetProto proto);
int (*send)(int fd, const void *buf, size_t len);
int (*recv_timeout)(int fd, void *buf, size_t len, uint32_t timeout);
int (*close)(int fd);
void (*set_event_cb)(at_socket_evt_t event, at_evt_cb_t cb);
char *deviceName;
} at_device_op_t;
/*at socket context*/
typedef struct {
int fd; /** socket fd */
List * recvpkt_list;
char remote_ip[IPV4_STR_MAX_LEN];
uint16_t remote_port;
uint32_t send_timeout_ms;
uint32_t recv_timeout_ms;
void * recv_lock;
at_device_op_t *dev_op;
eNetProto net_type;
eSocketState state;
} at_socket_ctx_t;
// at socket api
int at_device_op_register(at_device_op_t *device_op);
int at_socket_init(void);
int at_socket_parse_domain(const char *host_name, char *host_ip, size_t host_ip_len);
int at_socket_get_local_mac(char *macbuff, size_t bufflen);
int at_socket_get_local_ip(char *ip, size_t iplen, char *gw, size_t gwlen, char *mask, size_t masklen);
int at_socket_connect(const char *host, uint16_t port, eNetProto eProto);
int at_socket_close(int fd);
int at_socket_send(int fd, const void *buf, size_t len);
int at_socket_recv(int fd, void *buf, size_t len);
#endif

View File

@@ -0,0 +1,103 @@
/*
* 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.
*
*/
#ifndef __AT_UART_HAL_H__
#define __AT_UART_HAL_H__
/*
* UART data width
*/
typedef enum {
BAUDRATE_2400 = 2400,
BAUDRATE_4800 = 4800,
BAUDRATE_9600 = 9600,
BAUDRATE_19200 = 19200,
BAUDRATE_115200 = 115200,
BAUDRATE_921600 = 921600,
BAUDRATE_DEFAULT = 115200
} hal_uart_baudr_t;
/*
* UART data width
*/
typedef enum {
DATA_WIDTH_5BIT,
DATA_WIDTH_6BIT,
DATA_WIDTH_7BIT,
DATA_WIDTH_8BIT,
DATA_WIDTH_9BIT
} hal_uart_data_width_t;
/*
* UART stop bits
*/
typedef enum { STOP_BITS_1, STOP_BITS_2 } hal_uart_stop_bits_t;
/*
* UART flow control
*/
typedef enum {
FLOW_CONTROL_DISABLED,
FLOW_CONTROL_CTS,
FLOW_CONTROL_RTS,
FLOW_CONTROL_CTS_RTS
} hal_uart_flow_control_t;
/*
* UART parity
*/
typedef enum { NO_PARITY, ODD_PARITY, EVEN_PARITY } hal_uart_parity_t;
/*
* UART mode
*/
typedef enum { MODE_TX, MODE_RX, MODE_TX_RX } hal_uart_mode_t;
/*
* UART state
*/
typedef enum {
eUNUSED = 0,
eOPENED = 1,
eCLOSED = 2,
} hal_uart_state_t;
/*
* UART configuration
*/
typedef struct {
uint32_t baud_rate;
hal_uart_data_width_t data_width;
hal_uart_parity_t parity;
hal_uart_stop_bits_t stop_bits;
hal_uart_flow_control_t flow_control;
hal_uart_mode_t mode;
} uart_config_t;
typedef struct {
#ifdef __linux__
int fd; /* uart fd */
#else
void *uart_handle; /* uart handle,like stm32 UART_HandleTypeDef */
#endif
hal_uart_state_t state; /* uart state */
uart_config_t config; /* uart config */
} uart_dev_t;
#ifdef __cplusplus
}
#endif
#endif /* __AT_H__ */

View File

@@ -0,0 +1,46 @@
/*
* 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.
*
*/
#ifndef _AT_UTILS_H_
#define _AT_UTILS_H_
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#define WIDTH_SIZE 32
#ifndef __INT_MAX__
#define __INT_MAX__ 2147483647
#endif
#ifndef INT_MAX
#define INT_MAX (__INT_MAX__)
#endif
#define AT_CMD_COMMA_MARK ','
#define AT_CMD_DQUOTES_MARK '"'
#define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
int at_vprintfln(const char *format, va_list args);
void at_print_raw_cmd(const char *name, const char *cmd, int size);
const char *at_get_last_cmd(int *cmd_size);
int at_req_parse_args(const char *req_args, const char *req_expr, ...);
int at_sscanf(const char *buf, const char *fmt, va_list args);
void at_strip(char *str, const char patten);
void chr_strip(char *str, const char patten);
#endif

View File

@@ -0,0 +1,471 @@
/*
* 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.
*
*/
#ifndef IOT_COAP_CLIENT_H_
#define IOT_COAP_CLIENT_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include <sys/types.h>
#include "coap_client_net.h"
#include "network_interface.h"
#include "qcloud_iot_common.h"
#include "qcloud_iot_export.h"
#include "utils_list.h"
#include "utils_timer.h"
/* COAP protocol version */
#define COAP_MSG_VER (0x01)
/* COAP init token */
#define COAP_MSG_INIT_TOKEN (0x01020304)
/* Minimal command timeout of CoAP ACK/RESP */
#define MIN_COMMAND_TIMEOUT (500)
/* Maximal command timeout of CoAP ACK/RESP */
#define MAX_COMMAND_TIMEOUT (5000)
/* Max size of conn Id */
#define COAP_MAX_CONN_ID_LEN (6)
/* Max size of Message id */
#define COAP_MSG_MAX_MSG_ID ((1 << 16) - 1)
/* Max size of Topic length */
#define URI_PATH_MAX_LEN (128)
/* CoAP auth success */
#define COAP_TRUE (1)
/* CoAP auth fail */
#define COAP_FALSE (0)
/* unique CoAP auth URI */
#define COAP_AUTH_URI ("txauth9w0BAQsFA")
/* Max size of token */
#define COAP_MSG_MAX_TOKEN_LEN (8)
/* COAP Max code class */
#define COAP_MSG_MAX_CODE_CLASS (7)
/* COAP Max code detail */
#define COAP_MSG_MAX_CODE_DETAIL (31)
/* Get field of Option num */
#define COAP_MSG_OPTION_NUM(option) ((option)->option_num)
/* Get field of Next Option */
#define COAP_MSG_OP_NEXT(option) ((option)->next)
/* If COAP msg is empty */
#define COAP_MSG_IS_EMPTY(message) (((message)->code_class == 0) && ((message)->code_detail == 0))
/* If COAP msg is empty ACK */
#define COAP_MSG_IS_EMPTY_ACK(message) (((message)->code_class == 2) && ((message)->code_detail == 3))
/* If COAP msg is RESP */
#define COAP_MSG_IS_EMPTY_RSP(message) (((message)->code_class == 2) && ((message)->code_detail == 5))
/**
* @brief COAP msg type
*/
typedef enum {
COAP_MSG_REQ = 0,
COAP_MSG_SUCCESS = 2,
COAP_MSG_CLIENT_ERR = 4,
COAP_MSG_SERVER_ERR = 5,
COAP_MSG_SDKINTERNAL_ERR = 6,
} CoAPMessageClass;
/**
* @brief COAP msg type
*/
typedef enum { COAP_MSG_GET = 1, COAP_MSG_POST = 2, COAP_MSG_PUT = 3, COAP_MSG_DELETE = 4 } CoAPRequestMethod;
typedef enum {
/* CoAP Success Response code detail */
COAP_MSG_CODE_201_CREATED = 01, /* Mapping to CoAP codeClass.codeDetail 2.01 */
COAP_MSG_CODE_202_DELETED = 02, /* Mapping to CoAP codeClass.codeDetail 2.02 */
COAP_MSG_CODE_203_VALID = 03, /* Mapping to CoAP codeClass.codeDetail 2.03 */
COAP_MSG_CODE_204_CHANGED = 04, /* Mapping to CoAP codeClass.codeDetail 2.04 */
COAP_MSG_CODE_205_CONTENT = 05, /* Mapping to CoAP codeClass.codeDetail 2.05 */
COAP_MSG_CODE_231_CONTINUE = 31, /* Mapping to CoAP codeClass.codeDetail 2.31 */
/* CoAP Client Error Response code detail */
COAP_MSG_CODE_400_BAD_REQUEST = 00, /* Mapping to CoAP codeClass.codeDetail 4.00 */
COAP_MSG_CODE_401_UNAUTHORIZED = 01, /* Mapping to CoAP codeClass.codeDetail 4.01 */
COAP_MSG_CODE_402_BAD_OPTION = 02, /* Mapping to CoAP codeClass.codeDetail 4.02 */
COAP_MSG_CODE_403_FORBIDDEN = 03, /* Mapping to CoAP codeClass.codeDetail 4.03 */
COAP_MSG_CODE_404_NOT_FOUND = 04, /* Mapping to CoAP codeClass.codeDetail 4.04 */
COAP_MSG_CODE_405_METHOD_NOT_ALLOWED = 05, /* Mapping to CoAP codeClass.codeDetail 4.05 */
COAP_MSG_CODE_406_NOT_ACCEPTABLE = 06, /* Mapping to CoAP codeClass.codeDetail 4.06 */
COAP_MSG_CODE_408_REQUEST_ENTITY_INCOMPLETE = 8, /* Mapping to CoAP codeClass.codeDetail 4.08 */
COAP_MSG_CODE_412_PRECONDITION_FAILED = 12, /* Mapping to CoAP codeClass.codeDetail 4.12 */
COAP_MSG_CODE_413_REQUEST_ENTITY_TOO_LARGE = 13, /* Mapping to CoAP codeClass.codeDetail 4.13 */
COAP_MSG_CODE_415_UNSUPPORTED_CONTENT_FORMAT = 15, /* Mapping to CoAP codeClass.codeDetail 4.15 */
/* CoAP Server Error Response code detail */
COAP_MSG_CODE_500_INTERNAL_SERVER_ERROR = 00, /* Mapping to CoAP codeClass.codeDetail 5.00 */
COAP_MSG_CODE_501_NOT_IMPLEMENTED = 01, /* Mapping to CoAP codeClass.codeDetail 5.01 */
COAP_MSG_CODE_502_BAD_GATEWAY = 02, /* Mapping to CoAP codeClass.codeDetail 5.02 */
COAP_MSG_CODE_503_SERVICE_UNAVAILABLE = 03, /* Mapping to CoAP codeClass.codeDetail 5.03 */
COAP_MSG_CODE_504_GATEWAY_TIMEOUT = 04, /* Mapping to CoAP codeClass.codeDetail 5.04 */
COAP_MSG_CODE_505_PROXYING_NOT_SUPPORTED = 05, /* Mapping to CoAP codeClass.codeDetail 5.05 */
COAP_MSG_CODE_600_TIMEOUT = 00, /* Mapping to self define CoAP codeClass.codeDetail 6.00 */
} CoAPRespCodeDetail;
/**
* @brief Option number enumeration
*/
typedef enum {
COAP_MSG_IF_MATCH = 1, // If-Match option number
COAP_MSG_URI_HOST = 3, // URI-Host option number
COAP_MSG_ETAG = 4, // Entity-Tag option number
COAP_MSG_IF_NONE_MATCH = 5, // If-None-Match option number
COAP_MSG_URI_PORT = 7, // URI-Port option number
COAP_MSG_LOCATION_PATH = 8, // Location-Path option number
COAP_MSG_URI_PATH = 11, // URI-Path option number
COAP_MSG_CONTENT_FORMAT = 12, // Content-Format option number
COAP_MSG_MAX_AGE = 14, // Max-Age option number
COAP_MSG_URI_QUERY = 15, // URI-Query option number
COAP_MSG_ACCEPT = 17, // Accept option number
COAP_MSG_LOCATION_QUERY = 20, // Location-Query option number
COAP_MSG_BLOCK2 = 23, // Block2 option number
COAP_MSG_BLOCK1 = 27, // Block1 option number
COAP_MSG_SIZE2 = 28, // Size2 option number
COAP_MSG_PROXY_URI = 35, // Proxy-URI option number
COAP_MSG_PROXY_SCHEME = 39, // Proxy-Scheme option number
COAP_MSG_SIZE1 = 60, // Size1 option number
COAP_MSG_AUTH_TOKEN = 61, // auth token option number
COAP_MSG_NEED_RESP = 62, // CoAP need content response
} CoAPMsgOptionNum;
/* CoAP QCloud IoT Client structure */
typedef struct Client {
char is_authed; // CoAP Client auth or not
char conn_id[COAP_MAX_CONN_ID_LEN]; // conn id for a CoAP connection
unsigned int message_token; // msg token
char *auth_token; // auth token
int auth_token_len;
uint16_t next_msg_id; // COAP msg id
size_t send_buf_size; // size of write buffer
size_t read_buf_size; // size of read buffer
unsigned char send_buf[COAP_SENDMSG_MAX_BUFLEN];
unsigned char recv_buf[COAP_RECVMSG_MAX_BUFLEN];
void *lock_send_buf; // mutex/lock for write buffer
void *lock_list_wait_ack; // mutex/lock for wait ack list
Network network_stack; // MQTT network stack
uint32_t command_timeout_ms; // CoAP command timeout, unit:ms
List *message_list; // msg list
unsigned char max_retry_count; // Max retry count
CoAPEventHandler event_handle; // event callback
DeviceInfo device_info;
char host_addr[HOST_STR_LENGTH];
#ifdef AUTH_MODE_CERT
char cert_file_path[FILE_PATH_MAX_LEN]; // full path of device cert file
char key_file_path[FILE_PATH_MAX_LEN]; // full path of device key file
#else
unsigned char psk_decode[DECODE_PSK_LENGTH];
#endif
} CoAPClient;
/**
* @brief CoAP Option
*/
typedef struct coap_msg_op {
unsigned short option_num; // Option number
unsigned val_len; // Option length
char * val; // Pointer to a buffer containing the option value
struct coap_msg_op *next; // Pointer to the next option structure in the list
} CoAPMsgOption;
/**
* @brief CoAP Option list
*/
typedef struct {
CoAPMsgOption *first; // Pointer to the first option structure in the list
CoAPMsgOption *last; // Pointer to the last option structure in the list
} CoAPMsgOptionList;
/**
* @brief CoAP node state
*/
typedef enum {
COAP_NODE_STATE_NORMANL = 0,
COAP_NODE_STATE_INVALID,
} CoAPNodeState;
typedef struct {
CoAPNodeState node_state;
void * user_context;
unsigned short msg_id;
char acked;
unsigned char token_len;
unsigned char token[COAP_MSG_MAX_TOKEN_LEN];
unsigned char retrans_count;
Timer start_time;
unsigned char *message;
unsigned int msglen;
OnRespCallback handler;
} CoAPMsgSendInfo;
/**
* @brief COAP msg type
*/
typedef enum {
COAP_MSG_CON = 0x0, /**< msg need to wait for ACK */
COAP_MSG_NON = 0x1, /**< msg no need to wait for ACK */
COAP_MSG_ACK = 0x2, /**< msg ACK */
COAP_MSG_RST = 0x3 /**< msg Reset */
} CoAPMsgType;
/**
* @brief CoAP message structure
*/
typedef struct {
unsigned version; // CoAP protocol version
CoAPMsgType type; // msg type
unsigned code_class; // Code class
unsigned code_detail; // Code detail
unsigned short msg_id; // msg id
char * pay_load; // msg payload
size_t pay_load_len; // length of payload
char token[COAP_MSG_MAX_TOKEN_LEN]; // msg token
unsigned token_len; // length of token
CoAPMsgOptionList op_list; // Option list
OnRespCallback handler; // CoAP Response msg callback
void * user_context; // user context
} CoAPMessage;
#define DEFAULT_COAP_MESSAGE \
{ \
COAP_MSG_VER, COAP_MSG_CON, COAP_MSG_REQ, COAP_MSG_POST, 0, NULL, 0, {0}, 0, {0}, NULL, NULL \
}
/**
* @brief Init CoAPClient
*
* @param pClient reference to CoAP client
* @param pParams CoAP init parameters
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int qcloud_iot_coap_init(CoAPClient *pClient, CoAPInitParams *pParams);
/**
* @brief Generate next CoAPMessage msg Id
*
* @param pClient reference to CoAP client
* @return msg Id
*/
uint16_t get_next_coap_msg_id(CoAPClient *pClient);
/**
* @brief Generate next CoAPMessage msg token
*
* @param pClient reference to CoAP client
* @param tokenData msg token
* @return token length
*/
unsigned int get_coap_message_token(CoAPClient *client, char *tokenData);
/**
* @brief set message type
*
* @param message CoAP msg
* @param
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int coap_message_type_set(CoAPMessage *message, unsigned type);
/**
* @brief set message code
*
* @param message CoAP msg
* @param code_class CoAPMessageClass
* @param code_detail
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int coap_message_code_set(CoAPMessage *message, unsigned code_class, unsigned code_detail);
/**
* @brief set message Id
*
* @param message CoAP msg
* @param msg_id
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int coap_message_id_set(CoAPMessage *message, unsigned msg_id);
/**
* @brief set msg token
*
* @param message CoAP msg
* @param buf token string
* @param len token length
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int coap_message_token_set(CoAPMessage *message, char *buf, size_t len);
/**
* @brief set msg payload
*
* @param message CoAP msg
* @param buf msg payload buffer
* @param len length of payload
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int coap_message_payload_set(CoAPMessage *message, char *buf, size_t len);
/**
* @brief add msg option
*
* @param message CoAP msg
* @param num option number
* @param len option length
* @param val option string
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int coap_message_option_add(CoAPMessage *message, unsigned num, unsigned len, const char *val);
/**
* @brief set msg callback
*
* @param message CoAP msg
* @param callback
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int coap_message_callback_set(CoAPMessage *message, OnRespCallback callback);
/**
* @brief set user context
*
* @param message CoAP msg
* @param userContext
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int coap_message_context_set(CoAPMessage *message, void *userContext);
/**
* @brief create CoAPMsgOption from option number/len/val
*
* @param num CoAP option number
* @param len CoAP option string len
* @param val CoAP option string value
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
CoAPMsgOption *qcloud_iot_coap_option_init(unsigned num, unsigned len, const char *val);
/**
* @brief destroy CoAPMessage
*
* @param[in,out] message
*/
void coap_message_destroy(CoAPMessage *message);
/**
* @brief Read and handle CoAP msg
*
* @param pClient CoAPClient
* @param timeout_ms timeout value in millisecond
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int coap_message_cycle(CoAPClient *client, uint32_t timeout_ms);
/**
* @brief Send CoAP msg
*
* @param client CoAPClient
* @param message msg to send
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
ssize_t coap_message_send(CoAPClient *client, CoAPMessage *message);
/**
* @brief Read CoAP msg
*
* @param client CoAPClient
* @param timeout_ms timeout value in millisecond
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
ssize_t coap_message_recv(CoAPClient *client, uint32_t timeout_ms);
/**
* @brief do CoAPClient auth
*
* @param client CoAPClient
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int coap_client_auth(CoAPClient *client);
/**
* @brief Parse a message
*
* @param[in,out] message Pointer to a message structure
* @param[in] buf Pointer to a buffer containing the message
* @param[in] len Length of the buffer
*
* @returns Operation status
* @retval 0 Success
* @retval <0 Error
*/
ssize_t deserialize_coap_message(CoAPMessage *message, char *buf, size_t len);
/**
* @brief Format a message
*
* @param[in] message Pointer to a message structure
* @param[out] buf Pointer to a buffer to contain the formatted message
* @param[in] len Length of the buffer
*
* @returns Length of the formatted message or error code
* @retval >0 Length of the formatted message
* @retval <0 Error
*/
ssize_t serialize_coap_message(CoAPMessage *message, char *buf, size_t len);
void coap_msg_dump(CoAPMessage *msg);
#ifdef __cplusplus
}
#endif
#endif /* IOT_COAP_CLIENT_H_ */

View File

@@ -0,0 +1,32 @@
/*
* 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.
*
*/
#ifndef IOT_COAP_CLIENT_NET_H_
#define IOT_COAP_CLIENT_NET_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include "network_interface.h"
int qcloud_iot_coap_network_init(Network *pNetwork);
#ifdef __cplusplus
}
#endif
#endif /* IOT_COAP_CLIENT_NET_H_ */

View File

@@ -0,0 +1,97 @@
/*
* 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.
*
*/
#ifndef IOT_GATEWAY_COMMON_H_
#define IOT_GATEWAY_COMMON_H_
#include "qcloud_iot_export.h"
#define GATEWAY_PAYLOAD_BUFFER_LEN 1024
#define GATEWAY_RECEIVE_BUFFER_LEN 1024
#define GATEWAY_LOOP_MAX_COUNT 100
/* The format of operation of gateway topic */
#define GATEWAY_TOPIC_OPERATION_FMT "$gateway/operation/%s/%s"
/* The format of operation result of gateway topic */
#define GATEWAY_TOPIC_OPERATION_RESULT_FMT "$gateway/operation/result/%s/%s"
/* The format of gateway client id */
#define GATEWAY_CLIENT_ID_FMT "%s/%s"
/* The format of operation result of gateway topic */
#define GATEWAY_PAYLOAD_STATUS_FMT \
"{\"type\":\"%s\",\"payload\":{\"devices\":[{\"product_id\":\"%s\",\"device_name\":\"%s\"}]}}"
/* Subdevice seesion status */
typedef enum _SubdevSessionStatus {
/* Initial */
SUBDEV_SEESION_STATUS_INIT,
/* Online */
SUBDEV_SEESION_STATUS_ONLINE,
/* Offline */
SUBDEV_SEESION_STATUS_OFFLINE,
/* Maximum number of seesion status type */
SUBDEV_SEESION_STATUS_MAX
} SubdevSessionStatus;
/* The structure of subdevice session */
typedef struct _SubdevSession {
char product_id[MAX_SIZE_OF_PRODUCT_ID + 1];
char device_name[MAX_SIZE_OF_DEVICE_NAME + 1];
SubdevSessionStatus session_status;
struct _SubdevSession *next;
} SubdevSession;
/* The structure of common reply data */
typedef struct _ReplyData {
int32_t result;
char client_id[MAX_SIZE_OF_CLIENT_ID + 1];
} ReplyData;
/* The structure of gateway data */
typedef struct _GatewayData {
int32_t sync_status;
ReplyData online;
ReplyData offline;
} GatewayData;
/* The structure of gateway context */
typedef struct _Gateway {
void * mqtt;
SubdevSession * session_list;
GatewayData gateway_data;
MQTTEventHandler event_handle;
int is_construct;
char recv_buf[GATEWAY_RECEIVE_BUFFER_LEN];
} Gateway;
SubdevSession *subdev_add_session(Gateway *gateway, char *product_id, char *device_name);
SubdevSession *subdev_find_session(Gateway *gateway, char *product_id, char *device_name);
int subdev_remove_session(Gateway *gateway, char *product_id, char *device_name);
int gateway_subscribe_unsubscribe_topic(Gateway *gateway, char *topic_filter, SubscribeParams *params,
int is_subscribe);
int gateway_subscribe_unsubscribe_default(Gateway *gateway, GatewayParam *param);
int gateway_publish_sync(Gateway *gateway, char *topic, PublishParams *params, int32_t *result);
#endif /* IOT_GATEWAY_COMMON_H_ */

View File

@@ -0,0 +1,141 @@
/*
* 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.
*
*/
#ifndef __JSON_PARSER_H__
#define __JSON_PARSER_H__
#include "lite-utils.h"
/**
The descriptions of the json value node type
**/
enum JSONTYPE { JSNONE = -1, JSSTRING = 0, JSOBJECT, JSARRAY, JSNUMBER, JSBOOLEAN, JSNULL, JSTYPEMAX };
/**
The error codes produced by the JSON parsers
**/
enum JSON_PARSE_CODE { JSON_PARSE_ERR, JSON_PARSE_OK, JSON_PARSE_FINISH };
/**
The return codes produced by the JSON parsers
**/
enum JSON_PARSE_RESULT { JSON_RESULT_ERR = -1, JSON_RESULT_OK };
typedef int (*json_parse_cb)(char *p_cName, int iNameLen, char *p_cValue, int iValueLen, int iValueType,
void *p_Result);
/**
* @brief Parse the JSON string, and iterate through all keys and values,
* then handle the keys and values by callback function.
*
* @param[in] p_cJsonStr @n The JSON string
* @param[in] iStrLen @n The JSON string length
* @param[in] pfnCB @n Callback function
* @param[out] p_CBData @n User data
* @return JSON_RESULT_OK success, JSON_RESULT_ERR failed
* @see None.
* @note None.
**/
int json_parse_name_value(char *p_cJsonStr, int iStrLen, json_parse_cb pfnCB, void *p_CBData);
/**
* @brief Get the value by a specified key from a json string
*
* @param[in] p_cJsonStr @n the JSON string
* @param[in] iStrLen @n the JSON string length
* @param[in] p_cName @n the specified key string
* @param[out] p_iValueLen @n the value length
* @param[out] p_iValueType @n the value type
* @return A pointer to the value
* @see None.
* @note None.
**/
char *json_get_value_by_name(char *p_cJsonStr, int iStrLen, char *p_cName, int *p_iValueLen, int *p_iValueType);
/**
* @brief Get the JSON object point associate with a given type.
*
* @param[in] type @n The object type
* @param[in] str @n The JSON string
* @returns The json object point with the given field type.
* @see None.
* @note None.
*/
char *json_get_object(int type, char *str);
char *json_get_next_object(int type, char *str, char **key, int *key_len, char **val, int *val_len, int *val_type);
/**
* @brief retrieve each key&value pair from the json string
*
* @param[in] str @n Json string to revolve
* @param[in] pos @n cursor
* @param[out] key @n pointer to the next Key object
* @param[out] klen @n Key object length
* @param[out] val @n pointer to the next Value object
* @param[out] vlen @n Value object length
* @param[out] vtype @n Value object type(digital, string, object, array)
* @see None.
* @note None.
*/
#define json_object_for_each_kv(str, pos, key, klen, val, vlen, vtype) \
for (pos = json_get_object(JSOBJECT, str); \
pos != 0 && *pos != 0 && (pos = json_get_next_object(JSOBJECT, pos, &key, &klen, &val, &vlen, &vtype)) != 0;)
/**
* @brief retrieve each entry from the json array
*
* @param[in] str @n Json array to revolve
* @param[in] pos @n cursor
* @param[out] entry @n pointer to the next entry from the array
* @param[out] len @n entry length
* @param[out] type @n entry type(digital, string, object, array)
* @see None.
* @note None.
*/
#define json_array_for_each_entry(str, pos, entry, len, type) \
for (pos = json_get_object(JSARRAY, str); \
pos != 0 && *pos != 0 && (pos = json_get_next_object(JSARRAY, ++pos, 0, 0, &entry, &len, &type)) != 0;)
/**
* @brief backup the last character to register parameters,
* and set the end character with '\0'
*
* @param[in] json_str @n json string
* @param[in] str_len @n json string lenth
* @param[out] register @n used to backup the last character
* @see None.
* @note None.
*/
#define backup_json_str_last_char(json_str, str_len, register) \
{ \
register = *((char *)json_str + str_len); \
*((char *)json_str + str_len) = '\0'; \
}
/**
* @brief restore the last character from register parameters
*
* @param[in] json_str @n json string
* @param[in] str_len @n json string lenth
* @param[in] register @n used to restore the last character
* @see None.
* @note None.
*/
#define restore_json_str_last_char(json_str, str_len, register) \
{ \
*((char *)json_str + str_len) = register; \
}
#endif /* __JSON_PARSER_H__ */

View File

@@ -0,0 +1,103 @@
/*
* 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.
*
*/
#ifndef QCLOUD_IOT_LOG_UPLOAD_H_
#define QCLOUD_IOT_LOG_UPLOAD_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "qcloud_iot_export_log.h"
/**
* @brief init the log upload functions
*
* @param init_params
* @return QCLOUD_RET_SUCCESS when success
*/
int init_log_uploader(LogUploadInitParams *init_params);
/**
* @brief free log buffer and finish the log upload functions
*/
void fini_log_uploader(void);
/**
* @brief check if log uploader is init or not
*/
bool is_log_uploader_init(void);
/**
* @brief append one log item to upload buffer
*
* @param log_content
* @param log_size
* @return 0 when success, -1 when fail
*/
int append_to_upload_buffer(const char *log_content, size_t log_size);
/**
* @brief clear current upload buffer
*
* @return
*/
void clear_upload_buffer(void);
/**
* @brief do one upload to server
*
* @param force_upload if true, it will do upload right away, otherwise it will check log_level, buffer left and upload
* interval
* @return QCLOUD_RET_SUCCESS when success or no log to upload or timer is not expired
*/
int do_log_upload(bool force_upload);
/**
* @brief set the log mqtt client to get system time
*
* @param client
*/
void set_log_mqtt_client(void *client);
/**
* @brief set if only do log upload when communication error with IoT Hub
*
* @param value if true, only do log upload when communication error with IoT Hub
*/
void set_log_upload_in_comm_err(bool value);
/**
* @brief get current upload log_level from IoT Hub
*
* @param client
* @param log_level
* @return QCLOUD_RET_SUCCESS when success
*/
int qcloud_get_log_level(void *client, int *log_level);
/**
* @brief subscribe to upload log_level topic
*
* @param client
* @return QCLOUD_RET_SUCCESS when success
*/
int qcloud_log_topic_subscribe(void *client);
#ifdef __cplusplus
}
#endif
#endif // QCLOUD_IOT_LOG_UPLOAD_H_

View File

@@ -0,0 +1,563 @@
/*
* 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.
*
*/
#ifndef IOT_MQTT_CLIENT_H_
#define IOT_MQTT_CLIENT_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "mqtt_client_net.h"
#include "qcloud_iot_common.h"
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "utils_list.h"
#include "utils_param_check.h"
#include "utils_timer.h"
/* packet id, random from [1 - 65536] */
#define MAX_PACKET_ID (65535)
/* Max size of conn Id */
#define MAX_CONN_ID_LEN (6)
/* Max number of topic subscribed */
#define MAX_MESSAGE_HANDLERS (10)
/* Max number in repub list */
#define MAX_REPUB_NUM (20)
/* Minimal wait interval when reconnect */
#define MIN_RECONNECT_WAIT_INTERVAL (1000)
/* Minimal MQTT timeout value */
#define MIN_COMMAND_TIMEOUT (500)
/* Maxmal MQTT timeout value */
#define MAX_COMMAND_TIMEOUT (20000)
/* Max size of a topic name */
#define MAX_SIZE_OF_CLOUD_TOPIC ((MAX_SIZE_OF_DEVICE_NAME) + (MAX_SIZE_OF_PRODUCT_ID) + 64 + 6)
/* minimal TLS handshaking timeout value (unit: ms) */
#define QCLOUD_IOT_TLS_HANDSHAKE_TIMEOUT (5 * 1000)
#define MQTT_RMDUP_MSG_ENABLED
/**
* @brief MQTT Message Type
*/
typedef enum msgTypes {
RESERVED = 0, // Reserved
CONNECT = 1, // Client request to connect to Server
CONNACK = 2, // Connect Acknowledgment
PUBLISH = 3, // Publish message
PUBACK = 4, // Publish Acknowledgment
PUBREC = 5, // Publish Received
PUBREL = 6, // Publish Release
PUBCOMP = 7, // Publish Complete
SUBSCRIBE = 8, // Client Subscribe request
SUBACK = 9, // Subscribe Acknowledgment
UNSUBSCRIBE = 10, // Client Unsubscribe request
UNSUBACK = 11, // Unsubscribe Acknowledgment
PINGREQ = 12, // PING Request
PINGRESP = 13, // PING Response
DISCONNECT = 14 // Client is Disconnecting
} MessageTypes;
typedef enum { NOTCONNECTED = 0, CONNECTED = 1 } ConnStatus;
/**
* MQTT byte 1: fixed header
* bits |7654: Message Type | 3:DUP flag | 21:QoS level | 0:RETAIN |
*/
#define MQTT_HEADER_TYPE_SHIFT 0x04
#define MQTT_HEADER_TYPE_MASK 0xF0
#define MQTT_HEADER_DUP_SHIFT 0x03
#define MQTT_HEADER_DUP_MASK 0x08
#define MQTT_HEADER_QOS_SHIFT 0x01
#define MQTT_HEADER_QOS_MASK 0x06
#define MQTT_HEADER_RETAIN_MASK 0x01
/**
* @brief MQTT will options sturcture
*
*/
typedef struct {
char struct_id[4]; // The eyecatcher for this structure. must be MQTW
uint8_t struct_version; // struct version = 0
char * topic_name;
char * message;
uint8_t retained;
QoS qos;
} WillOptions;
/**
* default MQTT will options
*/
#define DEFAULT_WILL_OPTIONS \
{ \
{'M', 'Q', 'T', 'W'}, 0, NULL, NULL, 0, QOS0 \
}
/**
* @brief define MQTT connect parameters structure
*
*/
typedef struct {
char *client_id; // unique client id
char *username; // user name
char *password; // passwrod
char conn_id[MAX_CONN_ID_LEN];
char struct_id[4]; // The eyecatcher for this structure. must be MQTC.
uint8_t struct_version; // struct version = 0
uint8_t mqtt_version; // MQTT protocol version: 4 = 3.1.1
uint16_t keep_alive_interval; // keep alive interval, unit: second
uint8_t clean_session; // flag of clean session, refer to MQTT spec 3.1.2.4
uint8_t auto_connect_enable; // enable auto connection or not
#ifdef AUTH_WITH_NOTLS
char *device_secret; // PSK
int device_secret_len; // length of PSK
#endif
} MQTTConnectParams;
/**
* default value of MQTT connect parameters structure
*/
#ifdef AUTH_WITH_NOTLS
#define DEFAULT_MQTTCONNECT_PARAMS \
{ \
NULL, NULL, NULL, {0}, {'M', 'Q', 'T', 'C'}, 0, 4, 240, 1, 1, NULL, 0 \
}
#else
#define DEFAULT_MQTTCONNECT_PARAMS \
{ \
NULL, NULL, NULL, {0}, {'M', 'Q', 'T', 'C'}, 0, 4, 240, 1, 1 \
}
#endif
/**
* @brief data structure for topic subscription handle
*/
typedef struct SubTopicHandle {
const char * topic_filter; // topic name, wildcard filter is supported
OnMessageHandler message_handler; // callback when msg of this subscription arrives
OnSubEventHandler sub_event_handler; // callback when event of this subscription happens
void * handler_user_data; // user context for callback
QoS qos; // QoS
} SubTopicHandle;
/**
* @brief data structure for system time service
*/
typedef struct _sys_mqtt_state {
bool topic_sub_ok;
bool result_recv_ok;
long time;
} SysMQTTState;
/**
* @brief MQTT QCloud IoT Client structure
*/
typedef struct Client {
uint8_t is_connected;
uint8_t was_manually_disconnected;
uint8_t is_ping_outstanding; // 1 = ping request is sent while ping response not arrived yet
uint16_t next_packet_id; // MQTT random packet id
uint32_t command_timeout_ms; // MQTT command timeout, unit:ms
uint32_t current_reconnect_wait_interval; // unit:ms
uint32_t counter_network_disconnected; // number of disconnection
size_t write_buf_size; // size of MQTT write buffer
size_t read_buf_size; // size of MQTT read buffer
unsigned char write_buf[QCLOUD_IOT_MQTT_TX_BUF_LEN]; // MQTT write buffer
unsigned char read_buf[QCLOUD_IOT_MQTT_RX_BUF_LEN]; // MQTT read buffer
void *lock_generic; // mutex/lock for this client struture
void *lock_write_buf; // mutex/lock for write buffer
void *lock_list_pub; // mutex/lock for puback waiting list
void *lock_list_sub; // mutex/lock for suback waiting list
List *list_pub_wait_ack; // puback waiting list
List *list_sub_wait_ack; // suback waiting list
MQTTEventHandler event_handle; // callback for MQTT event
MQTTConnectParams options; // handle to connection parameters
Network network_stack; // MQTT network stack
Timer ping_timer; // MQTT ping timer
Timer reconnect_delay_timer; // MQTT reconnect delay timer
SubTopicHandle sub_handles[MAX_MESSAGE_HANDLERS]; // subscription handle array
DeviceInfo device_info;
char host_addr[HOST_STR_LENGTH];
#ifdef AUTH_MODE_CERT
char cert_file_path[FILE_PATH_MAX_LEN]; // full path of device cert file
char key_file_path[FILE_PATH_MAX_LEN]; // full path of device key file
#else
unsigned char psk_decode[DECODE_PSK_LENGTH];
#endif
#ifdef MQTT_RMDUP_MSG_ENABLED
#define MQTT_MAX_REPEAT_BUF_LEN 10
uint16_t repeat_packet_id_buf[MQTT_MAX_REPEAT_BUF_LEN];
unsigned int current_packet_id_cnt;
#endif
#ifdef SYSTEM_COMM
SysMQTTState sys_state;
#endif
#ifdef MULTITHREAD_ENABLED
bool thread_running;
int thread_exit_code;
#endif
} Qcloud_IoT_Client;
/**
* @brief MQTT protocol version
*/
typedef enum { MQTT_3_1_1 = 4 } MQTT_VERSION;
typedef enum MQTT_NODE_STATE {
MQTT_NODE_STATE_NORMANL = 0,
MQTT_NODE_STATE_INVALID,
} MQTTNodeState;
/* topic publish info */
typedef struct REPUBLISH_INFO {
Timer pub_start_time; /* timer for puback waiting */
MQTTNodeState node_state; /* node state in wait list */
uint16_t msg_id; /* packet id */
uint32_t len; /* msg length */
unsigned char *buf; /* msg buffer */
} QcloudIotPubInfo;
/* topic subscribe/unsubscribe info */
typedef struct SUBSCRIBE_INFO {
enum msgTypes type; /* type: sub or unsub */
uint16_t msg_id; /* packet id */
Timer sub_start_time; /* timer for suback waiting */
MQTTNodeState node_state; /* node state in wait list */
SubTopicHandle handler; /* handle of topic subscribed(unsubcribed) */
uint16_t len; /* msg length */
unsigned char *buf; /* msg buffer */
} QcloudIotSubInfo;
/**
* @brief Init MQTT client
*
* @param pClient handle to MQTT client
* @param pParams MQTT init parameters
*
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int qcloud_iot_mqtt_init(Qcloud_IoT_Client *pClient, MQTTInitParams *pParams);
/**
* @brief Release resources of MQTT client
*
* @param pClient handle to MQTT client
*
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int qcloud_iot_mqtt_fini(Qcloud_IoT_Client *pClient);
/**
* @brief Connect with MQTT server
*
* @param pClient handle to MQTT client
* @param pParams MQTT connect parameters
*
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int qcloud_iot_mqtt_connect(Qcloud_IoT_Client *pClient, MQTTConnectParams *pParams);
/**
* @brief Reconnect with MQTT server and re-subscribe topics if reconnected
*
* @param pClient handle to MQTT client
*
* @return QCLOUD_RET_MQTT_RECONNECTED for success, or err code for failure
*/
int qcloud_iot_mqtt_attempt_reconnect(Qcloud_IoT_Client *pClient);
/**
* @brief Disconnect with MQTT server
*
* @param pClient handle to MQTT client
*
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int qcloud_iot_mqtt_disconnect(Qcloud_IoT_Client *pClient);
/**
* @brief Publish MQTT message
*
* @param pClient handle to MQTT client
* @param topicName MQTT topic name
* @param pParams publish parameters
*
* @return packet id (>=0) when success, or err code (<0) for failure
*/
int qcloud_iot_mqtt_publish(Qcloud_IoT_Client *pClient, char *topicName, PublishParams *pParams);
/**
* @brief Subscribe MQTT topic
*
* @param pClient handle to MQTT client
* @param topicFilter MQTT topic filter
* @param pParams subscribe parameters
*
* @return packet id (>=0) when success, or err code (<0) for failure
*/
int qcloud_iot_mqtt_subscribe(Qcloud_IoT_Client *pClient, char *topicFilter, SubscribeParams *pParams);
/**
* @brief Re-subscribe MQTT topics
*
* @param pClient handle to MQTT client
*
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int qcloud_iot_mqtt_resubscribe(Qcloud_IoT_Client *pClient);
/**
* @brief Unsubscribe MQTT topic
*
* @param pClient handle to MQTT client
* @param topicFilter MQTT topic filter
*
* @return packet id (>=0) when success, or err code (<0) for failure
*/
int qcloud_iot_mqtt_unsubscribe(Qcloud_IoT_Client *pClient, char *topicFilter);
/**
* @brief check if MQTT topic has been subscribed or not
*
* @param pClient handle to MQTT client
* @param topicFilter MQTT topic filter
*
* @return true when successfully subscribed, or false if not yet
*/
bool qcloud_iot_mqtt_is_sub_ready(Qcloud_IoT_Client *pClient, char *topicFilter);
/**
* @brief Check connection and keep alive state, read/handle MQTT message in synchronized way
*
* @param pClient handle to MQTT client
* @param timeout_ms timeout value (unit: ms) for this operation
*
* @return QCLOUD_RET_SUCCESS when success, QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT when try reconnecing, or err code for
* failure
*/
int qcloud_iot_mqtt_yield(Qcloud_IoT_Client *pClient, uint32_t timeout_ms);
// workaround wrapper for qcloud_iot_mqtt_yield for multi-thread mode
int qcloud_iot_mqtt_yield_mt(Qcloud_IoT_Client *mqtt_client, uint32_t timeout_ms);
/**
* @brief Check if auto reconnect is enabled or not
*
* @param pClient handle to MQTT client
* @return true if auto reconnect is enabled
*/
bool qcloud_iot_mqtt_is_autoreconnect_enabled(Qcloud_IoT_Client *pClient);
/**
* @brief Set to enable auto reconnect or not
*
* @param pClient handle to MQTT client
* @param value enable or disable
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int qcloud_iot_mqtt_set_autoreconnect(Qcloud_IoT_Client *pClient, bool value);
/**
* @brief Get the count of disconnection
*
* @param pClient handle to MQTT client
* @return count of disconnection
*/
int qcloud_iot_mqtt_get_network_disconnected_count(Qcloud_IoT_Client *pClient);
/**
* @brief Set the count of disconnection
*
* @param pClient handle to MQTT client
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int qcloud_iot_mqtt_reset_network_disconnected_count(Qcloud_IoT_Client *pClient);
/**
* @brief Get next packet id
*
* @param pClient
* @return
*/
uint16_t get_next_packet_id(Qcloud_IoT_Client *pClient);
/**
* @brief Get next conn id
*
* @param options
* @return
*/
void get_next_conn_id(char *conn_id);
/**
* @brief Init packet header
* @param header
* @param message_type
* @param qos
* @param dup
* @param retained
* @return
*/
int mqtt_init_packet_header(unsigned char *header, MessageTypes message_type, QoS qos, uint8_t dup, uint8_t retained);
/**
* @brief Read and handle one MQTT msg/ack from server
*
* @param pClient
* @param timer
* @param packet_type
* @param qos
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int cycle_for_read(Qcloud_IoT_Client *pClient, Timer *timer, uint8_t *packet_type, QoS qos);
/**
* @brief Send the packet in buffer
*
* @param pClient
* @param length
* @param timer
* @return
*/
int send_mqtt_packet(Qcloud_IoT_Client *pClient, size_t length, Timer *timer);
/**
* @brief wait for a specific packet with timeout
*
* only used in single-threaded mode where one command at a time is in process
*
* @param pClient MQTT Client
* @param packet_type MQTT packet type
* @param timer timer with timeout
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int wait_for_read(Qcloud_IoT_Client *pClient, uint8_t packet_type, Timer *timer, QoS qos);
/**
* @brief Set MQTT connection state
*
* @param pClient MQTT Client
* @param connected 0: disconnected 1: connected
* @return
*/
void set_client_conn_state(Qcloud_IoT_Client *pClient, uint8_t connected);
/**
* @brief Get MQTT connection state
*
* @param pClient MQTT Client
* @return 0: disconnected 1: connected
*/
uint8_t get_client_conn_state(Qcloud_IoT_Client *pClient);
/**
* @brief Check Publish ACK waiting list, remove the node if PUBACK received or timeout
*
* @param pClient MQTT client
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int qcloud_iot_mqtt_pub_info_proc(Qcloud_IoT_Client *pClient);
/**
* @brief Check Subscribe ACK waiting list, remove the node if SUBACK received or timeout
*
* @param pClient MQTT client
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int qcloud_iot_mqtt_sub_info_proc(Qcloud_IoT_Client *pClient);
int push_sub_info_to(Qcloud_IoT_Client *c, int len, unsigned short msgId, MessageTypes type, SubTopicHandle *handler,
ListNode **node);
int serialize_pub_ack_packet(unsigned char *buf, size_t buf_len, MessageTypes packet_type, uint8_t dup,
uint16_t packet_id, uint32_t *serialized_len);
int serialize_packet_with_zero_payload(unsigned char *buf, size_t buf_len, MessageTypes packetType,
uint32_t *serialized_len);
int deserialize_publish_packet(unsigned char *dup, QoS *qos, uint8_t *retained, uint16_t *packet_id, char **topicName,
uint16_t *topicNameLen, unsigned char **payload, size_t *payload_len, unsigned char *buf,
size_t buf_len);
int deserialize_suback_packet(uint16_t *packet_id, uint32_t max_count, uint32_t *count, QoS *grantedQoSs,
unsigned char *buf, size_t buf_len);
int deserialize_unsuback_packet(uint16_t *packet_id, unsigned char *buf, size_t buf_len);
int deserialize_ack_packet(uint8_t *packet_type, uint8_t *dup, uint16_t *packet_id, unsigned char *buf, size_t buf_len);
#ifdef MQTT_RMDUP_MSG_ENABLED
void reset_repeat_packet_id_buffer(Qcloud_IoT_Client *pClient);
#endif
size_t get_mqtt_packet_len(size_t rem_len);
size_t mqtt_write_packet_rem_len(unsigned char *buf, uint32_t length);
int mqtt_read_packet_rem_len_form_buf(unsigned char *buf, uint32_t *value, uint32_t *readBytesLen);
uint16_t mqtt_read_uint16_t(unsigned char **pptr);
unsigned char mqtt_read_char(unsigned char **pptr);
void mqtt_write_char(unsigned char **pptr, unsigned char c);
void mqtt_write_uint_16(unsigned char **pptr, uint16_t anInt);
void mqtt_write_utf8_string(unsigned char **pptr, const char *string);
#ifdef __cplusplus
}
#endif
#endif // IOT_MQTT_CLIENT_H_

View File

@@ -0,0 +1,38 @@
/*
* 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.
*
*/
#ifndef IOT_MQTT_CLIENT_NET_H_
#define IOT_MQTT_CLIENT_NET_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "network_interface.h"
/**
* @brief Init network stack
*
* @param pNetwork
* @param pConnectParams
* @return 0 for success
*/
int qcloud_iot_mqtt_network_init(Network *pNetwork);
#ifdef __cplusplus
}
#endif
#endif // IOT_MQTT_CLIENT_NET_H_

View File

@@ -0,0 +1,127 @@
/*
* 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.
*
*/
#ifndef _NETWORK_INTERFACE_H_
#define _NETWORK_INTERFACE_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include <stdint.h>
#include "qcloud_iot_import.h"
/*
* Type of network interface
*/
typedef enum { NETWORK_TCP = 0, NETWORK_UDP = 1, NETWORK_TLS = 2, NETWORK_DTLS = 3 } NETWORK_TYPE;
/**
* @brief Define structure for network stack
*/
typedef struct Network Network;
/**
* @brief Define structure for network stack
*
* Network init/connect/read/write/disconnect/state
*/
struct Network {
int (*init)(Network *);
int (*connect)(Network *);
int (*read)(Network *, unsigned char *, size_t, uint32_t, size_t *);
int (*write)(Network *, unsigned char *, size_t, uint32_t, size_t *);
void (*disconnect)(Network *);
int (*is_connected)(Network *);
// connetion handle:
// for non-AT: 0 = not connected, non-zero = connected
// for AT: 0 = valid connection, MAX_UNSINGED_INT = invalid
uintptr_t handle;
#ifndef AUTH_WITH_NOTLS
SSLConnectParams ssl_connect_params;
#endif
const char * host; // server address
int port; // server port
NETWORK_TYPE type;
};
/*
* Init network stack
*/
int network_init(Network *pNetwork);
/* return the handle */
int is_network_connected(Network *pNetwork);
/* network stack API */
#ifdef AT_TCP_ENABLED
#define AT_NO_CONNECTED_FD 0xffffffff
int network_at_tcp_read(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *read_len);
int network_at_tcp_write(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms,
size_t *written_len);
void network_at_tcp_disconnect(Network *pNetwork);
int network_at_tcp_connect(Network *pNetwork);
int network_at_tcp_init(Network *pNetwork);
#else
int network_tcp_read(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *read_len);
int network_tcp_write(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *written_len);
void network_tcp_disconnect(Network *pNetwork);
int network_tcp_connect(Network *pNetwork);
int network_tcp_init(Network *pNetwork);
#endif
#ifndef AUTH_WITH_NOTLS
int network_tls_read(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *read_len);
int network_tls_write(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *written_len);
void network_tls_disconnect(Network *pNetwork);
int network_tls_connect(Network *pNetwork);
int network_tls_init(Network *pNetwork);
#endif
#ifdef COAP_COMM_ENABLED
#ifdef AUTH_WITH_NOTLS
int network_udp_read(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *read_len);
int network_udp_write(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *written_len);
void network_udp_disconnect(Network *pNetwork);
int network_udp_connect(Network *pNetwork);
int network_udp_init(Network *pNetwork);
#else
int network_dtls_read(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *read_len);
int network_dtls_write(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms,
size_t *written_len);
void network_dtls_disconnect(Network *pNetwork);
int network_dtls_connect(Network *pNetwork);
int network_dtls_init(Network *pNetwork);
#endif
#endif
#ifdef __cplusplus
}
#endif
#endif /* _NETWORK_INTERFACE_H_ */

View File

@@ -0,0 +1,57 @@
/*
* 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.
*
*/
#ifndef IOT_OTA_CLIENT_H_
#define IOT_OTA_CLIENT_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
/* Specify the maximum characters of version */
#define OTA_MAX_TOPIC_LEN (64)
#define TYPE_FIELD "type"
#define MD5_FIELD "md5sum"
#define VERSION_FIELD "version"
#define URL_FIELD "url"
#define FILESIZE_FIELD "file_size"
#define RESULT_FIELD "result_code"
#define REPORT_VERSION_RSP "report_version_rsp"
#define UPDATE_FIRMWARE "update_firmware"
enum { MQTT_CHANNEL, COAP_CHANNEL };
typedef void (*OnOTAMessageCallback)(void *pcontext, const char *msg, uint32_t msgLen);
void *qcloud_osc_init(const char *productId, const char *deviceName, void *channel, OnOTAMessageCallback callback,
void *context);
int qcloud_osc_deinit(void *handle);
int qcloud_osc_report_progress(void *handle, const char *msg);
int qcloud_osc_report_version(void *handle, const char *msg);
int qcloud_osc_report_upgrade_result(void *handle, const char *msg);
#ifdef __cplusplus
}
#endif
#endif /* IOT_OTA_CLIENT_H_ */

View File

@@ -0,0 +1,37 @@
/*
* 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.
*
*/
#ifndef IOT_OTA_FETCH_H_
#define IOT_OTA_FETCH_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
void *ofc_Init(const char *url, uint32_t offset, uint32_t size);
int32_t qcloud_ofc_connect(void *handle);
int32_t qcloud_ofc_fetch(void *handle, char *buf, uint32_t buf_len, uint32_t timeout_s);
int qcloud_ofc_deinit(void *handle);
#ifdef __cplusplus
}
#endif
#endif /* IOT_OTA_FETCH_H_ */

View File

@@ -0,0 +1,82 @@
/*
* 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.
*
*/
#ifndef IOT_OTA_LIB_H_
#define IOT_OTA_LIB_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <sys/types.h>
#include "qcloud_iot_export_ota.h"
void *qcloud_otalib_md5_init(void);
void qcloud_otalib_md5_update(void *md5, const char *buf, size_t buf_len);
void qcloud_otalib_md5_finalize(void *md5, char *output_str);
void qcloud_otalib_md5_deinit(void *md5);
int qcloud_otalib_get_firmware_type(const char *json, char **type);
int qcloud_otalib_get_report_version_result(const char *json);
/**
* @brief Parse firmware info from JSON string
*
* @param json source JSON string
* @param type parsed type
* @param url parsed url
* @param version parsed version
* @param md5 parsed MD5
* @param fileSize parsed file size
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int qcloud_otalib_get_params(const char *json, char **type, char **url, char **version, char *md5, uint32_t *fileSize);
/**
* @brief Generate firmware info from id and version
*
* @param buf output buffer
* @param bufLen size of buffer
* @param id firmware id
* @param version firmware version
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int qcloud_otalib_gen_info_msg(char *buf, size_t bufLen, uint32_t id, const char *version);
/**
* @brief Generate firmware report
*
* @param buf output buffer
* @param bufLen size of buffer
* @param id firmware id
* @param version firmware version
* @param progress download progress
* @param reportType report type
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int qcloud_otalib_gen_report_msg(char *buf, size_t bufLen, uint32_t id, const char *version, int progress,
IOT_OTAReportType reportType);
#ifdef __cplusplus
}
#endif
#endif /* IOT_OTA_LIB_H_ */

View File

@@ -0,0 +1,31 @@
/*
* 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.
*
*/
#ifndef IOT_CA_H_
#define IOT_CA_H_
#ifdef __cplusplus
extern "C" {
#endif
const char *iot_ca_get(void);
const char *iot_https_ca_get(void);
#ifdef __cplusplus
}
#endif
#endif /* IOT_CA_H_ */

View File

@@ -0,0 +1,47 @@
/*
* 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.
*
*/
#ifndef QCLOUD_IOT_COMMON_H_
#define QCLOUD_IOT_COMMON_H_
/* IoT C-SDK APPID */
#define QCLOUD_IOT_DEVICE_SDK_APPID "21010406"
/* MQTT server domain */
#define QCLOUD_IOT_MQTT_DIRECT_DOMAIN "iotcloud.tencentdevices.com"
#define MQTT_SERVER_PORT_TLS 8883
#define MQTT_SERVER_PORT_NOTLS 1883
/* CoAP server domain */
#define QCLOUD_IOT_COAP_DEIRECT_DOMAIN "iotcloud.tencentdevices.com"
#define COAP_SERVER_PORT 5684
/* server domain for dynamic registering device */
#define DYN_REG_SERVER_URL "gateway.tencentdevices.com"
#define DYN_REG_SERVER_PORT 80
#define DYN_REG_SERVER_PORT_TLS 443
/* URL for doing log upload */
#define LOG_UPLOAD_SERVER_URL "http://devicelog.iot.cloud.tencent.com/cgi-bin/report-log"
#define LOG_UPLOAD_SERVER_DOMAIN "devicelog.iot.cloud.tencent.com"
#define LOG_UPLOAD_SERVER_PORT 80
/* Max size of a host name */
#define HOST_STR_LENGTH 64
/* Max size of base64 encoded PSK = 64, after decode: 64/4*3 = 48*/
#define DECODE_PSK_LENGTH 48
#endif /* QCLOUD_IOT_COMMON_H_ */

View File

@@ -0,0 +1,32 @@
/*
* 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.
*
*/
#ifndef IOT_DEVICE_H_
#define IOT_DEVICE_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
int iot_device_info_set(DeviceInfo *device_info, const char *product_id, const char *device_name);
#ifdef __cplusplus
}
#endif
#endif /* IOT_DEVICE_H_ */

View File

@@ -0,0 +1,121 @@
/*
* 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.
*
*/
#ifndef IOT_SHADOW_CLIENT_H_
#define IOT_SHADOW_CLIENT_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include "mqtt_client.h"
#include "qcloud_iot_device.h"
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "shadow_client_json.h"
#include "utils_param_check.h"
/* Max number of requests in appending state */
#define MAX_APPENDING_REQUEST_AT_ANY_GIVEN_TIME (10)
/* Max size of clientToken */
#define MAX_SIZE_OF_CLIENT_TOKEN (MAX_SIZE_OF_CLIENT_ID + 10)
/* Max size of JSON string which only contain clientToken field */
#define MAX_SIZE_OF_JSON_WITH_CLIENT_TOKEN (MAX_SIZE_OF_CLIENT_TOKEN + 20)
/* Size of buffer to receive JSON document from server */
#define CLOUD_IOT_JSON_RX_BUF_LEN (QCLOUD_IOT_MQTT_RX_BUF_LEN + 1)
/**
* @brief define type of request parameters
*/
typedef struct _RequestParam {
Method method; // method type: GET, UPDATE, DELETE
uint32_t timeout_sec; // request timeout in second
OnRequestCallback request_callback; // request callback
void *user_context; // user context for callback
} RequestParams;
#define DEFAULT_REQUEST_PARAMS {GET, 4, NULL, NULL};
/**
* @brief for property and it's callback
*/
typedef struct {
void *property;
OnPropRegCallback callback;
} PropertyHandler;
typedef struct _ShadowInnerData {
uint32_t token_num;
int32_t sync_status;
List * request_list;
List * property_handle_list;
char * result_topic;
} ShadowInnerData;
typedef struct _Shadow {
void * mqtt;
void * mutex;
eShadowType shadow_type;
MQTTEventHandler event_handle;
ShadowInnerData inner_data;
char shadow_recv_buf[CLOUD_IOT_JSON_RX_BUF_LEN];
} Qcloud_IoT_Shadow;
int qcloud_iot_shadow_init(Qcloud_IoT_Shadow *pShadow);
void qcloud_iot_shadow_reset(void *pClient);
/**
* @brief handle the expired requests in list
*
* @param pShadow shadow client
*/
void handle_expired_request(Qcloud_IoT_Shadow *pShadow);
/**
* @brief Entry of all shadow JSON request
*
* @param pShadow shadow client
* @param pParams request param
* @param pJsonDoc JSON buffer
* @param sizeOfBuffer size of buffer
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int do_shadow_request(Qcloud_IoT_Shadow *pShadow, RequestParams *pParams, char *pJsonDoc, size_t sizeOfBuffer);
/**
* @brief subscribe shadow topic $shadow/operation/result
*
* @param pShadow shadow client
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int subscribe_operation_result_to_cloud(Qcloud_IoT_Shadow *pShadow);
#ifdef __cplusplus
}
#endif
#endif /* IOT_SHADOW_CLIENT_H_ */

View File

@@ -0,0 +1,58 @@
/*
* 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.
*
*/
#ifndef IOT_SHADOW_CLIENT_COMMON_H_
#define IOT_SHADOW_CLIENT_COMMON_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "shadow_client.h"
/**
* @brief register a device property
*
* @param pShadow shadow client
* @param pProperty device property
* @param callback callback when property changes
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int shadow_common_register_property_on_delta(Qcloud_IoT_Shadow *pShadow, DeviceProperty *pProperty,
OnPropRegCallback callback);
/**
* @brief remove a device property
*
* @param pShadow shadow client
* @param pProperty device property
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int shadow_common_remove_property(Qcloud_IoT_Shadow *pshadow, DeviceProperty *pProperty);
/**
* @brief check if a device property exists
*
* @param pShadow shadow client
* @param pProperty device property
* @return 0 = not existed
*/
int shadow_common_check_property_existence(Qcloud_IoT_Shadow *pshadow, DeviceProperty *pProperty);
#ifdef __cplusplus
}
#endif
#endif // IOT_SHADOW_CLIENT_COMMON_H_

View File

@@ -0,0 +1,186 @@
/*
* 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.
*
*/
#ifndef IOT_SHADOW_CLIENT_JSON_H_
#define IOT_SHADOW_CLIENT_JSON_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#define VERSION_FIELD "version"
#define TYPE_FIELD "type"
#define CLIENT_TOKEN_FIELD "clientToken"
#define RESULT_FIELD "result"
#define OPERATION_DELTA "delta"
#define OPERATION_GET "get"
#define OPERATION_UPDATE "update"
#define PAYLOAD_STATE "payload.state"
#define PAYLOAD_VERSION "payload.version"
#define PAYLOAD_STATE_DELTA "payload.state.delta"
#define REPLY_CODE "code"
#define REPLY_STATUS "status"
/**
* add a JSON node to JSON string
*
* @param jsonBuffer JSON string buffer
* @param sizeOfBuffer size of buffer
* @param pKey key of JSON node
* @param pData value of JSON node
* @param type value type of JSON node
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int put_json_node(char *jsonBuffer, size_t sizeOfBuffer, const char *pKey, void *pData, JsonDataType type);
/**
* add a event JSON node to JSON string
*
* @param jsonBuffer JSON string buffer
* @param sizeOfBuffer size of buffer
* @param pKey key of JSON node
* @param pData value of JSON node
* @param type value type of JSON node
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int event_put_json_node(char *jsonBuffer, size_t sizeOfBuffer, const char *pKey, void *pData, JsonDataType type);
/**
* @brief generate a ClientToken
*
* @param pStrBuffer string buffer
* @param sizeOfBuffer size of buffer
* @param tokenNumber shadow token number, increment every time
* @param product_id device product ID
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int generate_client_token(char *pStrBuffer, size_t sizeOfBuffer, uint32_t *tokenNumber, char *product_id);
/**
* @brief generate an empty JSON with only clientToken
*
* @param tokenNumber shadow token number, increment every time
* @param pJsonBuffer JSON string buffer
* @param product_id device product ID
*/
void build_empty_json(uint32_t *tokenNumber, char *pJsonBuffer, char *product_id);
/**
* @brief parse field of clientToken from JSON string
*
* @param pJsonDoc source JSON string
* @param pClientToken pointer to field of ClientToken
* @return true for success
*/
bool parse_client_token(char *pJsonDoc, char **pClientToken);
/**
* @brief parse field of status from JSON string
*
* @param pJsonDoc source JSON string
* @param pStatus pointer to field of status
* @return true for success
*/
bool parse_status_return(char *pJsonDoc, char **pStatus);
/**
* @brief parse field of code from JSON string
*
* @param pJsonDoc source JSON string
* @param pCode pointer to field of Code
* @return true for success
*/
bool parse_code_return(char *pJsonDoc, int32_t *pCode);
/**
* @brief parse field of version from JSON string
*
* @param pJsonDoc source JSON string
* @param pVersionNumber pointer to version
* @return true for success
*/
bool parse_version_num(char *pJsonDoc, uint32_t *pVersionNumber);
/**
* @brief parse field of state from JSON string
*
* @param pJsonDoc source JSON string
* @param pState pointer to field of state
* @return true for success
*/
bool parse_shadow_state(char *pJsonDoc, char **pState);
/**
* @brief parse field of type from JSON string
*
* @param pJsonDoc source JSON string
* @param pType pointer to field of tyde
* @return true for success
*/
bool parse_shadow_operation_type(char *pJsonDoc, char **pType);
/**
* @brief parse field of result from JSON string
*
* @param pJsonDoc source JSON string
* @param pResultCode pointer to result code
* @return true for success
*/
bool parse_shadow_operation_result_code(char *pJsonDoc, int16_t *pResultCode);
/**
* @brief parse field of delta from JSON string
*
* @param pJsonDoc source JSON string
* @param pDelta pointer to field of delta
* @return true for success
*/
bool parse_shadow_operation_delta(char *pJsonDoc, char **pDelta);
/**
* @brief parse field of get from JSON string
*
* @param pJsonDoc source JSON string
* @param pDelta pointer to field of delta
* @return true for success
*/
bool parse_shadow_operation_get(char *pJsonDoc, char **pDelta);
/**
* @brief update value in JSON if key is matched, not for OBJECT type
*
* @param pJsonDoc JSON string
* @param pProperty device property
* @return true for success
*/
bool update_value_if_key_match(char *pJsonDoc, DeviceProperty *pProperty);
#ifdef __cplusplus
}
#endif
#endif // IOT_SHADOW_CLIENT_JSON_H_

View File

@@ -0,0 +1,293 @@
/*
* 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.
*
*/
#ifndef QCLOUD_IOT_UTILS_AES_H_
#define QCLOUD_IOT_UTILS_AES_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include <stdint.h>
//========Platform================================//
#define UTILS_AES_C
#define UTILS_CIPHER_MODE_CBC
//#define UTILS_SELF_TEST
#define UTILS_ERR_PLATFORM_HW_ACCEL_FAILED -0x0070 /**< Hardware accelerator failed */
#define UTILS_ERR_PLATFORM_FEATURE_UNSUPPORTED -0x0072 /**< The requested feature is not supported by the platform */
/* Internal macros meant to be called only from within the library. */
#define UTILS_INTERNAL_VALIDATE_RET(cond, ret) \
do { \
} while (0)
#define UTILS_INTERNAL_VALIDATE(cond) \
do { \
} while (0)
//==============================================//
/* padlock.c and aesni.c rely on these values! */
#define UTILS_AES_ENCRYPT 1 /**< AES encryption. */
#define UTILS_AES_DECRYPT 0 /**< AES decryption. */
#define UTILS_AES_BLOCK_LEN 16
#define AES_KEY_BITS_128 128
#define AES_KEY_BITS_192 192
#define AES_KEY_BITS_256 256
/* Error codes in range 0x0020-0x0022 */
#define UTILS_ERR_AES_INVALID_KEY_LENGTH -0x0020 /**< Invalid key length. */
#define UTILS_ERR_AES_INVALID_INPUT_LENGTH -0x0022 /**< Invalid data input length. */
/* Error codes in range 0x0021-0x0025 */
#define UTILS_ERR_AES_BAD_INPUT_DATA -0x0021 /**< Invalid input data. */
/* UTILS_ERR_AES_FEATURE_UNAVAILABLE is deprecated and should not be used. */
#define UTILS_ERR_AES_FEATURE_UNAVAILABLE \
-0x0023 /**< Feature not available. For example, an unsupported AES key size. */
/* UTILS_ERR_AES_HW_ACCEL_FAILED is deprecated and should not be used. */
#define UTILS_ERR_AES_HW_ACCEL_FAILED -0x0025 /**< AES hardware accelerator failed. */
#if !defined(UTILS_AES_ALT)
// Regular implementation
//
/**
* \brief The AES context-type definition.
*/
typedef struct utils_aes_context {
int nr; /*!< The number of rounds. */
uint32_t *rk; /*!< AES round keys. */
uint32_t buf[68]; /*!< Unaligned data buffer. This buffer can
hold 32 extra Bytes, which can be used for
one of the following purposes:
<ul><li>Alignment if VIA padlock is
used.</li>
<li>Simplifying key expansion in the 256-bit
case by generating an extra round key.
</li></ul> */
} utils_aes_context;
#else /* UTILS_AES_ALT */
#include "aes_alt.h"
#endif /* UTILS_AES_ALT */
/**
* \brief This function initializes the specified AES context.
*
* It must be the first API called before using
* the context.
*
* \param ctx The AES context to initialize. This must not be \c NULL.
*/
void utils_aes_init(utils_aes_context *ctx);
/**
* \brief This function releases and clears the specified AES context.
*
* \param ctx The AES context to clear.
* If this is \c NULL, this function does nothing.
* Otherwise, the context must have been at least initialized.
*/
void utils_aes_free(utils_aes_context *ctx);
/**
* \brief This function sets the encryption key.
*
* \param ctx The AES context to which the key should be bound.
* It must be initialized.
* \param key The encryption key.
* This must be a readable buffer of size \p keybits bits.
* \param keybits The size of data passed in bits. Valid options are:
* <ul><li>128 bits</li>
* <li>192 bits</li>
* <li>256 bits</li></ul>
*
* \return \c 0 on success.
* \return #UTILS_ERR_AES_INVALID_KEY_LENGTH on failure.
*/
int utils_aes_setkey_enc(utils_aes_context *ctx, const unsigned char *key, unsigned int keybits);
/**
* \brief This function sets the decryption key.
*
* \param ctx The AES context to which the key should be bound.
* It must be initialized.
* \param key The decryption key.
* This must be a readable buffer of size \p keybits bits.
* \param keybits The size of data passed. Valid options are:
* <ul><li>128 bits</li>
* <li>192 bits</li>
* <li>256 bits</li></ul>
*
* \return \c 0 on success.
* \return #UTILS_ERR_AES_INVALID_KEY_LENGTH on failure.
*/
int utils_aes_setkey_dec(utils_aes_context *ctx, const unsigned char *key, unsigned int keybits);
/**
* \brief This function performs an AES single-block encryption or
* decryption operation.
*
* It performs the operation defined in the \p mode parameter
* (encrypt or decrypt), on the input data buffer defined in
* the \p input parameter.
*
* utils_aes_init(), and either utils_aes_setkey_enc() or
* utils_aes_setkey_dec() must be called before the first
* call to this API with the same context.
*
* \param ctx The AES context to use for encryption or decryption.
* It must be initialized and bound to a key.
* \param mode The AES operation: #UTILS_AES_ENCRYPT or
* #UTILS_AES_DECRYPT.
* \param input The buffer holding the input data.
* It must be readable and at least \c 16 Bytes long.
* \param output The buffer where the output data will be written.
* It must be writeable and at least \c 16 Bytes long.
* \return \c 0 on success.
*/
int utils_aes_crypt_ecb(utils_aes_context *ctx, int mode, const unsigned char input[16], unsigned char output[16]);
#if defined(UTILS_CIPHER_MODE_CBC)
/**
* \brief This function performs an AES-CBC encryption or decryption operation
* on full blocks.
*
* It performs the operation defined in the \p mode
* parameter (encrypt/decrypt), on the input data buffer defined in
* the \p input parameter.
*
* It can be called as many times as needed, until all the input
* data is processed. utils_aes_init(), and either
* utils_aes_setkey_enc() or utils_aes_setkey_dec() must be called
* before the first call to this API with the same context.
*
* \note This function operates on full blocks, that is, the input size
* must be a multiple of the AES block size of \c 16 Bytes.
*
* \note Upon exit, the content of the IV is updated so that you can
* call the same function again on the next
* block(s) of data and get the same result as if it was
* encrypted in one call. This allows a "streaming" usage.
* If you need to retain the contents of the IV, you should
* either save it manually or use the cipher module instead.
*
*
* \param ctx The AES context to use for encryption or decryption.
* It must be initialized and bound to a key.
* \param mode The AES operation: #UTILS_AES_ENCRYPT or
* #UTILS_AES_DECRYPT.
* \param length The length of the input data in Bytes. This must be a
* multiple of the block size (\c 16 Bytes).
* \param iv Initialization vector (updated after use).
* It must be a readable and writeable buffer of \c 16 Bytes.
* \param input The buffer holding the input data.
* It must be readable and of size \p length Bytes.
* \param output The buffer holding the output data.
* It must be writeable and of size \p length Bytes.
*
* \return \c 0 on success.
* \return #UTILS_ERR_AES_INVALID_INPUT_LENGTH
* on failure.
*/
int utils_aes_crypt_cbc(utils_aes_context *ctx, int mode, size_t length, unsigned char iv[16],
const unsigned char *input, unsigned char *output);
#endif /* UTILS_CIPHER_MODE_CBC */
/**
* \brief Internal AES block encryption function. This is only
* exposed to allow overriding it using
* \c UTILS_AES_ENCRYPT_ALT.
*
* \param ctx The AES context to use for encryption.
* \param input The plaintext block.
* \param output The output (ciphertext) block.
*
* \return \c 0 on success.
*/
int utils_internal_aes_encrypt(utils_aes_context *ctx, const unsigned char input[16], unsigned char output[16]);
/**
* \brief Internal AES block decryption function. This is only
* exposed to allow overriding it using see
* \c UTILS_AES_DECRYPT_ALT.
*
* \param ctx The AES context to use for decryption.
* \param input The ciphertext block.
* \param output The output (plaintext) block.
*
* \return \c 0 on success.
*/
int utils_internal_aes_decrypt(utils_aes_context *ctx, const unsigned char input[16], unsigned char output[16]);
#if !defined(UTILS_DEPRECATED_REMOVED)
#if defined(UTILS_DEPRECATED_WARNING)
#define UTILS_DEPRECATED __attribute__((deprecated))
#else
#define UTILS_DEPRECATED
#endif
/**
* \brief Deprecated internal AES block encryption function
* without return value.
*
* \deprecated Superseded by utils_internal_aes_encrypt()
*
* \param ctx The AES context to use for encryption.
* \param input Plaintext block.
* \param output Output (ciphertext) block.
*/
UTILS_DEPRECATED void utils_aes_encrypt(utils_aes_context *ctx, const unsigned char input[16],
unsigned char output[16]);
/**
* \brief Deprecated internal AES block decryption function
* without return value.
*
* \deprecated Superseded by utils_internal_aes_decrypt()
*
* \param ctx The AES context to use for decryption.
* \param input Ciphertext block.
* \param output Output (plaintext) block.
*/
UTILS_DEPRECATED void utils_aes_decrypt(utils_aes_context *ctx, const unsigned char input[16],
unsigned char output[16]);
#undef UTILS_DEPRECATED
#endif /* !UTILS_DEPRECATED_REMOVED */
#if defined(UTILS_SELF_TEST)
/**
* \brief Checkup routine.
*
* \return \c 0 on success.
* \return \c 1 on failure.
*/
int utils_aes_self_test(int verbose);
#endif /* UTILS_SELF_TEST */
int aes_sample(int verbose);
int utils_aes_cbc(uint8_t *pInData, uint32_t datalen, uint8_t *pOutData, uint32_t outBuffLen, uint8_t mode,
uint8_t *pKey, uint16_t keybits, uint8_t *iv);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,35 @@
/*
* 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.
*
*/
#ifndef QCLOUD_IOT_UTILS_BASE64_H_
#define QCLOUD_IOT_UTILS_BASE64_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include "qcloud_iot_export_error.h"
#include "qcloud_iot_export_log.h"
int qcloud_iot_utils_base64encode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen);
int qcloud_iot_utils_base64decode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen);
#ifdef __cplusplus
}
#endif
#endif /* QCLOUD_IOT_UTILS_BASE64_H_ */

View File

@@ -0,0 +1,25 @@
/*
* 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.
*
*/
#ifndef QCLOUD_IOT_UTILS_HMAC_H_
#define QCLOUD_IOT_UTILS_HMAC_H_
#include <string.h>
void utils_hmac_md5(const char *msg, int msg_len, char *digest, const char *key, int key_len);
void utils_hmac_sha1(const char *msg, int msg_len, char *digest, const char *key, int key_len);
#endif

View File

@@ -0,0 +1,76 @@
/*
* 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.
*
*/
#ifndef QCLOUD_IOT_UTILS_HTTPC_H_
#define QCLOUD_IOT_UTILS_HTTPC_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include "network_interface.h"
#define HTTP_PORT 80
#define HTTPS_PORT 443
typedef enum { HTTP_GET, HTTP_POST, HTTP_PUT, HTTP_DELETE, HTTP_HEAD } HttpMethod;
typedef struct {
int remote_port;
int response_code;
char * header;
char * auth_user;
char * auth_password;
Network network_stack;
} HTTPClient;
typedef struct {
bool is_more; // if more data to check
bool is_chunked; // if response in chunked data
int retrieve_len; // length of retrieve
int response_content_len; // length of resposne content
int post_buf_len; // post data length
int response_buf_len; // length of response data buffer
char *post_content_type; // type of post content
char *post_buf; // post data buffer
char *response_buf; // response data buffer
} HTTPClientData;
/**
* @brief do one http request
*
* @param client http client
* @param url server url
* @param port server port
* @param ca_crt_dir ca path
* @param method type of request
* @param client_data http data
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int qcloud_http_client_common(HTTPClient *client, const char *url, int port, const char *ca_crt, HttpMethod method,
HTTPClientData *client_data);
int qcloud_http_recv_data(HTTPClient *client, uint32_t timeout_ms, HTTPClientData *client_data);
int qcloud_http_client_connect(HTTPClient *client, const char *url, int port, const char *ca_crt);
void qcloud_http_client_close(HTTPClient *client);
#ifdef __cplusplus
}
#endif
#endif /* QCLOUD_IOT_UTILS_HTTPC_H_ */

View File

@@ -0,0 +1,92 @@
/*
* 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.
*
*/
#ifndef QCLOUD_IOT_UTILS_LIST_H_
#define QCLOUD_IOT_UTILS_LIST_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
/*
* ListNode iterator direction
*/
typedef enum { LIST_HEAD, LIST_TAIL } ListDirection;
/*
* define list node
*/
typedef struct ListNode {
struct ListNode *prev;
struct ListNode *next;
void * val;
} ListNode;
/*
* Double Linked List
*/
typedef struct {
ListNode * head;
ListNode * tail;
unsigned int len;
void (*free)(void *val);
int (*match)(void *a, void *b);
} List;
/*
* list iterator
*/
typedef struct {
ListNode * next;
ListDirection direction;
} ListIterator;
/* create node */
ListNode *list_node_new(void *val);
/* create list */
List *list_new(void);
ListNode *list_rpush(List *self, ListNode *node);
ListNode *list_lpush(List *self, ListNode *node);
ListNode *list_find(List *self, void *val);
ListNode *list_at(List *self, int index);
ListNode *list_rpop(List *self);
ListNode *list_lpop(List *self);
void list_remove(List *self, ListNode *node);
void list_destroy(List *self);
/* create iterator */
ListIterator *list_iterator_new(List *list, ListDirection direction);
ListIterator *list_iterator_new_from_node(ListNode *node, ListDirection direction);
ListNode *list_iterator_next(ListIterator *self);
void list_iterator_destroy(ListIterator *self);
#ifdef __cplusplus
}
#endif
#endif // QCLOUD_IOT_UTILS_LIST_H_

View File

@@ -0,0 +1,87 @@
/*
* 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.
*
*/
#ifndef QCLOUD_IOT_UTILS_MD5_H_
#define QCLOUD_IOT_UTILS_MD5_H_
#include "qcloud_iot_import.h"
typedef struct {
uint32_t total[2]; /*!< number of bytes processed */
uint32_t state[4]; /*!< intermediate digest state */
unsigned char buffer[64]; /*!< data block being processed */
} iot_md5_context;
/**
* @brief init MD5 context
*
* @param ctx MD5 context
*/
void utils_md5_init(iot_md5_context *ctx);
/**
* @brief free MD5 context
*
* @param ctx MD5 context
*/
void utils_md5_free(iot_md5_context *ctx);
/**
* @brief clone MD5 context
*
* @param dst destination MD5 context
* @param src source MD5 context
*/
void utils_md5_clone(iot_md5_context *dst, const iot_md5_context *src);
/**
* @brief start MD5 calculation
*
* @param ctx MD5 context
*/
void utils_md5_starts(iot_md5_context *ctx);
/**
* @brief MD5 update
*
* @param ctx MD5 context
* @param input input data
* @param ilen data length
*/
void utils_md5_update(iot_md5_context *ctx, const unsigned char *input, size_t ilen);
/**
* @brief finish MD5 calculation
*
* @param ctx MD5 context
* @param output MD5 result
*/
void utils_md5_finish(iot_md5_context *ctx, unsigned char output[16]);
/* MD5 internal process */
void utils_md5_process(iot_md5_context *ctx, const unsigned char data[64]);
/**
* @brief Output = MD5( input buffer )
*
* @param input data input
* @param ilen data lenght
* @param output MD5 result
*/
void utils_md5(const unsigned char *input, size_t ilen, unsigned char output[16]);
int8_t utils_hb2hex(uint8_t hb);
#endif

View File

@@ -0,0 +1,85 @@
/*
* 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.
*
*/
#ifndef _UTILS_PARAM_CHECK_H_
#define _UTILS_PARAM_CHECK_H_
#if defined(__cplusplus)
extern "C" {
#endif
#include "qcloud_iot_export_log.h"
#define NUMBERIC_SANITY_CHECK(num, err) \
do { \
if (0 == (num)) { \
Log_e("Invalid argument, numeric 0"); \
return (err); \
} \
} while (0)
#define NUMBERIC_SANITY_CHECK_RTN(num) \
do { \
if (0 == (num)) { \
Log_e("Invalid argument, numeric 0"); \
return; \
} \
} while (0)
#define POINTER_SANITY_CHECK(ptr, err) \
do { \
if (NULL == (ptr)) { \
Log_e("Invalid argument, %s = %p", #ptr, ptr); \
return (err); \
} \
} while (0)
#define POINTER_SANITY_CHECK_RTN(ptr) \
do { \
if (NULL == (ptr)) { \
Log_e("Invalid argument, %s = %p", #ptr, ptr); \
return; \
} \
} while (0)
#define STRING_PTR_SANITY_CHECK(ptr, err) \
do { \
if (NULL == (ptr)) { \
Log_e("Invalid argument, %s = %p", #ptr, (ptr)); \
return (err); \
} \
if (0 == strlen((ptr))) { \
Log_e("Invalid argument, %s = '%s'", #ptr, (ptr)); \
return (err); \
} \
} while (0)
#define STRING_PTR_SANITY_CHECK_RTN(ptr) \
do { \
if (NULL == (ptr)) { \
Log_e("Invalid argument, %s = %p", #ptr, (ptr)); \
return; \
} \
if (0 == strlen((ptr))) { \
Log_e("Invalid argument, %s = '%s'", #ptr, (ptr)); \
return; \
} \
} while (0)
#if defined(__cplusplus)
}
#endif
#endif /* _UTILS_PARAM_CHECK_H_ */

View File

@@ -0,0 +1,42 @@
/*
* 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.
*
*/
#ifndef __AT_RING_BUFF_H__
#define __AT_RING_BUFF_H__
#include "stdbool.h"
#include "stdint.h"
#define RINGBUFF_OK 0 /* No error, everything OK. */
#define RINGBUFF_ERR -1 /* Out of memory error. */
#define RINGBUFF_EMPTY -3 /* Timeout. */
#define RINGBUFF_FULL -4 /* Routing problem. */
#define RINGBUFF_TOO_SHORT -5
typedef struct _ring_buff_ {
uint32_t size;
uint32_t readpoint;
uint32_t writepoint;
char* buffer;
bool full;
} sRingbuff;
typedef sRingbuff* ring_buff_t;
int ring_buff_init(sRingbuff* ring_buff, char* buff, uint32_t size);
int ring_buff_flush(sRingbuff* ring_buff);
int ring_buff_push_data(sRingbuff* ring_buff, uint8_t* pData, int len);
int ring_buff_pop_data(sRingbuff* ring_buff, uint8_t* pData, int len);
#endif // __ringbuff_h__

View File

@@ -0,0 +1,88 @@
/*
* 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.
*
*/
#ifndef QCLOUD_IOT_UTILS_SHA1_H_
#define QCLOUD_IOT_UTILS_SHA1_H_
#include "qcloud_iot_import.h"
/**
* \brief SHA-1 context structure
*/
typedef struct {
uint32_t total[2]; /*!< number of bytes processed */
uint32_t state[5]; /*!< intermediate digest state */
unsigned char buffer[64]; /*!< data block being processed */
} iot_sha1_context;
/**
* \brief Initialize SHA-1 context
*
* \param ctx SHA-1 context to be initialized
*/
void utils_sha1_init(iot_sha1_context *ctx);
/**
* \brief Clear SHA-1 context
*
* \param ctx SHA-1 context to be cleared
*/
void utils_sha1_free(iot_sha1_context *ctx);
/**
* \brief Clone (the state of) a SHA-1 context
*
* \param dst The destination context
* \param src The context to be cloned
*/
void utils_sha1_clone(iot_sha1_context *dst, const iot_sha1_context *src);
/**
* \brief SHA-1 context setup
*
* \param ctx context to be initialized
*/
void utils_sha1_starts(iot_sha1_context *ctx);
/**
* \brief SHA-1 process buffer
*
* \param ctx SHA-1 context
* \param input buffer holding the data
* \param ilen length of the input data
*/
void utils_sha1_update(iot_sha1_context *ctx, const unsigned char *input, size_t ilen);
/**
* \brief SHA-1 final digest
*
* \param ctx SHA-1 context
* \param output SHA-1 checksum result
*/
void utils_sha1_finish(iot_sha1_context *ctx, unsigned char output[20]);
/* Internal use */
void utils_sha1_process(iot_sha1_context *ctx, const unsigned char data[64]);
/**
* \brief Output = SHA-1( input buffer )
*
* \param input buffer holding the data
* \param ilen length of the input data
* \param output SHA-1 checksum result
*/
void utils_sha1(const unsigned char *input, size_t ilen, unsigned char output[20]);
#endif

View File

@@ -0,0 +1,79 @@
/*
* 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.
*
*/
#ifndef QCLOUD_IOT_UTILS_TIMER_H_
#define QCLOUD_IOT_UTILS_TIMER_H_
#ifdef __cplusplus
extern "C" {
#endif
// Add the platform specific timer includes to define the Timer struct
#include "qcloud_iot_import.h"
/**
* @brief Check if a timer is expired
*
* Call this function passing in a timer to check if that timer has expired.
*
* @param timer - pointer to the timer to be checked for expiration
* @return bool - true = timer expired, false = timer not expired
*/
bool expired(Timer *timer);
/**
* @brief Create a timer (milliseconds)
*
* Sets the timer to expire in a specified number of milliseconds.
*
* @param timer - pointer to the timer to be set to expire in milliseconds
* @param timeout_ms - set the timer to expire in this number of milliseconds
*/
void countdown_ms(Timer *timer, unsigned int timeout_ms);
/**
* @brief Create a timer (seconds)
*
* Sets the timer to expire in a specified number of seconds.
*
* @param timer - pointer to the timer to be set to expire in seconds
* @param timeout - set the timer to expire in this number of seconds
*/
void countdown(Timer *timer, unsigned int timeout);
/**
* @brief Check the time remaining on a give timer
*
* Checks the input timer and returns the number of milliseconds remaining on the timer.
*
* @param timer - pointer to the timer to be set to checked
* @return int - milliseconds left on the countdown timer
*/
int left_ms(Timer *timer);
/**
* @brief Initialize a timer
*
* Performs any initialization required to the timer passed in.
*
* @param timer - pointer to the timer to be initialized
*/
void InitTimer(Timer *timer);
#ifdef __cplusplus
}
#endif
#endif // QCLOUD_IOT_UTILS_TIMER_H_

View File

@@ -0,0 +1,872 @@
/*
* 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 "at_client.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "at_utils.h"
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "utils_param_check.h"
#include "utils_timer.h"
#define AT_RESP_END_OK "OK"
#define AT_RESP_END_ERROR "ERROR"
#define AT_RESP_END_FAIL "FAIL"
#define AT_END_CR_LF "\r\n"
sRingbuff g_ring_buff;
static at_client sg_at_client = {0};
static uint32_t sg_flags = 0;
/*this function can be called only by at_uart_isr, just push the data to the at_client ringbuffer.*/
void at_client_uart_rx_isr_cb(uint8_t *pdata, uint8_t len)
{
(void)ring_buff_push_data(&g_ring_buff, pdata, len);
}
/**
* Create response object.
*
* @param buf_size the maximum response buffer size
* @param line_num the number of setting response lines
* = 0: the response data will auto return when received 'OK' or 'ERROR'
* != 0: the response data will return when received setting lines number data
* @param timeout the maximum response time
*
* @return != NULL: response object
* = NULL: no memory
*/
at_response_t at_create_resp(uint32_t buf_size, uint32_t line_num, uint32_t timeout)
{
at_response_t resp = NULL;
resp = (at_response_t)HAL_Malloc(sizeof(at_response));
if (resp == NULL) {
Log_e("AT create response object failed! No memory for response object!");
return NULL;
}
resp->buf = (char *)HAL_Malloc(buf_size);
if (resp->buf == NULL) {
Log_e("AT create response object failed! No memory for response buffer!");
HAL_Free(resp);
return NULL;
}
resp->buf_size = buf_size;
resp->line_num = line_num;
resp->line_counts = 0;
resp->timeout = timeout;
return resp;
}
/**
* Delete and free response object.
*
* @param resp response object
*/
void at_delete_resp(at_response_t resp)
{
if (resp && resp->buf) {
HAL_Free(resp->buf);
}
if (resp) {
HAL_Free(resp);
resp = NULL;
}
}
void at_delayms(uint32_t delayms)
{
#ifdef AT_OS_USED
HAL_SleepMs(delayms);
#else
HAL_DelayMs(delayms);
#endif
}
void at_setFlag(uint32_t flag)
{
sg_flags |= flag & 0xffffffff;
}
void at_clearFlag(uint32_t flag)
{
sg_flags &= (~flag) & 0xffffffff;
}
uint32_t at_getFlag(void)
{
return sg_flags;
}
bool at_waitFlag(uint32_t flag, uint32_t timeout)
{
Timer timer;
bool Ret = false;
countdown_ms(&timer, timeout);
do {
if (flag == (at_getFlag() & flag)) {
Ret = true;
break;
}
at_delayms(1);
} while (!expired(&timer));
return Ret;
}
/**
* Get one line AT response buffer by line number.
*
* @param resp response object
* @param resp_line line number, start from '1'
*
* @return != NULL: response line buffer
* = NULL: input response line error
*/
const char *at_resp_get_line(at_response_t resp, uint32_t resp_line)
{
char *resp_buf = resp->buf;
char *resp_line_buf = NULL;
int line_num = 1;
POINTER_SANITY_CHECK(resp, NULL);
if (resp_line > resp->line_counts || resp_line == 0) {
Log_e("AT response get line failed! Input response line(%d) error!", resp_line);
return NULL;
}
for (line_num = 1; line_num <= resp->line_counts; line_num++) {
if (resp_line == line_num) {
resp_line_buf = resp_buf;
return resp_line_buf;
}
resp_buf += strlen(resp_buf) + 1;
}
return NULL;
}
/**
* Get one line AT response buffer by keyword
*
* @param resp response object
* @param keyword query keyword
*
* @return != NULL: response line buffer
* = NULL: no matching data
*/
const char *at_resp_get_line_by_kw(at_response_t resp, const char *keyword)
{
char *resp_buf = resp->buf;
char *resp_line_buf = NULL;
int line_num = 1;
POINTER_SANITY_CHECK(resp, NULL);
POINTER_SANITY_CHECK(keyword, NULL);
for (line_num = 1; line_num <= resp->line_counts; line_num++) {
if (strstr(resp_buf, keyword)) {
resp_line_buf = resp_buf;
return resp_line_buf;
}
resp_buf += strlen(resp_buf) + 1;
}
return NULL;
}
/**
* Get and parse AT response buffer arguments by line number.
*
* @param resp response object
* @param resp_line line number, start from '1'
* @param resp_expr response buffer expression
*
* @return -1 : input response line number error or get line buffer error
* 0 : parsed without match
* >0 : the number of arguments successfully parsed
*/
int at_resp_parse_line_args(at_response_t resp, uint32_t resp_line, const char *resp_expr, ...)
{
va_list args;
int resp_args_num = 0;
const char *resp_line_buf = NULL;
POINTER_SANITY_CHECK(resp, -1);
POINTER_SANITY_CHECK(resp_expr, -1);
if ((resp_line_buf = at_resp_get_line(resp, resp_line)) == NULL) {
return -1;
}
va_start(args, resp_expr);
resp_args_num = vsscanf(resp_line_buf, resp_expr, args);
va_end(args);
return resp_args_num;
}
/**
* Get and parse AT response buffer arguments by keyword.
*
* @param resp response object
* @param keyword query keyword
* @param resp_expr response buffer expression
*
* @return -1 : input keyword error or get line buffer error
* 0 : parsed without match
* >0 : the number of arguments successfully parsed
*/
int at_resp_parse_line_args_by_kw(at_response_t resp, const char *keyword, const char *resp_expr, ...)
{
va_list args;
int resp_args_num = 0;
const char *resp_line_buf = NULL;
POINTER_SANITY_CHECK(resp, -1);
POINTER_SANITY_CHECK(resp_expr, -1);
if ((resp_line_buf = at_resp_get_line_by_kw(resp, keyword)) == NULL) {
return -1;
}
va_start(args, resp_expr);
resp_args_num = vsscanf(resp_line_buf, resp_expr, args);
va_end(args);
return resp_args_num;
}
/**
* Send commands to AT server and wait response.
*
* @param client current AT client object
* @param resp AT response object, using NULL when you don't care response
* @param cmd_expr AT commands expression
*
* @return 0 : success
* -1 : response status error
* -2 : wait timeout
*/
int at_obj_exec_cmd(at_response_t resp, const char *cmd_expr, ...)
{
POINTER_SANITY_CHECK(cmd_expr, QCLOUD_ERR_INVAL);
va_list args;
int cmd_size = 0;
int result = QCLOUD_RET_SUCCESS;
const char *cmd = NULL;
at_client_t client = at_client_get();
if (client == NULL) {
Log_e("input AT Client object is NULL, please create or get AT Client object!");
return QCLOUD_ERR_FAILURE;
}
HAL_MutexLock(client->lock);
resp->line_counts = 0;
client->resp_status = AT_RESP_OK;
client->resp = resp;
va_start(args, cmd_expr);
at_vprintfln(cmd_expr, args);
va_end(args);
if (resp != NULL) {
#ifndef AT_OS_USED
client->resp_status = AT_RESP_TIMEOUT;
at_client_yeild(NULL, resp->timeout);
if (client->resp_status != AT_RESP_OK) {
cmd = at_get_last_cmd(&cmd_size);
Log_e("execute command (%.*s) failed!", cmd_size, cmd);
result = QCLOUD_ERR_FAILURE;
goto __exit;
}
#else
if (HAL_SemaphoreWait(client->resp_sem, resp->timeout) < 0) {
cmd = at_get_last_cmd(&cmd_size);
Log_e("execute command (%.*s) failed!", cmd_size, cmd);
result = QCLOUD_ERR_FAILURE;
goto __exit;
}
if (client->resp_status != AT_RESP_OK) {
cmd = at_get_last_cmd(&cmd_size);
Log_e("execute command (%.*s) failed!", cmd_size, cmd);
result = QCLOUD_ERR_FAILURE;
goto __exit;
}
#endif
}
__exit:
client->resp = NULL;
HAL_MutexUnlock(client->lock);
return result;
}
/**
* Send data to AT server, send data don't have end sign(eg: \r\n).
*
* @param client current AT client object
* @param buf send data buffer
* @param size send fixed data size
* @param timeout timeout for send
*
* @return >0: send data size
* =0: send failed
*/
int at_client_send(at_client_t client, const char *buf, int size, uint32_t timeout)
{
POINTER_SANITY_CHECK(buf, 0);
if (client == NULL) {
Log_e("input AT Client object is NULL, please create or get AT Client object!");
return 0;
}
#ifdef AT_DEBUG
at_print_raw_cmd("send", buf, size);
#endif
return HAL_AT_Uart_Send((void *)buf, size);
}
static int at_client_getchar(at_client_t client, char *pch, uint32_t timeout)
{
int ret = QCLOUD_RET_SUCCESS;
Timer timer;
countdown_ms(&timer, timeout);
do {
#ifndef AT_UART_RECV_IRQ
if (0 == HAL_AT_Uart_Recv((void *)pch, 1, NULL, timeout)) {
continue;
}
#else
if (0 ==
ring_buff_pop_data(client->pRingBuff, (uint8_t *)pch, 1)) { // push data to ringbuff @ AT_UART_IRQHandler
continue;
}
#endif
else {
break;
}
} while (!expired(&timer));
if (expired(&timer)) {
ret = QCLOUD_ERR_FAILURE;
}
return ret;
}
/**
* AT client receive fixed-length data.
*
* @param client current AT client object
* @param buf receive data buffer
* @param size receive fixed data size
* @param timeout receive data timeout (ms)
*
* @note this function can only be used in execution function of URC data
*
* @return >0: receive data size
* =0: receive failed
*/
int at_client_obj_recv(char *buf, int size, int timeout)
{
int read_idx = 0;
int result = QCLOUD_RET_SUCCESS;
char ch;
POINTER_SANITY_CHECK(buf, 0);
at_client_t client = at_client_get();
if (client == NULL) {
Log_e("input AT Client object is NULL, please create or get AT Client object!");
return 0;
}
while (1) {
if (read_idx < size) {
result = at_client_getchar(client, &ch, timeout);
if (result != QCLOUD_RET_SUCCESS) {
Log_e("AT Client receive failed, uart device get data error(%d)", result);
return 0;
}
buf[read_idx++] = ch;
} else {
break;
}
}
#ifdef AT_DEBUG
at_print_raw_cmd("urc_recv", buf, size);
#endif
return read_idx;
}
/**
* AT client set end sign.
*
* @param client current AT client object
* @param ch the end sign, can not be used when it is '\0'
*/
void at_set_end_sign(char ch)
{
at_client_t client = at_client_get();
if (client == NULL) {
Log_e("input AT Client object is NULL, please create or get AT Client object!");
return;
}
client->end_sign = ch;
}
/**
* set URC(Unsolicited Result Code) table
*
* @param client current AT client object
* @param table URC table
* @param size table size
*/
void at_set_urc_table(at_client_t client, const at_urc_t urc_table, uint32_t table_sz)
{
int idx;
if (client == NULL) {
Log_e("input AT Client object is NULL, please create or get AT Client object!");
return;
}
for (idx = 0; idx < table_sz; idx++) {
POINTER_SANITY_CHECK_RTN(urc_table[idx].cmd_prefix);
POINTER_SANITY_CHECK_RTN(urc_table[idx].cmd_suffix);
}
client->urc_table = urc_table;
client->urc_table_size = table_sz;
}
at_client_t at_client_get(void)
{
return &sg_at_client;
}
static const at_urc *get_urc_obj(at_client_t client)
{
int i, prefix_len, suffix_len;
int buf_sz;
char *buffer = NULL;
if (client->urc_table == NULL) {
return NULL;
}
buffer = client->recv_buffer;
buf_sz = client->cur_recv_len;
for (i = 0; i < client->urc_table_size; i++) {
prefix_len = strlen(client->urc_table[i].cmd_prefix);
suffix_len = strlen(client->urc_table[i].cmd_suffix);
if (buf_sz < prefix_len + suffix_len) {
continue;
}
if ((prefix_len ? !strncmp(buffer, client->urc_table[i].cmd_prefix, prefix_len) : 1) &&
(suffix_len ? !strncmp(buffer + buf_sz - suffix_len, client->urc_table[i].cmd_suffix, suffix_len) : 1)) {
// Log_d("matched:%s", client->urc_table[i].cmd_prefix);
return &client->urc_table[i];
}
}
return NULL;
}
static int at_recv_readline(at_client_t client)
{
int read_len = 0;
char ch = 0, last_ch = 0;
bool is_full = false;
int ret;
memset(client->recv_buffer, 0x00, client->recv_bufsz);
client->cur_recv_len = 0;
while (1) {
ret = at_client_getchar(client, &ch, GET_CHAR_TIMEOUT_MS);
if (QCLOUD_RET_SUCCESS != ret) {
return -1;
}
if (read_len < client->recv_bufsz) {
client->recv_buffer[read_len++] = ch;
client->cur_recv_len = read_len;
} else {
is_full = true;
}
/* is newline or URC data */
if ((ch == '\n' && last_ch == '\r') || (client->end_sign != 0 && ch == client->end_sign) ||
get_urc_obj(client)) {
if (is_full) {
Log_e("read line failed. The line data length is out of buffer size(%d)!", client->recv_bufsz);
memset(client->recv_buffer, 0x00, client->recv_bufsz);
client->cur_recv_len = 0;
ring_buff_flush(client->pRingBuff);
return -1;
}
break;
}
last_ch = ch;
}
#ifdef AT_DEBUG
at_print_raw_cmd("recvline", client->recv_buffer, read_len);
#endif
return read_len;
}
#ifdef AT_OS_USED
static void client_parser(void *userContex)
{
int resp_buf_len = 0;
const at_urc *urc;
int line_counts = 0;
at_client_t client = at_client_get();
Log_d("client_parser start...");
while (1) {
if (at_recv_readline(client) > 0) {
#ifdef AT_DEBUG
const char *cmd = NULL;
int cmdsize = 0;
cmd = at_get_last_cmd(&cmdsize);
Log_d("last_cmd:(%.*s), readline:%s", cmdsize, cmd, client->recv_buffer);
#endif
if ((urc = get_urc_obj(client)) != NULL) {
/* current receive is request, try to execute related operations */
if (urc->func != NULL) {
urc->func(client->recv_buffer, client->cur_recv_len);
}
} else if (client->resp != NULL) {
if (client->end_sign != 0) { // handle endsign
if (client->recv_buffer[client->cur_recv_len - 1] != client->end_sign) {
continue;
} else {
goto exit;
}
}
/* current receive is response */
client->recv_buffer[client->cur_recv_len - 1] = '\0';
if (resp_buf_len + client->cur_recv_len < client->resp->buf_size) {
/* copy response lines, separated by '\0' */
memcpy(client->resp->buf + resp_buf_len, client->recv_buffer, client->cur_recv_len);
resp_buf_len += client->cur_recv_len;
line_counts++;
} else {
client->resp_status = AT_RESP_BUFF_FULL;
Log_e("Read response buffer failed. The Response buffer size is out of buffer size(%d)!",
client->resp->buf_size);
}
/* check response result */
if (memcmp(client->recv_buffer, AT_RESP_END_OK, strlen(AT_RESP_END_OK)) == 0 &&
client->resp->line_num == 0) {
/* get the end data by response result, return response state END_OK. */
client->resp_status = AT_RESP_OK;
} else if (strstr(client->recv_buffer, AT_RESP_END_ERROR) ||
(memcmp(client->recv_buffer, AT_RESP_END_FAIL, strlen(AT_RESP_END_FAIL)) == 0)) {
client->resp_status = AT_RESP_ERROR;
} else if (line_counts == client->resp->line_num && client->resp->line_num) {
/* get the end data by response line, return response state END_OK.*/
client->resp_status = AT_RESP_OK;
} else {
continue;
}
exit:
client->resp->line_counts = line_counts;
client->resp = NULL;
resp_buf_len = 0;
line_counts = 0;
HAL_SemaphorePost(client->resp_sem);
} else {
// Log_d("unrecognized line: %.*s", client->cur_recv_len, client->recv_buffer);
}
} else {
// Log_d("read no new line");
}
}
}
#else
void at_client_yeild(at_urc *expect_urc, uint32_t timeout)
{
int resp_buf_len = 0;
const at_urc *urc;
int line_counts = 0;
int prefix_len;
int suffix_len;
Timer timer;
at_client_t client = at_client_get();
Log_d("Entry...");
countdown_ms(&timer, timeout);
do {
if (at_recv_readline(client) > 0) {
#ifdef AT_DEBUG
const char *cmd = NULL;
int cmdsize = 0;
cmd = at_get_last_cmd(&cmdsize);
Log_d("last_cmd:(%.*s), readline:%s", cmdsize, cmd, client->recv_buffer);
#endif
if ((urc = get_urc_obj(client)) != NULL) {
/* current receive is request, try to execute related operations */
if (urc->func != NULL) {
urc->func(client->recv_buffer, client->cur_recv_len);
}
/*expect urc matched then break*/
if (expect_urc != NULL) {
prefix_len = strlen(expect_urc->cmd_prefix);
suffix_len = strlen(expect_urc->cmd_suffix);
if ((prefix_len ? !strncmp(urc->cmd_prefix, expect_urc->cmd_prefix, prefix_len) : 1) &&
(suffix_len ? !strncmp(urc->cmd_suffix, expect_urc->cmd_suffix, suffix_len) : 1)) {
client->resp_status = AT_RESP_OK;
break;
}
}
} else if (client->resp != NULL) {
if (client->end_sign != 0) { // handle endsign
if (client->recv_buffer[client->cur_recv_len - 1] != client->end_sign) {
continue;
} else {
client->resp_status = AT_RESP_OK;
client->resp->line_counts = line_counts;
client->resp = NULL;
// client->resp_notice = true;
resp_buf_len = 0;
line_counts = 0;
break;
}
}
/* current receive is response */
client->recv_buffer[client->cur_recv_len - 1] = '\0';
if (resp_buf_len + client->cur_recv_len < client->resp->buf_size) {
/* copy response lines, separated by '\0' */
memcpy(client->resp->buf + resp_buf_len, client->recv_buffer, client->cur_recv_len);
resp_buf_len += client->cur_recv_len;
line_counts++;
} else {
client->resp_status = AT_RESP_BUFF_FULL;
Log_e("Read response buffer failed. The Response buffer size is out of buffer size(%d)!",
client->resp->buf_size);
}
/* check response result */
if (memcmp(client->recv_buffer, AT_RESP_END_OK, strlen(AT_RESP_END_OK)) == 0 &&
client->resp->line_num == 0) {
/* get the end data by response result, return response state END_OK. */
client->resp_status = AT_RESP_OK;
} else if (strstr(client->recv_buffer, AT_RESP_END_ERROR) ||
(memcmp(client->recv_buffer, AT_RESP_END_FAIL, strlen(AT_RESP_END_FAIL)) == 0)) {
client->resp_status = AT_RESP_ERROR;
} else if (line_counts == client->resp->line_num && client->resp->line_num) {
/* get the end data by response line, return response state END_OK.*/
client->resp_status = AT_RESP_OK;
} else {
if (!expired(&timer)) {
continue;
} else {
break;
}
}
client->resp->line_counts = line_counts;
client->resp = NULL;
// client->resp_notice = true;
resp_buf_len = 0;
line_counts = 0;
break;
} else {
// Log_d("unrecognized line: %.*s", client->cur_recv_len, client->recv_buffer);
}
} else {
// Log_d("read no new line");
}
} while (!expired(&timer));
}
#endif
/* initialize the client parameters */
int at_client_para_init(at_client_t client)
{
char *ringBuff = NULL;
char *recvBuff = NULL;
client->lock = HAL_MutexCreate();
if (NULL == client->lock) {
Log_e("create lock err");
return QCLOUD_ERR_FAILURE;
}
#ifdef AT_OS_USED
client->resp_sem = HAL_SemaphoreCreate();
if (NULL == client->resp_sem) {
Log_e("create sem err");
goto err_exit;
}
client->parser = client_parser;
#endif
ringBuff = HAL_Malloc(RING_BUFF_LEN);
if (NULL == ringBuff) {
Log_e("malloc ringbuff err");
goto err_exit;
}
ring_buff_init(&g_ring_buff, ringBuff, RING_BUFF_LEN);
recvBuff = HAL_Malloc(CLINET_BUFF_LEN);
if (NULL == recvBuff) {
Log_e("malloc recvbuff err");
goto err_exit;
}
client->recv_buffer = recvBuff;
client->pRingBuff = &g_ring_buff;
client->recv_bufsz = CLINET_BUFF_LEN;
client->cur_recv_len = 0;
client->resp = NULL;
client->urc_table = NULL;
client->urc_table_size = 0;
client->end_sign = 0;
return QCLOUD_RET_SUCCESS;
err_exit:
if (client->lock) {
HAL_MutexDestroy(client->lock);
client->lock = NULL;
}
if (client->resp_sem) {
HAL_SemaphoreDestroy(client->resp_sem);
client->resp_sem = NULL;
}
HAL_Free(ringBuff);
HAL_Free(recvBuff);
return QCLOUD_ERR_FAILURE;
}
/**
* AT client initialize.
*
* @param pClient pinter of at client which to be inited
* @return @see eTidResault
*/
int at_client_init(at_client_t *pClient)
{
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
at_client_t client;
int result;
client = at_client_get();
if (NULL == client) {
Log_e("no at client get");
result = QCLOUD_ERR_FAILURE;
goto exit;
}
if (AT_STATUS_INITIALIZED == client->status) {
Log_e("at client has been initialized");
result = QCLOUD_ERR_FAILURE;
goto exit;
}
result = at_client_para_init(client);
if (result == QCLOUD_RET_SUCCESS) {
Log_d("AT client(V%s) initialize success.", AT_FRAME_VERSION);
client->status = AT_STATUS_INITIALIZED;
*pClient = client;
#if defined(AT_OS_USED) && defined(MULTITHREAD_ENABLED)
// create thread for at parser
if (NULL != client->parser) {
#define AT_PARSER_THREAD_STACK 6144
#define AT_PARSER_THREAD_PRIORITY 0
ThreadParams thread_params = {0};
thread_params.thread_func = client->parser;
thread_params.thread_name = "at_client_parser";
thread_params.user_arg = client;
thread_params.stack_size = AT_PARSER_THREAD_STACK;
thread_params.priority = AT_PARSER_THREAD_PRIORITY;
result = HAL_ThreadCreate(&thread_params);
if (QCLOUD_RET_SUCCESS == result) {
Log_d("create at_parser thread success!");
} else {
Log_e("create at_parser thread fail!");
}
#undef AT_PARSER_THREAD_STACK
#undef AT_PARSER_THREAD_PRIORITY
}
#endif
} else {
*pClient = NULL;
client->status = AT_STATUS_UNINITIALIZED;
Log_e("AT client(V%s) initialize failed(%d).", AT_FRAME_VERSION, result);
}
exit:
return result;
}
int at_client_deinit(at_client_t pClient)
{
// TO DO:
return QCLOUD_RET_SUCCESS;
}

View File

@@ -0,0 +1,413 @@
/*
* 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 "at_socket_inf.h"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "utils_param_check.h"
/** The global array of available at */
static at_socket_ctx_t at_socket_ctxs[MAX_AT_SOCKET_NUM];
/**at socket operation mutex */
static void *sg_at_socket_mutex;
/**at device driver ops*/
static at_device_op_t *sg_at_device_ops = NULL;
#define MAX_RECV_PKT_PER_CHAIN (10)
static at_device_op_t *_at_device_op_get(void)
{
return sg_at_device_ops;
}
static int _at_socket_ctx_free(at_socket_ctx_t *pCtx)
{
POINTER_SANITY_CHECK(pCtx, QCLOUD_ERR_INVAL);
pCtx->fd = UNUSED_SOCKET;
pCtx->net_type = eNET_DEFAULT;
if (pCtx->recvpkt_list) {
list_destroy(pCtx->recvpkt_list);
pCtx->recvpkt_list = NULL;
}
if (pCtx->recv_lock) {
HAL_MutexDestroy(pCtx->recv_lock);
pCtx->recv_lock = NULL;
}
return QCLOUD_RET_SUCCESS;
}
static at_socket_ctx_t *_at_socket_ctx_alloc(void)
{
int i;
for (i = 0; i < MAX_AT_SOCKET_NUM; i++) {
if (at_socket_ctxs[i].state == eSOCKET_CLOSED) {
at_socket_ctxs[i].net_type = eNET_DEFAULT;
at_socket_ctxs[i].send_timeout_ms = AT_SOCKET_SEND_TIMEOUT_MS;
at_socket_ctxs[i].recv_timeout_ms = AT_SOCKET_RECV_TIMEOUT_MS;
at_socket_ctxs[i].dev_op = _at_device_op_get();
at_socket_ctxs[i].recv_lock = HAL_MutexCreate();
if (NULL == at_socket_ctxs[i].recv_lock) {
Log_e("create recv lock fail");
goto exit;
}
at_socket_ctxs[i].recvpkt_list = list_new();
if (NULL != at_socket_ctxs[i].recvpkt_list) {
at_socket_ctxs[i].recvpkt_list->free = HAL_Free;
} else {
Log_e("no memory to allocate recvpkt_list");
goto exit;
}
at_socket_ctxs[i].state = eSOCKET_ALLOCED;
return &at_socket_ctxs[i];
}
}
exit:
if (i < MAX_AT_SOCKET_NUM) {
_at_socket_ctx_free(&at_socket_ctxs[i]);
}
return NULL;
}
static at_socket_ctx_t *_at_socket_find(int fd)
{
int i;
for (i = 0; i < MAX_AT_SOCKET_NUM; i++) {
if (at_socket_ctxs[i].fd == fd) {
return &at_socket_ctxs[i];
}
}
return NULL;
}
/* get a block to the AT socket receive list*/
static int _at_recvpkt_put(List *rlist, const char *ptr, size_t length)
{
at_recv_pkt *pkt = NULL;
if (rlist->len > MAX_RECV_PKT_PER_CHAIN) {
Log_e("Too many recv packets wait for read");
HAL_Free(pkt);
return QCLOUD_ERR_FAILURE;
}
pkt = (at_recv_pkt *)HAL_Malloc(sizeof(struct at_recv_pkt));
if (pkt == NULL) {
Log_e("No memory for receive packet table!");
return QCLOUD_ERR_FAILURE;
}
pkt->bfsz_totle = length;
pkt->bfsz_index = 0;
pkt->buff = (char *)ptr;
ListNode *node = list_node_new(pkt);
if (NULL == node) {
Log_e("run list_node_new is error!");
HAL_Free(pkt);
return QCLOUD_ERR_FAILURE;
}
list_rpush(rlist, node);
return length;
}
/* get a block from AT socket receive list */
static int _at_recvpkt_get(List *pkt_list, char *buff, size_t len)
{
ListIterator *iter;
ListNode * node = NULL;
at_recv_pkt * pkt;
size_t readlen = 0, page_len = 0;
POINTER_SANITY_CHECK(buff, QCLOUD_ERR_INVAL);
if (pkt_list->len) {
iter = list_iterator_new(pkt_list, LIST_HEAD);
if (NULL == iter) {
Log_e("new listiterator fail");
return QCLOUD_ERR_TCP_READ_FAIL;
}
/*traverse recv pktlist*/
do {
node = list_iterator_next(iter);
if (!node) {
break;
}
/*get recv packet*/
pkt = (at_recv_pkt *)(node->val);
if (!pkt) {
Log_e("pkt is invalid!");
list_remove(pkt_list, node);
continue;
}
page_len = pkt->bfsz_totle - pkt->bfsz_index;
if (page_len >= (len - readlen)) {
memcpy(buff + readlen, pkt->buff + pkt->bfsz_index, (len - readlen));
pkt->bfsz_index += len - readlen;
readlen = len;
break;
} else {
memcpy(buff + readlen, pkt->buff + pkt->bfsz_index, page_len);
readlen += page_len;
/*delete pkt after read*/
HAL_Free(pkt->buff);
list_remove(pkt_list, node);
}
} while (1);
list_iterator_destroy(iter);
}
return readlen;
}
static void _at_socket_recv_cb(int fd, at_socket_evt_t event, char *buff, size_t bfsz)
{
POINTER_SANITY_CHECK_RTN(buff);
at_socket_ctx_t *pAtSocket;
if (event == AT_SOCKET_EVT_RECV) {
HAL_MutexLock(sg_at_socket_mutex);
pAtSocket = _at_socket_find(fd + MAX_AT_SOCKET_NUM);
if (_at_recvpkt_put(pAtSocket->recvpkt_list, buff, bfsz) < 0) {
Log_e("put recv package to list fail");
HAL_Free(buff);
}
HAL_MutexUnlock(sg_at_socket_mutex);
}
}
static void _at_socket_closed_cb(int fd, at_socket_evt_t event, char *buff, size_t bfsz)
{
// fancyxu
at_socket_ctx_t *pAtSocket;
pAtSocket = _at_socket_find(fd + MAX_AT_SOCKET_NUM);
if (event == AT_SOCKET_EVT_CLOSED) {
HAL_MutexLock(sg_at_socket_mutex);
pAtSocket->state = eSOCKET_CLOSED;
_at_socket_ctx_free(pAtSocket);
HAL_MutexUnlock(sg_at_socket_mutex);
}
}
int at_device_op_register(at_device_op_t *device_op)
{
int rc;
if (NULL == sg_at_device_ops) {
sg_at_device_ops = device_op;
rc = QCLOUD_RET_SUCCESS;
} else {
Log_e("pre device op already register");
rc = QCLOUD_ERR_FAILURE;
}
return rc;
}
int at_socket_init(void)
{
int i;
int rc = QCLOUD_RET_SUCCESS;
for (i = 0; i < MAX_AT_SOCKET_NUM; i++) {
at_socket_ctxs[i].fd = UNUSED_SOCKET;
at_socket_ctxs[i].state = eSOCKET_CLOSED;
at_socket_ctxs[i].dev_op = NULL;
at_socket_ctxs[i].recvpkt_list = NULL;
}
sg_at_socket_mutex = HAL_MutexCreate();
if (sg_at_socket_mutex == NULL) {
Log_e("create sg_at_socket_mutex fail \n");
rc = QCLOUD_ERR_FAILURE;
}
if (NULL != sg_at_device_ops) {
if (QCLOUD_RET_SUCCESS == sg_at_device_ops->init()) {
Log_d("at device %s init success",
(NULL == sg_at_device_ops->deviceName) ? "noname" : sg_at_device_ops->deviceName);
sg_at_device_ops->set_event_cb(AT_SOCKET_EVT_RECV, _at_socket_recv_cb);
sg_at_device_ops->set_event_cb(AT_SOCKET_EVT_CLOSED, _at_socket_closed_cb);
} else {
Log_e("at device %s init fail",
(NULL == sg_at_device_ops->deviceName) ? "noname" : sg_at_device_ops->deviceName);
}
}
return rc;
}
int at_socket_parse_domain(const char *host_name, char *host_ip, size_t host_ip_len)
{
at_device_op_t *at_op = _at_device_op_get();
POINTER_SANITY_CHECK(at_op, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(at_op->parse_domain, QCLOUD_ERR_INVAL);
return at_op->parse_domain(host_name, host_ip, host_ip_len);
}
int at_socket_get_local_mac(char *macbuff, size_t bufflen)
{
at_device_op_t *at_op = _at_device_op_get();
POINTER_SANITY_CHECK(at_op, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(at_op->get_local_mac, QCLOUD_ERR_INVAL);
return at_op->get_local_mac(macbuff, bufflen);
}
int at_socket_get_local_ip(char *ip, size_t iplen, char *gw, size_t gwlen, char *mask, size_t masklen)
{
at_device_op_t *at_op = _at_device_op_get();
POINTER_SANITY_CHECK(at_op, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(at_op->get_local_ip, QCLOUD_ERR_INVAL);
return at_op->get_local_ip(ip, iplen, gw, gwlen, mask, masklen);
}
int at_socket_connect(const char *host, uint16_t port, eNetProto eProto)
{
at_socket_ctx_t *pAtSocket;
int fd;
HAL_MutexLock(sg_at_socket_mutex);
pAtSocket = _at_socket_ctx_alloc();
HAL_MutexUnlock(sg_at_socket_mutex);
if ((NULL == pAtSocket) || (NULL == pAtSocket->dev_op) || (NULL == pAtSocket->dev_op->connect)) {
Log_e("alloc socket fail");
return QCLOUD_ERR_FAILURE;
}
fd = pAtSocket->dev_op->connect(host, port, eProto);
if (fd < 0) {
Log_e("dev_op connect fail,pls check at device driver!");
_at_socket_ctx_free(pAtSocket);
} else {
pAtSocket->fd = fd + MAX_AT_SOCKET_NUM;
pAtSocket->state = eSOCKET_CONNECTED;
}
return pAtSocket->fd;
}
int at_socket_close(int fd)
{
at_socket_ctx_t *pAtSocket;
pAtSocket = _at_socket_find(fd);
if (NULL == pAtSocket) { // server close the connection
Log_e("socket was closed");
return QCLOUD_ERR_TCP_PEER_SHUTDOWN;
}
int rc;
if ((eSOCKET_CONNECTED == pAtSocket->state) && (NULL != pAtSocket->dev_op) && (NULL != pAtSocket->dev_op->close)) {
rc = pAtSocket->dev_op->close(pAtSocket->fd - MAX_AT_SOCKET_NUM);
} else {
rc = QCLOUD_ERR_FAILURE;
}
return rc;
}
int at_socket_send(int fd, const void *buf, size_t len)
{
at_socket_ctx_t *pAtSocket;
pAtSocket = _at_socket_find(fd);
POINTER_SANITY_CHECK(pAtSocket, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(pAtSocket->dev_op, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(pAtSocket->dev_op->send, QCLOUD_ERR_INVAL);
if (pAtSocket->state != eSOCKET_CONNECTED) {
Log_e("socket was closed");
return QCLOUD_ERR_TCP_PEER_SHUTDOWN;
} else {
return pAtSocket->dev_op->send(fd - MAX_AT_SOCKET_NUM, buf, len);
}
}
int at_socket_recv(int fd, void *buf, size_t len)
{
at_socket_ctx_t *pAtSocket;
size_t recv_len;
pAtSocket = _at_socket_find(fd);
POINTER_SANITY_CHECK(pAtSocket, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(pAtSocket->dev_op, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(pAtSocket->dev_op->recv_timeout, QCLOUD_ERR_INVAL);
if (pAtSocket->state != eSOCKET_CONNECTED) {
Log_e("socket was closed");
return QCLOUD_ERR_TCP_READ_FAIL;
} else {
HAL_MutexLock(pAtSocket->recv_lock);
// call at device recv driver for os and nonos
if (pAtSocket->recvpkt_list->len == 0) {
if (pAtSocket->dev_op->recv_timeout(fd - MAX_AT_SOCKET_NUM, buf, len, pAtSocket->recv_timeout_ms) !=
QCLOUD_RET_SUCCESS) {
Log_e("at device recv err"); // do not return yet
}
}
/* receive packet list last transmission of remaining data */
recv_len = _at_recvpkt_get(pAtSocket->recvpkt_list, (char *)buf, len);
HAL_MutexUnlock(pAtSocket->recv_lock);
}
return recv_len;
}
int at_socket_recv_timeout(int fd, void *buf, size_t len, uint32_t timeout)
{
at_socket_ctx_t *pAtSocket;
pAtSocket = _at_socket_find(fd);
POINTER_SANITY_CHECK(pAtSocket, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(pAtSocket->dev_op, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(pAtSocket->dev_op->recv_timeout, QCLOUD_ERR_INVAL);
if (pAtSocket->state != eSOCKET_CONNECTED) {
Log_e("socket was closed");
return QCLOUD_ERR_TCP_PEER_SHUTDOWN;
} else {
return pAtSocket->dev_op->recv_timeout(fd - MAX_AT_SOCKET_NUM, buf, len, timeout);
}
}

View File

@@ -0,0 +1,345 @@
/*
* 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 "at_utils.h"
#include <ctype.h>
#include <string.h>
#include "at_client.h"
#include "qcloud_iot_import.h"
#include "utils_param_check.h"
static char send_buf[CLINET_BUFF_LEN];
static int last_cmd_len = 0;
/**
* dump hex format data to console device
*
* @param name name for hex object, it will show on log header
* @param buf hex buffer
* @param size buffer size
*/
void at_print_raw_cmd(const char *name, const char *buf, int size)
{
int i, j;
for (i = 0; i < size; i += WIDTH_SIZE) {
HAL_Printf("%s: %04X-%04X: ", name, i, i + WIDTH_SIZE);
for (j = 0; j < WIDTH_SIZE; j++) {
if (i + j < size) {
HAL_Printf("%02X ", buf[i + j]);
} else {
HAL_Printf(" ");
}
if ((j + 1) % 8 == 0) {
HAL_Printf(" ");
}
}
HAL_Printf(" ");
for (j = 0; j < WIDTH_SIZE; j++) {
if (i + j < size) {
HAL_Printf("%c", __is_print(buf[i + j]) ? buf[i + j] : '.');
}
}
HAL_Printf("\n\r");
}
}
const char *at_get_last_cmd(int *cmd_size)
{
*cmd_size = last_cmd_len;
return send_buf;
}
int at_vprintf(const char *format, va_list args)
{
last_cmd_len = vsnprintf(send_buf, sizeof(send_buf), format, args);
#ifdef AT_DEBUG
at_print_raw_cmd("send", send_buf, last_cmd_len);
#endif
return HAL_AT_Uart_Send((uint8_t *)send_buf, last_cmd_len);
}
int at_vprintfln(const char *format, va_list args)
{
int len;
len = at_vprintf(format, args);
HAL_AT_Uart_Send("\r\n", 2);
return len + 2;
}
/**
* at_sscanf - Unformat a buffer into a list of arguments, rewrite sscanf
* @buf: input buffer
* @fmt: format of buffer
* @args: arguments
*/
int at_sscanf(const char *buf, const char *fmt, va_list args)
{
const char *str = buf;
char * next;
int num = 0;
int qualifier;
int base;
int field_width = -1;
int is_sign = 0;
while (*fmt && *str) {
/* skip any white space in format */
/* white space in format matchs any amount of
* white space, including none, in the input.
*/
if (isspace(*fmt)) {
while (isspace(*fmt)) ++fmt;
while (isspace(*str)) ++str;
}
/* anything that is not a conversion must match exactly */
if (*fmt != '%' && *fmt) {
if (*fmt++ != *str++)
break;
continue;
}
if (!*fmt)
break;
++fmt;
/* skip this conversion.
* advance both strings to next white space
*/
if (*fmt == '*') {
while (!isspace(*fmt) && *fmt) fmt++;
while (!isspace(*str) && *str) str++;
continue;
}
/* get field width */
if (isdigit(*fmt))
field_width = atoi(fmt);
/* get conversion qualifier */
qualifier = -1;
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'Z') {
qualifier = *fmt;
fmt++;
}
base = 10;
is_sign = 0;
if (!*fmt || !*str)
break;
switch (*fmt++) {
case 'c': {
char *s = (char *)va_arg(args, char *);
if (field_width == -1)
field_width = 1;
do {
*s++ = *str++;
} while (field_width-- > 0 && *str);
num++;
}
continue;
case 's': {
char *s = (char *)va_arg(args, char *);
if (field_width == -1)
field_width = INT_MAX;
/* first, skip leading white space in buffer */
while (isspace(*str)) str++;
/* now copy until next white space */
while (*str && ((*str) != ',')) {
if (isspace(*str)) {
str++;
} else {
*s++ = *str++;
}
}
*s = '\0';
num++;
}
continue;
/* S for special handling for MQTTPUB JSON content */
case 'S': {
char *s = (char *)va_arg(args, char *);
if (field_width == -1)
field_width = INT_MAX;
/* first, skip leading white space in buffer */
while (isspace(*str)) str++;
/* now copy until next white space */
while (*str) {
if (isspace(*str)) {
str++;
} else {
*s++ = *str++;
}
}
*s = '\0';
num++;
}
continue;
case 'n':
/* return number of characters read so far */
{
int *i = (int *)va_arg(args, int *);
*i = str - buf;
}
continue;
case 'o':
base = 8;
break;
case 'x':
case 'X':
base = 16;
break;
case 'd':
case 'i':
is_sign = 1;
case 'u':
break;
case '%':
/* looking for '%' in str */
if (*str++ != '%')
return num;
continue;
default:
/* invalid format; stop here */
return num;
}
/* have some sort of integer conversion.
* first, skip white space in buffer.
*/
while (isspace(*str)) str++;
if (!*str || !isdigit(*str))
break;
switch (qualifier) {
case 'h':
if (is_sign) {
short *s = (short *)va_arg(args, short *);
*s = (short)strtol(str, &next, base);
} else {
unsigned short *s = (unsigned short *)va_arg(args, unsigned short *);
*s = (unsigned short)strtoul(str, &next, base);
}
break;
case 'l':
if (is_sign) {
long *l = (long *)va_arg(args, long *);
*l = strtol(str, &next, base);
} else {
unsigned long *l = (unsigned long *)va_arg(args, unsigned long *);
*l = strtoul(str, &next, base);
}
break;
case 'L':
if (is_sign) {
long long *l = (long long *)va_arg(args, long long *);
*l = strtoll(str, &next, base);
} else {
unsigned long long *l = (unsigned long long *)va_arg(args, unsigned long long *);
*l = strtoull(str, &next, base);
}
break;
case 'Z': {
unsigned long *s = (unsigned long *)va_arg(args, unsigned long *);
*s = (unsigned long)strtoul(str, &next, base);
} break;
default:
if (is_sign) {
int *i = (int *)va_arg(args, int *);
*i = (int)strtol(str, &next, base);
} else {
unsigned int *i = (unsigned int *)va_arg(args, unsigned int *);
*i = (unsigned int)strtoul(str, &next, base);
}
break;
}
num++;
if (!next)
break;
str = next;
}
return num;
}
/**
* AT server request arguments parse arguments
*
* @param req_args request arguments
* @param req_expr request expression
*
* @return -1 : parse arguments failed
* 0 : parse without match
* >0 : The number of arguments successfully parsed
*/
int at_req_parse_args(const char *req_args, const char *req_expr, ...)
{
va_list args;
int req_args_num = 0;
POINTER_SANITY_CHECK(req_args, 0);
POINTER_SANITY_CHECK(req_expr, 0);
va_start(args, req_expr);
// req_args_num = vsscanf(req_args, req_expr, args);
req_args_num = at_sscanf(req_args, req_expr, args);
va_end(args);
return req_args_num;
}
void at_strip(char *str, const char patten)
{
char *start, *end;
start = str;
end = str + strlen(str) - 1;
if (*str == patten) {
start++;
}
if (*end == patten) {
*end-- = '\0';
}
strcpy(str, start);
}
void chr_strip(char *str, const char patten)
{
char *end = str + strlen(str);
while (*str != '\0') {
if (*str == patten) {
memmove(str, str + 1, end - str);
}
str++;
}
}

View File

@@ -0,0 +1,153 @@
/*
* 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 "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#ifdef AT_TCP_ENABLED
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "at_socket_inf.h"
#include "network_interface.h"
#include "utils_param_check.h"
#include "utils_timer.h"
int network_at_tcp_init(Network *pNetwork)
{
int rc;
/*at device init entry: at_client init, device driver register to at_socket*/
rc = at_device_init();
if (QCLOUD_RET_SUCCESS != rc) {
Log_e("at device init fail,rc:%d", rc);
return rc;
}
/*do after at device init*/
rc = at_socket_init();
if (QCLOUD_RET_SUCCESS != rc) {
Log_e("at socket init fail,rc:%d", rc);
}
return rc;
}
int network_at_tcp_connect(Network *pNetwork)
{
POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL);
int fd = at_socket_connect(pNetwork->host, pNetwork->port, eNET_TCP);
if (fd < 0) {
Log_e("fail to connect with TCP server: %s:%u", pNetwork->host, pNetwork->port);
pNetwork->handle = AT_NO_CONNECTED_FD;
return -1;
} else {
Log_d("connected with TCP server: %s:%u", pNetwork->host, pNetwork->port);
pNetwork->handle = fd;
return 0;
}
}
int network_at_tcp_read(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *read_len)
{
int ret, err_code;
uint32_t len_recv;
Timer timer;
InitTimer(&timer);
countdown_ms(&timer, timeout_ms);
len_recv = 0;
err_code = 0;
do {
if (expired(&timer)) {
err_code = QCLOUD_ERR_TCP_READ_TIMEOUT;
break;
}
ret = at_socket_recv(pNetwork->handle, data + len_recv, datalen - len_recv);
if (ret > 0) {
len_recv += ret;
} else if (ret == 0) {
err_code = QCLOUD_ERR_TCP_NOTHING_TO_READ;
} else { // ret < 0
Log_e("recv fail\n");
err_code = QCLOUD_ERR_TCP_READ_FAIL;
break;
}
} while ((len_recv < datalen));
if (err_code == QCLOUD_ERR_TCP_READ_TIMEOUT && len_recv == 0) {
err_code = QCLOUD_ERR_TCP_NOTHING_TO_READ;
}
*read_len = len_recv;
return (datalen == len_recv) ? QCLOUD_RET_SUCCESS : err_code;
}
int network_at_tcp_write(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms,
size_t *written_len)
{
int ret;
uint32_t len_sent;
Timer timer;
int net_err = 0;
InitTimer(&timer);
countdown_ms(&timer, timeout_ms);
len_sent = 0;
ret = 1; /* send one time if timeout_ms is value 0 */
do {
ret = at_socket_send(pNetwork->handle, data + len_sent, datalen - len_sent);
if (ret > 0) {
len_sent += ret;
} else if (0 == ret) {
Log_e("No data be sent\n");
} else {
Log_e("send fail, ret:%d\n", ret);
net_err = 1;
break;
}
} while (!net_err && (len_sent < datalen) && (!expired(&timer)));
*written_len = (size_t)len_sent;
return (len_sent > 0 && net_err == 0) ? QCLOUD_RET_SUCCESS : QCLOUD_ERR_TCP_WRITE_FAIL;
}
void network_at_tcp_disconnect(Network *pNetwork)
{
int rc;
rc = at_socket_close((int)pNetwork->handle);
if (QCLOUD_RET_SUCCESS != rc) {
Log_e("socket close error\n");
}
return;
}
#endif

View File

@@ -0,0 +1,111 @@
/*
* 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 "network_interface.h"
#include "qcloud_iot_export_error.h"
#include "utils_param_check.h"
int is_network_connected(Network *pNetwork)
{
return pNetwork->handle;
}
#ifdef AT_TCP_ENABLED
int is_network_at_connected(Network *pNetwork)
{
return pNetwork->handle == AT_NO_CONNECTED_FD ? 0 : pNetwork->handle == AT_NO_CONNECTED_FD;
}
#endif
int network_init(Network *pNetwork)
{
POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL);
// to avoid process crash when writing to a broken socket
#if defined(__linux__)
signal(SIGPIPE, SIG_IGN);
#endif
switch (pNetwork->type) {
case NETWORK_TCP:
#ifdef AT_TCP_ENABLED
pNetwork->init = network_at_tcp_init;
pNetwork->connect = network_at_tcp_connect;
pNetwork->read = network_at_tcp_read;
pNetwork->write = network_at_tcp_write;
pNetwork->disconnect = network_at_tcp_disconnect;
pNetwork->is_connected = is_network_at_connected;
pNetwork->handle = AT_NO_CONNECTED_FD;
#else
pNetwork->init = network_tcp_init;
pNetwork->connect = network_tcp_connect;
pNetwork->read = network_tcp_read;
pNetwork->write = network_tcp_write;
pNetwork->disconnect = network_tcp_disconnect;
pNetwork->is_connected = is_network_connected;
pNetwork->handle = 0;
#endif
break;
#ifndef AUTH_WITH_NOTLS
case NETWORK_TLS:
pNetwork->init = network_tls_init;
pNetwork->connect = network_tls_connect;
pNetwork->read = network_tls_read;
pNetwork->write = network_tls_write;
pNetwork->disconnect = network_tls_disconnect;
pNetwork->is_connected = is_network_connected;
pNetwork->handle = 0;
break;
#endif
#ifdef COAP_COMM_ENABLED
#ifdef AUTH_WITH_NOTLS
case NETWORK_UDP:
pNetwork->init = network_udp_init;
pNetwork->connect = network_udp_connect;
pNetwork->read = network_udp_read;
pNetwork->write = network_udp_write;
pNetwork->disconnect = network_udp_disconnect;
pNetwork->is_connected = is_network_connected;
pNetwork->handle = 0;
break;
#else
case NETWORK_DTLS:
pNetwork->init = network_dtls_init;
pNetwork->connect = network_dtls_connect;
pNetwork->read = network_dtls_read;
pNetwork->write = network_dtls_write;
pNetwork->disconnect = network_dtls_disconnect;
pNetwork->is_connected = is_network_connected;
pNetwork->handle = 0;
break;
#endif
#endif
default:
Log_e("unknown network type: %d", pNetwork->type);
return QCLOUD_ERR_INVAL;
}
return pNetwork->init(pNetwork);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,131 @@
/*
* 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 "network_interface.h"
#include "qcloud_iot_export_error.h"
#include "qcloud_iot_import.h"
#include "utils_param_check.h"
/*
* TCP/UDP socket API
*/
int network_tcp_init(Network *pNetwork)
{
return QCLOUD_RET_SUCCESS;
}
int network_tcp_connect(Network *pNetwork)
{
POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL);
pNetwork->handle = HAL_TCP_Connect(pNetwork->host, pNetwork->port);
if (0 == pNetwork->handle) {
return -1;
}
return 0;
}
int network_tcp_read(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *read_len)
{
POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL);
int rc = 0;
rc = HAL_TCP_Read(pNetwork->handle, data, (uint32_t)datalen, timeout_ms, read_len);
return rc;
}
int network_tcp_write(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *written_len)
{
POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL);
int rc = 0;
rc = HAL_TCP_Write(pNetwork->handle, data, datalen, timeout_ms, written_len);
return rc;
}
void network_tcp_disconnect(Network *pNetwork)
{
POINTER_SANITY_CHECK_RTN(pNetwork);
if (0 == pNetwork->handle) {
return;
}
HAL_TCP_Disconnect(pNetwork->handle);
pNetwork->handle = 0;
return;
}
#if (defined COAP_COMM_ENABLED) && (defined AUTH_WITH_NOTLS)
int network_udp_init(Network *pNetwork)
{
return QCLOUD_RET_SUCCESS;
}
int network_udp_read(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *read_len)
{
POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL);
int ret = HAL_UDP_ReadTimeout(pNetwork->handle, data, datalen, timeout_ms);
if (ret > 0) {
*read_len = ret;
ret = 0;
}
return ret;
}
int network_udp_write(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *written_len)
{
POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL);
int ret = HAL_UDP_Write(pNetwork->handle, data, datalen);
if (ret > 0) {
*written_len = ret;
ret = 0;
}
return ret;
}
void network_udp_disconnect(Network *pNetwork)
{
POINTER_SANITY_CHECK_RTN(pNetwork);
HAL_UDP_Disconnect(pNetwork->handle);
pNetwork->handle = 0;
return;
}
int network_udp_connect(Network *pNetwork)
{
POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL);
pNetwork->handle = HAL_UDP_Connect(pNetwork->host, pNetwork->port);
if (0 == pNetwork->handle) {
return -1;
}
return 0;
}
#endif

View File

@@ -0,0 +1,117 @@
/*
* 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 "network_interface.h"
#include "qcloud_iot_export_error.h"
#include "qcloud_iot_import.h"
#include "utils_param_check.h"
/*
* TLS/DTLS network API
*/
#ifndef AUTH_WITH_NOTLS
int network_tls_init(Network *pNetwork)
{
return QCLOUD_RET_SUCCESS;
}
int network_tls_connect(Network *pNetwork)
{
POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL);
int ret = QCLOUD_ERR_FAILURE;
pNetwork->handle = (uintptr_t)HAL_TLS_Connect(&(pNetwork->ssl_connect_params), pNetwork->host, pNetwork->port);
if (pNetwork->handle != 0) {
ret = QCLOUD_RET_SUCCESS;
}
return ret;
}
int network_tls_read(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *read_len)
{
POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL);
int rc = HAL_TLS_Read(pNetwork->handle, data, datalen, timeout_ms, read_len);
return rc;
}
int network_tls_write(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *written_len)
{
POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL);
int rc = HAL_TLS_Write(pNetwork->handle, data, datalen, timeout_ms, written_len);
return rc;
}
void network_tls_disconnect(Network *pNetwork)
{
POINTER_SANITY_CHECK_RTN(pNetwork);
HAL_TLS_Disconnect(pNetwork->handle);
pNetwork->handle = 0;
}
#ifdef COAP_COMM_ENABLED
int network_dtls_init(Network *pNetwork)
{
return QCLOUD_RET_SUCCESS;
}
int network_dtls_read(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *read_len)
{
POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL);
return HAL_DTLS_Read(pNetwork->handle, data, datalen, timeout_ms, read_len);
}
int network_dtls_write(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *written_len)
{
POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL);
return HAL_DTLS_Write(pNetwork->handle, data, datalen, written_len);
}
void network_dtls_disconnect(Network *pNetwork)
{
POINTER_SANITY_CHECK_RTN(pNetwork);
HAL_DTLS_Disconnect(pNetwork->handle);
pNetwork->handle = 0;
return;
}
int network_dtls_connect(Network *pNetwork)
{
POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL);
int ret = QCLOUD_ERR_FAILURE;
pNetwork->handle = (uintptr_t)HAL_DTLS_Connect(&(pNetwork->ssl_connect_params), pNetwork->host, pNetwork->port);
if (pNetwork->handle != 0) {
ret = QCLOUD_RET_SUCCESS;
}
return ret;
}
#endif
#endif

View File

@@ -0,0 +1,360 @@
/*
* 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 "coap_client.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.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_base64.h"
#include "utils_param_check.h"
static uint16_t _get_random_start_packet_id(void)
{
srand((unsigned)time(NULL));
return rand() % 65536 + 1;
}
DeviceInfo *IOT_COAP_GetDeviceInfo(void *pClient)
{
POINTER_SANITY_CHECK(pClient, NULL);
CoAPClient *coap_client = (CoAPClient *)pClient;
return &coap_client->device_info;
}
void *IOT_COAP_Construct(CoAPInitParams *pParams)
{
POINTER_SANITY_CHECK(pParams, NULL);
STRING_PTR_SANITY_CHECK(pParams->product_id, NULL);
STRING_PTR_SANITY_CHECK(pParams->device_name, NULL);
CoAPClient *coap_client = NULL;
if ((coap_client = (CoAPClient *)HAL_Malloc(sizeof(CoAPClient))) == NULL) {
Log_e("memory not enough to malloc COAPClient");
return NULL;
}
int rc = qcloud_iot_coap_init(coap_client, pParams);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("coap init failed: %d", rc);
HAL_Free(coap_client);
return NULL;
}
if (coap_client->network_stack.connect(&coap_client->network_stack) != QCLOUD_RET_SUCCESS) {
Log_e("coap connect to host: %s:%d failed: %d", coap_client->network_stack.host,
coap_client->network_stack.port, rc);
HAL_Free(coap_client);
return NULL;
} else {
Log_i("coap connect to host: %s:%d success", coap_client->network_stack.host, coap_client->network_stack.port);
}
coap_client_auth(coap_client);
while (coap_client->is_authed == -1) {
IOT_COAP_Yield(coap_client, 200);
}
if (coap_client->is_authed == COAP_TRUE) {
Log_i("device auth successfully, connid: %s", coap_client->conn_id);
return coap_client;
} else {
Log_e("device auth failed, connid: %s", coap_client->conn_id);
void *client = coap_client;
IOT_COAP_Destroy(&client);
return NULL;
}
}
void IOT_COAP_Destroy(void **pClient)
{
POINTER_SANITY_CHECK_RTN(*pClient);
CoAPClient *coap_client = (CoAPClient *)(*pClient);
if ((coap_client)->network_stack.handle != 0) {
(coap_client)->network_stack.disconnect(&(coap_client)->network_stack);
}
list_destroy(coap_client->message_list);
HAL_MutexDestroy(coap_client->lock_send_buf);
HAL_MutexDestroy(coap_client->lock_list_wait_ack);
if (coap_client->auth_token != NULL) {
HAL_Free(coap_client->auth_token);
coap_client->auth_token = NULL;
}
coap_client->auth_token_len = 0;
coap_client->is_authed = -1;
HAL_Free(*pClient);
*pClient = NULL;
Log_i("coap release!");
}
int IOT_COAP_Yield(void *pClient, uint32_t timeout_ms)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
CoAPClient *coap_client = (CoAPClient *)pClient;
return coap_message_cycle(coap_client, timeout_ms);
}
int IOT_COAP_SendMessage(void *pClient, char *topicName, SendMsgParams *sendParams)
{
IOT_FUNC_ENTRY
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(topicName, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(sendParams, QCLOUD_ERR_INVAL);
if (strlen(topicName) > URI_PATH_MAX_LEN) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MAX_TOPIC_LENGTH);
}
int ret = QCLOUD_RET_SUCCESS;
CoAPClient *coap_client = (CoAPClient *)pClient;
CoAPMessage send_message = DEFAULT_COAP_MESSAGE;
coap_message_type_set(&send_message, COAP_MSG_CON);
coap_message_code_set(&send_message, COAP_MSG_REQ, COAP_MSG_POST);
coap_message_id_set(&send_message, get_next_coap_msg_id(coap_client));
char message_token[8] = {0};
int len = get_coap_message_token(pClient, message_token);
coap_message_token_set(&send_message, message_token, len);
send_message.pay_load = (char *)HAL_Malloc(sendParams->pay_load_len);
if (NULL == send_message.pay_load)
IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
coap_message_payload_set(&send_message, sendParams->pay_load, sendParams->pay_load_len);
coap_message_option_add(&send_message, COAP_MSG_URI_PATH, strlen(topicName), topicName);
coap_message_option_add(&send_message, COAP_MSG_AUTH_TOKEN, coap_client->auth_token_len, coap_client->auth_token);
if (sendParams->need_resp == false) {
coap_message_option_add(&send_message, COAP_MSG_NEED_RESP, 1, "0");
coap_message_context_set(&send_message, sendParams->user_context);
} else {
coap_message_option_add(&send_message, COAP_MSG_NEED_RESP, 1, "1");
coap_message_callback_set(&send_message, sendParams->resp_callback);
coap_message_context_set(&send_message, sendParams->user_context);
}
ret = coap_message_send(coap_client, &send_message);
HAL_Free(send_message.pay_load);
if (ret != QCLOUD_RET_SUCCESS) {
IOT_FUNC_EXIT_RC(ret)
}
IOT_FUNC_EXIT_RC(send_message.msg_id)
}
int IOT_COAP_GetMessageId(void *pMessage)
{
IOT_FUNC_ENTRY
POINTER_SANITY_CHECK(pMessage, QCLOUD_ERR_INVAL);
CoAPMessage *message = (CoAPMessage *)pMessage;
IOT_FUNC_EXIT_RC(message->msg_id)
}
int IOT_COAP_GetMessagePayload(void *pMessage, char **payload, int *payloadLen)
{
IOT_FUNC_ENTRY
POINTER_SANITY_CHECK(pMessage, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(payload, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(payloadLen, QCLOUD_ERR_INVAL);
CoAPMessage *message = (CoAPMessage *)pMessage;
if (message->code_class != COAP_MSG_SUCCESS || message->code_detail != COAP_MSG_CODE_205_CONTENT) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE)
}
*payload = message->pay_load;
*payloadLen = message->pay_load_len;
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS)
}
int IOT_COAP_GetMessageCode(void *pMessage)
{
IOT_FUNC_ENTRY
POINTER_SANITY_CHECK(pMessage, QCLOUD_ERR_INVAL);
CoAPMessage *message = (CoAPMessage *)pMessage;
int rc = COAP_EVENT_ACK_TIMEOUT;
if (message->code_class == COAP_MSG_SUCCESS) {
rc = COAP_EVENT_RECEIVE_RESPCONTENT;
} else if (message->code_class == COAP_MSG_CLIENT_ERR) {
if (message->code_detail == COAP_MSG_CODE_401_UNAUTHORIZED) {
rc = COAP_EVENT_UNAUTHORIZED;
} else {
rc = COAP_EVENT_FORBIDDEN;
}
} else if (message->code_class == COAP_MSG_SERVER_ERR) {
rc = COAP_EVENT_INTERNAL_SERVER_ERROR;
} else if (message->code_class == COAP_MSG_SDKINTERNAL_ERR) {
rc = COAP_EVENT_SEPRESP_TIMEOUT;
} else {
/**
* no more error code
*/
Log_e("not supported code class: %d", message->code_class);
}
IOT_FUNC_EXIT_RC(rc)
}
int qcloud_iot_coap_init(CoAPClient *pClient, CoAPInitParams *pParams)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(pParams, QCLOUD_ERR_INVAL);
memset(pClient, 0x0, sizeof(CoAPClient));
int rc = iot_device_info_set(&(pClient->device_info), pParams->product_id, pParams->device_name);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("failed to set device info: %d", rc);
return rc;
}
int size =
HAL_Snprintf(pClient->host_addr, HOST_STR_LENGTH, "%s.%s", pParams->product_id, QCLOUD_IOT_COAP_DEIRECT_DOMAIN);
if (size < 0 || size > HOST_STR_LENGTH - 1) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
pClient->is_authed = -1;
if (pParams->command_timeout < MIN_COMMAND_TIMEOUT)
pParams->command_timeout = MIN_COMMAND_TIMEOUT;
if (pParams->command_timeout > MAX_COMMAND_TIMEOUT)
pParams->command_timeout = MAX_COMMAND_TIMEOUT;
pClient->command_timeout_ms = pParams->command_timeout;
#ifndef AUTH_WITH_NOTLS
#ifdef AUTH_MODE_CERT
Log_d("cert file: %s", pParams->cert_file);
Log_d("key file: %s", pParams->key_file);
strncpy(pClient->cert_file_path, pParams->cert_file, FILE_PATH_MAX_LEN - 1);
strncpy(pClient->key_file_path, pParams->key_file, FILE_PATH_MAX_LEN - 1);
// device param for TLS connection
pClient->network_stack.ssl_connect_params.cert_file = pParams->cert_file;
pClient->network_stack.ssl_connect_params.key_file = pParams->key_file;
pClient->network_stack.ssl_connect_params.ca_crt = iot_ca_get();
pClient->network_stack.ssl_connect_params.ca_crt_len = strlen(pClient->network_stack.ssl_connect_params.ca_crt);
#else
pClient->network_stack.ssl_connect_params.psk_id = pClient->device_info.client_id;
if (pParams->device_secret != NULL) {
size_t src_len = strlen(pParams->device_secret);
size_t len;
memset(pClient->psk_decode, 0x00, DECODE_PSK_LENGTH);
qcloud_iot_utils_base64decode(pClient->psk_decode, DECODE_PSK_LENGTH, &len,
(unsigned char *)pParams->device_secret, src_len);
pClient->network_stack.ssl_connect_params.psk = (char *)pClient->psk_decode;
pClient->network_stack.ssl_connect_params.psk_length = len;
pClient->network_stack.ssl_connect_params.ca_crt = NULL;
pClient->network_stack.ssl_connect_params.ca_crt_len = 0;
} else {
Log_e("psk is empty!");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
}
#endif
pClient->network_stack.host = pClient->host_addr;
pClient->network_stack.port = COAP_SERVER_PORT;
#else
pClient->network_stack.host = pClient->host_addr;
pClient->network_stack.port = COAP_SERVER_PORT;
#endif
pClient->auth_token = NULL;
pClient->auth_token_len = 0;
// next_msg_id, random: 1- 65536
pClient->next_msg_id = _get_random_start_packet_id();
pClient->read_buf_size = COAP_RECVMSG_MAX_BUFLEN;
pClient->send_buf_size = COAP_SENDMSG_MAX_BUFLEN;
pClient->lock_send_buf = HAL_MutexCreate();
if (pClient->lock_send_buf == NULL) {
Log_e("create send buf lock failed");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
pClient->lock_list_wait_ack = HAL_MutexCreate();
if (pClient->lock_list_wait_ack == NULL) {
Log_e("create send buf lock failed");
goto error;
}
pClient->message_list = list_new();
pClient->max_retry_count = pParams->max_retry_count;
pClient->event_handle = pParams->event_handle;
// init network stack
qcloud_iot_coap_network_init(&(pClient->network_stack));
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
error:
if (pClient->lock_send_buf != NULL) {
HAL_MutexDestroy(pClient->lock_send_buf);
pClient->lock_send_buf = NULL;
}
if (pClient->lock_list_wait_ack != NULL) {
HAL_MutexDestroy(pClient->lock_list_wait_ack);
pClient->lock_list_wait_ack = NULL;
}
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,147 @@
/*
* 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 <string.h>
#include <time.h>
#include "coap_client.h"
#include "qcloud_iot_common.h"
#include "qcloud_iot_device.h"
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "utils_param_check.h"
static void _coap_client_auth_callback(void *message, void *userContext)
{
IOT_FUNC_ENTRY
POINTER_SANITY_CHECK_RTN(message);
POINTER_SANITY_CHECK_RTN(userContext);
CoAPClient * client = (CoAPClient *)userContext;
CoAPMessage *msg = (CoAPMessage *)message;
if (msg->code_class == COAP_MSG_SUCCESS && msg->code_detail == COAP_MSG_CODE_205_CONTENT) {
Log_i("auth token message success, code_class: %d code_detail: %d", msg->code_class, msg->code_detail);
if (msg->pay_load_len == 0 || msg->pay_load == NULL || strlen(msg->pay_load) == 0) {
client->is_authed = COAP_FALSE;
Log_e("auth token response empty");
} else {
client->auth_token_len = msg->pay_load_len;
client->auth_token = HAL_Malloc(client->auth_token_len);
strncpy(client->auth_token, msg->pay_load, client->auth_token_len);
client->is_authed = COAP_TRUE;
Log_d("auth_token_len = %d, auth_token = %.*s", client->auth_token_len, client->auth_token_len,
client->auth_token);
}
} else {
client->is_authed = COAP_FALSE;
Log_e("auth token message failed, code_class: %d code_detail: %d", msg->code_class, msg->code_detail);
}
IOT_FUNC_EXIT
}
static void get_coap_next_conn_id(CoAPClient *pclient)
{
int i = 0;
srand((unsigned)time(0));
for (i = 0; i < COAP_MAX_CONN_ID_LEN - 1; i++) {
int flag = rand() % 3;
switch (flag) {
case 0:
pclient->conn_id[i] = (rand() % 26) + 'a';
break;
case 1:
pclient->conn_id[i] = (rand() % 26) + 'A';
break;
case 2:
pclient->conn_id[i] = (rand() % 10) + '0';
break;
}
}
pclient->conn_id[COAP_MAX_CONN_ID_LEN - 1] = '\0';
return;
}
int coap_client_auth(CoAPClient *pclient)
{
IOT_FUNC_ENTRY
POINTER_SANITY_CHECK(pclient, QCLOUD_ERR_COAP_NULL);
int ret = QCLOUD_RET_SUCCESS;
CoAPClient *coap_client = (CoAPClient *)pclient;
CoAPMessage send_message = DEFAULT_COAP_MESSAGE;
coap_message_type_set(&send_message, COAP_MSG_CON);
coap_message_code_set(&send_message, COAP_MSG_REQ, COAP_MSG_POST);
coap_message_id_set(&send_message, get_next_coap_msg_id(coap_client));
char message_token[8] = {0};
int len = get_coap_message_token(pclient, message_token);
coap_message_token_set(&send_message, message_token, len);
len = MAX_SIZE_OF_PRODUCT_ID + strlen(pclient->device_info.device_name) + strlen(COAP_AUTH_URI) + 4;
char *auth_path = (char *)HAL_Malloc(len);
HAL_Snprintf(auth_path, len, "%s/%s/%s", pclient->device_info.product_id, pclient->device_info.device_name,
COAP_AUTH_URI);
coap_message_option_add(&send_message, COAP_MSG_URI_PATH, strlen(auth_path), auth_path);
HAL_Free(auth_path);
coap_message_option_add(&send_message, COAP_MSG_NEED_RESP, 1, "0");
coap_message_callback_set(&send_message, _coap_client_auth_callback);
coap_message_context_set(&send_message, pclient);
get_coap_next_conn_id(coap_client);
send_message.pay_load_len = strlen(QCLOUD_IOT_DEVICE_SDK_APPID) + COAP_MAX_CONN_ID_LEN + 2;
send_message.pay_load = (char *)HAL_Malloc(send_message.pay_load_len);
if (NULL == send_message.pay_load)
IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
char *temp_pay_load = (char *)HAL_Malloc(send_message.pay_load_len);
if (NULL == temp_pay_load) {
HAL_Free(send_message.pay_load);
IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
}
HAL_Snprintf(temp_pay_load, send_message.pay_load_len, "%s;%s", QCLOUD_IOT_DEVICE_SDK_APPID, coap_client->conn_id);
coap_message_payload_set(&send_message, temp_pay_load, send_message.pay_load_len);
ret = coap_message_send(coap_client, &send_message);
HAL_Free(temp_pay_load);
HAL_Free(send_message.pay_load);
IOT_FUNC_EXIT_RC(ret)
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,284 @@
/*
* 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 <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "coap_client.h"
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "utils_param_check.h"
/**
* @brief Free an option structure that was allocated by coap_msg_op_new
*
* @param[in,out] op Pointer to the option structure
*/
static void _coap_msg_op_delete(CoAPMsgOption *option)
{
IOT_FUNC_ENTRY
HAL_Free(option->val);
HAL_Free(option);
IOT_FUNC_EXIT
}
/**
* @brief Deinitialise an option linked-list structure
*
* @param[in,out] list Pointer to an option linked-list structure
*/
static void _coap_msg_op_list_destroy(CoAPMsgOptionList *list)
{
IOT_FUNC_ENTRY
CoAPMsgOption *prev = NULL;
CoAPMsgOption *option = NULL;
option = list->first;
while (option != NULL) {
prev = option;
option = option->next;
_coap_msg_op_delete(prev);
}
memset(list, 0, sizeof(CoAPMsgOptionList));
IOT_FUNC_EXIT
}
uint16_t get_next_coap_msg_id(CoAPClient *pClient)
{
IOT_FUNC_ENTRY
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
unsigned int id = 0;
id = pClient->next_msg_id =
(uint16_t)((COAP_MSG_MAX_MSG_ID == pClient->next_msg_id) ? 1 : (pClient->next_msg_id + 1));
IOT_FUNC_EXIT_RC(id)
}
unsigned int get_coap_message_token(CoAPClient *client, char *tokenData)
{
unsigned int value = client->message_token;
tokenData[0] = ((value & 0x00FF) >> 0);
tokenData[1] = ((value & 0xFF00) >> 8);
tokenData[2] = ((value & 0xFF0000) >> 16);
tokenData[3] = ((value & 0xFF000000) >> 24);
client->message_token++;
return sizeof(unsigned int);
}
int coap_message_type_set(CoAPMessage *message, unsigned type)
{
IOT_FUNC_ENTRY
if ((type != COAP_MSG_CON) && (type != COAP_MSG_NON) && (type != COAP_MSG_ACK) && (type != COAP_MSG_RST)) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL)
}
message->type = type;
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS)
}
int coap_message_code_set(CoAPMessage *message, unsigned code_class, unsigned code_detail)
{
IOT_FUNC_ENTRY
if (code_class > COAP_MSG_MAX_CODE_CLASS) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL)
}
if (code_detail > COAP_MSG_MAX_CODE_DETAIL) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL)
}
message->code_class = code_class;
message->code_detail = code_detail;
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS)
}
int coap_message_id_set(CoAPMessage *message, unsigned msg_id)
{
IOT_FUNC_ENTRY
if (msg_id > COAP_MSG_MAX_MSG_ID) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL)
}
message->msg_id = msg_id;
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS)
}
int coap_message_token_set(CoAPMessage *message, char *buf, size_t len)
{
IOT_FUNC_ENTRY
if (len > COAP_MSG_MAX_TOKEN_LEN) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL)
}
memcpy(message->token, buf, len);
message->token_len = len;
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS)
}
int coap_message_payload_set(CoAPMessage *message, char *buf, size_t len)
{
IOT_FUNC_ENTRY
message->pay_load_len = 0;
if (len > 0) {
if (message->pay_load == NULL) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE)
}
memcpy(message->pay_load, buf, len);
message->pay_load_len = len;
}
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS)
}
int coap_message_option_add(CoAPMessage *message, unsigned num, unsigned len, const char *val)
{
IOT_FUNC_ENTRY
CoAPMsgOption * prev = NULL;
CoAPMsgOption * option = NULL;
CoAPMsgOptionList *list = &message->op_list;
if ((option = qcloud_iot_coap_option_init(num, len, val)) == NULL) {
Log_e("allocate new option failed.");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE)
}
if (list->first == NULL) {
/* empty list */
list->first = option;
list->last = option;
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS)
}
if (option->option_num < list->first->option_num) {
/* start of the list */
option->next = list->first;
list->first = option;
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS)
}
prev = list->first;
while (prev != list->last) {
/* middle of the list */
if ((prev->option_num <= option->option_num) && (option->option_num < prev->next->option_num)) {
option->next = prev->next;
prev->next = option;
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS)
}
prev = prev->next;
}
/* end of the list */
list->last->next = option;
list->last = option;
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS)
}
int coap_message_callback_set(CoAPMessage *message, OnRespCallback callback)
{
IOT_FUNC_ENTRY
message->handler = callback;
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS)
}
int coap_message_context_set(CoAPMessage *message, void *userContext)
{
IOT_FUNC_ENTRY
message->user_context = userContext;
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS)
}
CoAPMsgOption *qcloud_iot_coap_option_init(unsigned num, unsigned len, const char *val)
{
IOT_FUNC_ENTRY
CoAPMsgOption *option = NULL;
option = (CoAPMsgOption *)HAL_Malloc(sizeof(CoAPMsgOption));
if (option == NULL) {
Log_e("no space to malloc option");
return NULL;
}
option->option_num = num;
option->val_len = len;
option->val = (char *)HAL_Malloc(len);
if (option->val == NULL) {
HAL_Free(option);
option = NULL;
Log_e("no space to malloc option");
return NULL;
}
memcpy(option->val, val, len);
option->next = NULL;
return option;
}
void coap_message_destroy(CoAPMessage *message)
{
IOT_FUNC_ENTRY
_coap_msg_op_list_destroy(&message->op_list);
if (message->pay_load != NULL) {
HAL_Free(message->pay_load);
}
memset(message, 0, sizeof(CoAPMessage));
IOT_FUNC_EXIT
}
void coap_msg_dump(CoAPMessage *msg)
{
Log_i("msg->version = %u", msg->version);
Log_i("msg->type = %d", msg->type);
Log_i("msg->code_class = %u", msg->code_class);
Log_i("msg->code_detail = %u", msg->code_detail);
Log_i("msg->msg_id = %d", msg->msg_id);
Log_i("msg->pay_load_len = %d", msg->pay_load_len);
Log_i("msg->pay_load: %s", msg->pay_load);
Log_i("msg->token_len = %u", msg->token_len);
Log_i("msg->token: %s", msg->token);
return;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,387 @@
/*
* 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 <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "coap_client.h"
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "utils_param_check.h"
#define COAP_MSG_OPLIST_LAST(list) ((list)->last) /**< Get the last option in an option linked-list */
#define COAP_MSG_OPLIST_EMPTY(list) \
((list)->first == NULL) /**< Indicate whether or not an option linked-list is empty */
#define Swap16(A) ((((uint16_t)(A)&0xff00) >> 8) | (((uint16_t)(A)&0x00ff) << 8))
/**
* @brief Check a message for correctness
*
* The following checks from RFC7252 are performed:
*
* An Empty message has the Code field set to 0.00. The Token Length
* field MUST be set to 0 and bytes of data MUST NOT be present after
* the Message ID field. If there are any bytes, they MUST be processed
* as a message format error.
*
* The Reset message MUST echo the Message ID of the Confirmable message
* and MUST be Empty.
*
* A Non-confirmable message always carries either a request or response
* and MUST NOT be Empty.
*
* @param[in] msg Pointer to a message structure
* @returns Operation status
* @retval 0 Success
* @retval <0 Error
*/
static int _coap_msg_check(CoAPMessage *msg)
{
IOT_FUNC_ENTRY
if ((msg->code_class == 0) && (msg->code_detail == 0)) {
/* empty message */
if ((msg->type == COAP_MSG_NON) || (msg->token_len != 0) || (!COAP_MSG_OPLIST_EMPTY(&msg->op_list)) ||
(msg->pay_load_len != 0)) {
Log_e("coap msg op list is not empty");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
} else {
/* non-empty message */
if (msg->type == COAP_MSG_RST) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
}
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS)
}
/**
* @brief Allocate an option structure and add it to the end of an option linked-list structure
*
* @param[in,out] list Pointer to an option linked-list structure
* @param[in] num Option number
* @param[in] len Option length
* @param[in] val Pointer to a buffer containing the option value
*
* @returns Operation status
* @retval 0 Success
* @retval <0 Error
*/
static int _coap_msg_op_list_add_last(CoAPMsgOptionList *list, unsigned num, unsigned len, const char *val)
{
IOT_FUNC_ENTRY
CoAPMsgOption *option = NULL;
if ((option = qcloud_iot_coap_option_init(num, len, val)) == NULL) {
Log_e("allocate new option failed.");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE)
}
if (list->first == NULL) {
list->first = option;
list->last = option;
} else {
list->last->next = option;
list->last = option;
}
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS)
}
/**
* @brief Parse the header in a message
*
* @param[out] msg Pointer to a message structure
* @param[in] buf Pointer to a buffer containing the message
* @param[in] len Length of the buffer
*
* @returns Number of bytes parsed or error code
* @retval >0 Number of bytes parsed
* @retval <0 Error
*/
static ssize_t _coap_message_deserialize_header(CoAPMessage *msg, char *buf, size_t len)
{
IOT_FUNC_ENTRY
char *p = buf;
if (len < 4) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
msg->version = (p[0] >> 6) & 0x03;
if (msg->version != COAP_MSG_VER) {
return -EINVAL;
}
msg->type = (p[0] >> 4) & 0x03;
msg->token_len = p[0] & 0x0f;
if (msg->token_len > sizeof(msg->token)) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
msg->code_detail = p[1] & 0x1f;
msg->code_class = (p[1] >> 5) & 0x07;
if ((msg->code_class != COAP_MSG_REQ) && (msg->code_class != COAP_MSG_SUCCESS) &&
(msg->code_class != COAP_MSG_CLIENT_ERR) && (msg->code_class != COAP_MSG_SERVER_ERR)) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_COAP_BADMSG)
}
msg->msg_id = Swap16(*((uint16_t *)(&p[2])));
p += 4;
IOT_FUNC_EXIT_RC(p - buf)
}
/**
* @brief Parse the token in a message
*
* @param[out] msg Pointer to a message structure
* @param[in] buf Pointer to a buffer containing the message
* @param[in] len Length of the buffer
*
* @returns Number of bytes parsed or error code
* @retval >0 Number of bytes parsed
* @retval <0 Error
*/
static ssize_t _coap_message_deserialize_token(CoAPMessage *msg, char *buf, size_t len)
{
IOT_FUNC_ENTRY
if (len < msg->token_len) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
memcpy(msg->token, buf, msg->token_len);
IOT_FUNC_EXIT_RC(msg->token_len)
}
/**
* @brief Parse an option in a message
*
* @param[in,out] msg Pointer to a message structure
* @param[in] buf Pointer to a buffer containing the message
* @param[in] len Length of the buffer
*
* @returns Number of bytes parsed or error code
* @retval >0 Number of bytes parsed
* @retval <0 Error
*/
static ssize_t _coap_message_deserialize_option(CoAPMessage *msg, char *buf, size_t len)
{
IOT_FUNC_ENTRY
CoAPMsgOption *prev = NULL;
unsigned op_delta = 0;
unsigned op_len = 0;
unsigned op_num = 0;
char * p = buf;
int ret = 0;
if (len < 1) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
op_delta = (p[0] >> 4) & 0x0f;
op_len = p[0] & 0x0f;
if ((op_delta == 15) || (op_len == 15)) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
p++;
len--;
if (op_delta == 13) {
if (len < 1) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
op_delta += p[0];
p++;
len--;
} else if (op_delta == 14) {
if (len < 2) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
op_delta = 269 + Swap16(*((uint16_t *)(&p[0])));
p += 2;
len -= 2;
}
if (op_len == 13) {
if (len < 1) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
op_len += p[0];
p++;
len--;
} else if (op_len == 14) {
if (len < 2) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
op_len = 269 + Swap16(*((uint16_t *)(&p[0])));
p += 2;
len -= 2;
}
if (len < op_len) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
prev = COAP_MSG_OPLIST_LAST(&msg->op_list);
if (prev == NULL) {
op_num = op_delta;
} else {
op_num = COAP_MSG_OPTION_NUM(prev) + op_delta;
}
ret = _coap_msg_op_list_add_last(&msg->op_list, op_num, op_len, p);
if (ret < 0) {
IOT_FUNC_EXIT_RC(ret)
}
p += op_len;
IOT_FUNC_EXIT_RC(p - buf)
}
/**
* @brief Parse the options in a message
*
* @param[in,out] msg Pointer to a message structure
* @param[in] buf Pointer to a buffer containing the message
* @param[in] len Length of the buffer
*
* @returns Number of bytes parsed or error code
* @retval >0 Number of bytes parsed
* @retval <0 Error
*/
static ssize_t _coap_message_deserialize_options(CoAPMessage *msg, char *buf, size_t len)
{
IOT_FUNC_ENTRY
ssize_t num = 0;
char * p = buf;
while (1) {
if (((p[0] & 0xff) == 0xff) || (len == 0)) {
break;
}
num = _coap_message_deserialize_option(msg, p, len);
if (num < 0) {
return num;
}
p += num;
len -= num;
}
IOT_FUNC_EXIT_RC(p - buf)
}
/**
* @brief Parse the payload in a message
*
* @param[out] msg Pointer to a message structure
* @param[in] buf Pointer to a buffer containing the message
* @param[in] len Length of the buffer
*
* @returns Number of bytes parsed or error code
* @retval >0 Number of bytes parsed
* @retval <0 Error
*/
static ssize_t _coap_message_deserialize_payload(CoAPMessage *msg, char *buf, size_t len)
{
IOT_FUNC_ENTRY
char *p = buf;
if (len == 0) {
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS)
}
if ((p[0] & 0xff) != 0xff) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
p++;
len--;
if (len == 0) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
msg->pay_load = (char *)HAL_Malloc(len);
if (msg->pay_load == NULL) {
return -ENOMEM;
}
memcpy(msg->pay_load, p, len);
msg->pay_load_len = len;
p += len;
IOT_FUNC_EXIT_RC(p - buf)
}
ssize_t deserialize_coap_message(CoAPMessage *message, char *buf, size_t len)
{
IOT_FUNC_ENTRY
ssize_t num = 0;
char * p = buf;
num = _coap_message_deserialize_header(message, p, len);
if (num < 0) {
Log_e("coap_message_deserialize_header failed, num:%lu", num);
coap_message_destroy(message);
goto error;
}
p += num;
len -= num;
num = _coap_message_deserialize_token(message, p, len);
if (num < 0) {
Log_e("coap_message_deserialize_token failed, num:%lu", num);
coap_message_destroy(message);
goto error;
}
p += num;
len -= num;
num = _coap_message_deserialize_options(message, p, len);
if (num < 0) {
Log_e("coap_message_deserialize_options failed, num:%lu", num);
coap_message_destroy(message);
goto error;
}
p += num;
len -= num;
num = _coap_message_deserialize_payload(message, p, len);
if (num < 0) {
Log_e("coap_message_deserialize_payload failed, num:%lu", num);
coap_message_destroy(message);
goto error;
}
IOT_FUNC_EXIT_RC(_coap_msg_check(message))
error:
IOT_FUNC_EXIT_RC(QCLOUD_ERR_COAP_INTERNAL)
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,418 @@
/*
* 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 <string.h>
#include "coap_client.h"
#include "coap_client_net.h"
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "utils_param_check.h"
#include "utils_timer.h"
#define PROCESS_ACK_CMD (0)
#define PROCESS_PIGGY_CMD (1)
#define PROCESS_RESP_CMD (2)
#define PROCESS_WAIT_CMD (3)
static void _event_message_type_set(CoAPEventMessage *eventMsg, CoAPMessage *message, uint16_t processCmd)
{
if (message->code_class == COAP_MSG_SUCCESS && message->code_detail == COAP_MSG_CODE_205_CONTENT) {
eventMsg->event_type = processCmd == PROCESS_RESP_CMD ? COAP_EVENT_RECEIVE_RESPCONTENT : COAP_EVENT_RECEIVE_ACK;
} else if (message->code_class == COAP_MSG_CLIENT_ERR && message->code_detail == COAP_MSG_CODE_401_UNAUTHORIZED) {
eventMsg->event_type = COAP_EVENT_UNAUTHORIZED;
Log_e("coap messagefailed, message id: %d, failure reason: %d.%d", message->msg_id, message->code_class,
message->code_detail);
} else if (message->code_class == COAP_MSG_CLIENT_ERR && message->code_detail == COAP_MSG_CODE_403_FORBIDDEN) {
eventMsg->event_type = COAP_EVENT_FORBIDDEN;
Log_e("coap message failed, message id: %d, failure reason: %d.%d", message->msg_id, message->code_class,
message->code_detail);
} else {
eventMsg->event_type = COAP_EVENT_INTERNAL_SERVER_ERROR;
Log_e("coap message failed, message id: %d, failure reason: %d.%d", message->msg_id, message->code_class,
message->code_detail);
}
}
static int _coap_message_list_proc(CoAPClient *client, CoAPMessage *message, uint16_t processCmd)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
HAL_MutexLock(client->lock_list_wait_ack);
if (client->message_list->len <= 0) {
HAL_MutexUnlock(client->lock_list_wait_ack);
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
ListIterator * iter;
ListNode * node = NULL;
ListNode * temp_node = NULL;
CoAPMsgSendInfo *send_info = NULL;
if ((iter = list_iterator_new(client->message_list, LIST_TAIL)) == NULL) {
HAL_MutexUnlock(client->lock_list_wait_ack);
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
for (;;) {
node = list_iterator_next(iter);
if (NULL != temp_node) {
list_remove(client->message_list, temp_node);
Log_i("remove node");
temp_node = NULL;
}
if (NULL == node) {
break;
}
send_info = (CoAPMsgSendInfo *)node->val;
if (NULL == send_info) {
Log_e("node's value is invalid!");
continue;
}
if (processCmd == PROCESS_ACK_CMD) {
if (send_info->msg_id == message->msg_id) {
send_info->acked = 1; /* ACK is received */
InitTimer(&send_info->start_time);
countdown_ms(&send_info->start_time, client->command_timeout_ms);
}
} else if (processCmd == PROCESS_RESP_CMD) {
if (0 != send_info->token_len && send_info->token_len == message->token_len &&
0 == memcmp(send_info->token, message->token, message->token_len)) {
message->user_context = send_info->user_context;
if (send_info->handler != NULL) {
send_info->handler(message, send_info->user_context);
} else if (NULL != client->event_handle.h_fp) { // event handle process
CoAPEventMessage event_msg = {0};
_event_message_type_set(&event_msg, message, processCmd);
event_msg.message = message;
message->msg_id = send_info->msg_id;
client->event_handle.h_fp(client->event_handle.context, &event_msg);
} else {
Log_e("nether response callback nor event callback is set");
}
Log_d("remove the message id %d from list", send_info->msg_id);
send_info->node_state = COAP_NODE_STATE_INVALID;
}
} else if (processCmd == PROCESS_PIGGY_CMD) {
if (send_info->msg_id == message->msg_id) {
message->user_context = send_info->user_context;
if (send_info->handler != NULL) {
send_info->handler(message, send_info->user_context);
} else if (NULL != client->event_handle.h_fp) { // event handle process
CoAPEventMessage event_msg = {0};
_event_message_type_set(&event_msg, message, processCmd);
event_msg.message = (void *)(uintptr_t)(message->msg_id);
client->event_handle.h_fp(client->event_handle.context, &event_msg);
} else {
Log_e("nether response callback nor event callback is set");
}
Log_d("remove the message id %d from list", send_info->msg_id);
send_info->acked = 1; /* ACK is received */
send_info->node_state = COAP_NODE_STATE_INVALID;
}
} else if (processCmd == PROCESS_WAIT_CMD) {
if (COAP_NODE_STATE_INVALID == send_info->node_state) {
temp_node = node;
continue;
}
if (left_ms(&send_info->start_time) > 0) {
continue;
}
if (send_info->retrans_count < client->max_retry_count && (0 == send_info->acked)) {
InitTimer(&send_info->start_time);
countdown_ms(&send_info->start_time, client->command_timeout_ms);
send_info->retrans_count++;
Log_d("start to retansmit the message id %d len %d", send_info->msg_id, send_info->msglen);
size_t written_len = 0;
int ret = client->network_stack.write(&client->network_stack, send_info->message, send_info->msglen,
left_ms(&send_info->start_time), &written_len);
if (ret != QCLOUD_RET_SUCCESS) {
Log_e("retansmit the message id %d failed.", send_info->msg_id, send_info->msglen);
continue;
}
} else {
send_info->node_state = COAP_NODE_STATE_INVALID;
temp_node = node;
if (send_info->handler != NULL) {
message->type = COAP_MSG_ACK;
message->user_context = send_info->user_context;
message->code_class = COAP_MSG_SDKINTERNAL_ERR;
message->code_detail = COAP_MSG_CODE_600_TIMEOUT;
message->msg_id = send_info->msg_id;
send_info->handler(message, send_info->user_context);
} else if (NULL != client->event_handle.h_fp) {
CoAPEventMessage event_msg = {0};
if (send_info->acked) {
event_msg.event_type = COAP_EVENT_SEPRESP_TIMEOUT;
} else {
event_msg.event_type = COAP_EVENT_ACK_TIMEOUT;
}
event_msg.message = (void *)(uintptr_t)(send_info->msg_id);
client->event_handle.h_fp(client->event_handle.context, &event_msg);
} else {
Log_e("nether response callback nor event callback is set");
}
continue;
}
}
}
list_iterator_destroy(iter);
HAL_MutexUnlock(client->lock_list_wait_ack);
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
/**
* @brief Send ACK to server
*
* @param client reference to CoAP client
* @param msgId msg Id
*
* @returns Operation status
* @retval 0 Success
* @retval <0 Error
*/
static int _coap_client_send_ack(CoAPClient *client, int msgId)
{
IOT_FUNC_ENTRY
CoAPMessage ack = DEFAULT_COAP_MESSAGE;
int ret = 0;
if ((ret = coap_message_type_set(&ack, COAP_MSG_ACK)) != QCLOUD_RET_SUCCESS) {
coap_message_destroy(&ack);
IOT_FUNC_EXIT_RC(ret)
}
if ((ret = coap_message_id_set(&ack, msgId)) != QCLOUD_RET_SUCCESS) {
coap_message_destroy(&ack);
IOT_FUNC_EXIT_RC(ret)
}
ret = coap_message_send(client, &ack);
coap_message_destroy(&ack);
IOT_FUNC_EXIT_RC(ret)
}
static int _coap_piggyresp_message_handle(CoAPClient *client, CoAPMessage *message)
{
IOT_FUNC_ENTRY
int rc = _coap_message_list_proc(client, message, PROCESS_PIGGY_CMD);
IOT_FUNC_EXIT_RC(rc)
}
static int _coap_ack_message_handle(CoAPClient *client, CoAPMessage *message)
{
IOT_FUNC_ENTRY
int rc = _coap_message_list_proc(client, message, PROCESS_ACK_CMD);
IOT_FUNC_EXIT_RC(rc)
}
static int _coap_resp_message_handle(CoAPClient *client, CoAPMessage *message)
{
IOT_FUNC_ENTRY
int rc = 0;
if (COAP_MSG_CON == message->type) {
rc = _coap_client_send_ack(client, message->msg_id);
Log_d("send ack message for id: %d rc: %d", message->msg_id, rc);
}
rc = _coap_message_list_proc(client, message, PROCESS_RESP_CMD);
IOT_FUNC_EXIT_RC(rc)
}
static void _coap_message_handle(CoAPClient *client, unsigned char *buf, unsigned short datalen)
{
IOT_FUNC_ENTRY
int rc = QCLOUD_RET_SUCCESS;
CoAPMessage recv_message;
memset(&recv_message, 0x00, sizeof(CoAPMessage));
if ((rc = deserialize_coap_message(&recv_message, (char *)buf, datalen)) != QCLOUD_RET_SUCCESS) {
Log_e("deserialize message failed: %d", rc);
}
if (recv_message.type == COAP_MSG_ACK && COAP_MSG_IS_EMPTY_ACK(&recv_message)) { // empty ACK
Log_d("receive coap ACK message, id %d", recv_message.msg_id);
_coap_ack_message_handle(client, &recv_message);
} else if (recv_message.type == COAP_MSG_ACK && !COAP_MSG_IS_EMPTY(&recv_message)) { // piggy Response
Log_d("receive coap piggy ACK message, id %d", recv_message.msg_id);
_coap_piggyresp_message_handle(client, &recv_message);
} else if (recv_message.type == COAP_MSG_CON && COAP_MSG_IS_EMPTY_RSP(&recv_message)) { // payload Response
Log_d("receive coap response message, id: %d", recv_message.msg_id);
_coap_resp_message_handle(client, &recv_message);
} else if (recv_message.type == COAP_MSG_NON && COAP_MSG_IS_EMPTY_RSP(&recv_message)) { // payload Response
Log_d("receive coap response message, id: %d", recv_message.msg_id);
_coap_resp_message_handle(client, &recv_message);
} else {
Log_e("not recgonized recv message type");
}
if (recv_message.pay_load != NULL) {
HAL_Free(recv_message.pay_load);
recv_message.pay_load_len = 0;
}
IOT_FUNC_EXIT
}
static int _coap_message_list_add(CoAPClient *client, CoAPMessage *message, int len)
{
IOT_FUNC_ENTRY
CoAPMsgSendInfo *send_info = (CoAPMsgSendInfo *)HAL_Malloc(sizeof(CoAPMsgSendInfo));
if (send_info == NULL) {
Log_e("no memory to malloc SendInfo");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE)
}
send_info->node_state = COAP_NODE_STATE_NORMANL;
send_info->acked = 0;
send_info->user_context = message->user_context;
send_info->msg_id = message->msg_id;
send_info->handler = message->handler;
send_info->msglen = len;
if (COAP_MSG_CON == message->type) {
send_info->retrans_count = 0;
InitTimer(&send_info->start_time);
countdown_ms(&send_info->start_time, client->command_timeout_ms);
} else {
}
send_info->token_len = message->token_len;
memcpy(send_info->token, message->token, message->token_len);
send_info->message = (unsigned char *)HAL_Malloc(len);
if (NULL != send_info->message) {
memcpy(send_info->message, client->send_buf, len);
}
ListNode *node = list_node_new(send_info);
if (NULL == node) {
Log_e("run list_node_new is error!");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE)
}
HAL_MutexLock(client->lock_list_wait_ack);
list_rpush(client->message_list, node);
HAL_MutexUnlock(client->lock_list_wait_ack);
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS)
}
int coap_message_cycle(CoAPClient *client, uint32_t timeout_ms)
{
POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
int rc = coap_message_recv(client, timeout_ms);
if (rc != QCLOUD_RET_SUCCESS && rc != QCLOUD_ERR_SSL_READ_TIMEOUT) {
IOT_FUNC_EXIT_RC(rc)
}
CoAPMessage message = DEFAULT_COAP_MESSAGE;
rc = _coap_message_list_proc(client, &message, PROCESS_WAIT_CMD);
IOT_FUNC_EXIT_RC(rc)
}
ssize_t coap_message_send(CoAPClient *client, CoAPMessage *message)
{
IOT_FUNC_ENTRY
ssize_t ret;
size_t written_len = 0;
HAL_MutexLock(client->lock_send_buf);
if ((ret = serialize_coap_message(message, (char *)client->send_buf, client->send_buf_size)) < 0) {
Log_e("failed to serialize coap message");
HAL_MutexUnlock(client->lock_send_buf);
IOT_FUNC_EXIT_RC(ret)
}
ret = client->network_stack.write(&client->network_stack, client->send_buf, ret, 0, &written_len);
if (ret == QCLOUD_RET_SUCCESS) {
if (message->type == COAP_MSG_CON && message->code_class == COAP_MSG_REQ) {
ret = _coap_message_list_add(client, message, written_len);
Log_i("add coap message id: %d into wait list ret: %d", message->msg_id, ret);
} else {
Log_i("The message doesn't need to be retransmitted");
}
} else {
Log_e("coap net fail to write rc: %d", ret);
}
HAL_MutexUnlock(client->lock_send_buf);
IOT_FUNC_EXIT_RC(ret)
}
ssize_t coap_message_recv(CoAPClient *client, uint32_t timeout_ms)
{
IOT_FUNC_ENTRY
size_t read_lean = 0;
int rc = 0;
rc = client->network_stack.read(&client->network_stack, client->recv_buf, client->read_buf_size, timeout_ms,
&read_lean);
switch (rc) {
case QCLOUD_RET_SUCCESS:
_coap_message_handle(client, client->recv_buf, read_lean);
break;
case QCLOUD_ERR_SSL_READ_TIMEOUT:
break;
default:
break;
}
IOT_FUNC_EXIT_RC(rc)
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,41 @@
/*
* 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 "coap_client_net.h"
#include "network_interface.h"
int qcloud_iot_coap_network_init(Network *pNetwork)
{
int rc;
/* first choice: TLS */
pNetwork->type = NETWORK_DTLS;
#ifdef AUTH_WITH_NOTLS
pNetwork->type = NETWORK_UDP;
#endif
rc = network_init(pNetwork);
return rc;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,292 @@
/*
* 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 <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "coap_client.h"
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "utils_param_check.h"
#define COAP_MSG_OPLIST_FIRST(list) ((list)->first) /**< Get the first option from an option linked-list */
/**
* @brief Format the header in a message
*
* @param[in] message Pointer to a message structure
* @param[out] buf Pointer to a buffer to contain the formatted message
* @param[in] len Length of the buffer
*
* @returns Length of the formatted message or error code
* @retval >0 Length of the formatted message
* @retval <0 Error
*/
static ssize_t _coap_message_serialize_header(CoAPMessage *message, char *buf, size_t len)
{
IOT_FUNC_ENTRY
if (len < 4) {
return -ENOSPC;
}
buf[0] = (char)((COAP_MSG_VER << 6) | ((message->type & 0x03) << 4) | (message->token_len & 0x0f));
buf[1] = (char)(((message->code_class & 0x07) << 5) | (message->code_detail & 0x1f));
buf[2] = (message->msg_id & 0xFF00) >> 8;
buf[3] = (message->msg_id & 0x00FF);
IOT_FUNC_EXIT_RC(4)
}
/**
* @brief Format the token in a message
*
* @param[in] message Pointer to a message structure
* @param[out] buf Pointer to a buffer to contain the formatted message
* @param[in] len Length of the buffer
*
* @returns Length of the formatted message or error code
* @retval >0 Length of the formatted message
* @retval <0 Error
*/
static ssize_t _coap_message_serialize_token(CoAPMessage *message, char *buf, size_t len)
{
IOT_FUNC_ENTRY
if (len < message->token_len) {
return -ENOSPC;
}
memcpy(buf, message->token, message->token_len);
IOT_FUNC_EXIT_RC(message->token_len)
}
/**
* @brief Format an option in a message
*
* @param[in] op Pointer to an option structure
* @param[in] prev_num option number of the previous option
* @param[out] buf Pointer to a buffer to contain the formatted message
* @param[in] len Length of the buffer
*
* @returns Length of the formatted message or error code
* @retval >0 Length of the formatted message
* @retval <0 Error
*/
static ssize_t _coap_msg_format_op(CoAPMsgOption *op, unsigned prev_num, char *buf, size_t len)
{
IOT_FUNC_ENTRY
unsigned short op_delta = 0;
unsigned num = 0;
char * p = buf;
op_delta = op->option_num - prev_num;
num++;
/* option delta */
if (op_delta >= 269) {
num += 2;
} else if (op_delta >= 13) {
num += 1;
}
/* option length */
if (op->val_len >= 269) {
num += 2;
} else if (op->option_num >= 13) {
num += 1;
}
/* option value */
num += op->val_len;
if (num > len) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
/* option delta */
if (op_delta >= 269) {
p[0] = 14 << 4;
} else if (op_delta >= 13) {
p[0] = 13 << 4;
} else {
p[0] = op_delta << 4;
}
/* option length */
if (op->val_len >= 269) {
p[0] |= 14;
} else if (op->val_len >= 13) {
p[0] |= 13;
} else {
p[0] |= op->val_len;
}
p++;
len--;
/* option delta extended */
if (op_delta >= 269) {
*p = (unsigned char)(((op_delta - 269) & 0xFF00) >> 8);
*(p + 1) = (unsigned char)(((op_delta - 269) & 0x00FF));
p += 2;
len -= 2;
} else if (op_delta >= 13) {
p[0] = op_delta - 13;
p++;
len--;
}
/* option length extended */
if (op->val_len >= 269) {
*p = (unsigned char)(((op->val_len - 269) & 0xFF00) >> 8);
*(p + 1) = (unsigned char)(((op->val_len - 269) & 0x00FF));
p += 2;
len -= 2;
} else if (op->val_len >= 13) {
p[0] = op->val_len - 13;
p++;
len--;
}
/* option value */
memcpy(p, op->val, op->val_len);
p += op->val_len;
IOT_FUNC_EXIT_RC(p - buf)
}
/**
* @brief Format the options in a message
*
* @param[in] message Pointer to a message structure
* @param[out] buf Pointer to a buffer to contain the formatted message
* @param[in] len Length of the buffer
*
* @returns Length of the formatted message or error code
* @retval >0 Length of the formatted message
* @retval <0 Error
*/
static ssize_t _coap_message_serialize_options(CoAPMessage *message, char *buf, size_t len)
{
IOT_FUNC_ENTRY;
CoAPMsgOption *op = NULL;
unsigned prev_num = 0;
ssize_t num = 0;
char * p = buf;
op = COAP_MSG_OPLIST_FIRST(&message->op_list);
while (op != NULL) {
num = _coap_msg_format_op(op, prev_num, p, len);
if (num < 0) {
return num;
}
p += num;
len -= num;
prev_num = COAP_MSG_OPTION_NUM(op);
op = COAP_MSG_OP_NEXT(op);
}
IOT_FUNC_EXIT_RC(p - buf)
}
/**
* @brief Format the payload in a message
*
* @param[in] message Pointer to a message structure
* @param[out] buf Pointer to a buffer to contain the formatted message
* @param[in] len Length of the buffer
*
* @returns Length of the formatted message or error code
* @retval >0 Length of the formatted message
* @retval <0 Error
*/
static ssize_t _coap_message_serialize_payload(CoAPMessage *message, char *buf, size_t len)
{
IOT_FUNC_ENTRY;
if (message->pay_load_len == 0) {
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS)
}
if (message->pay_load_len + 1 > len) {
return -ENOSPC;
}
buf[0] = 0xff;
memcpy(&buf[1], message->pay_load, message->pay_load_len);
IOT_FUNC_EXIT_RC(message->pay_load_len + 1)
}
ssize_t serialize_coap_message(CoAPMessage *message, char *buf, size_t len)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(message, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL);
ssize_t num = 0;
char * p = buf;
num = _coap_message_serialize_header(message, p, len);
if (num < 0) {
Log_e("coap_message_serialize_header fail num=%lu", num);
goto error;
}
p += num;
len -= num;
num = _coap_message_serialize_token(message, p, len);
if (num < 0) {
Log_e("coap_message_serialize_token fail num=%lu", num);
goto error;
}
p += num;
len -= num;
num = _coap_message_serialize_options(message, p, len);
if (num < 0) {
Log_e("coap_message_serialize_options fail num=%lu", num);
goto error;
}
p += num;
len -= num;
num = _coap_message_serialize_payload(message, p, len);
if (num < 0) {
Log_e("coap_message_serialize_payload fail num=%lu", num);
goto error;
}
p += num;
IOT_FUNC_EXIT_RC(p - buf)
error:
IOT_FUNC_EXIT_RC(QCLOUD_ERR_COAP_INTERNAL)
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,796 @@
/*
* 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 "utils_httpc.h"
#include <ctype.h>
#include <string.h>
#include "qcloud_iot_ca.h"
#include "qcloud_iot_common.h"
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "utils_timer.h"
#define HTTP_CLIENT_MIN(x, y) (((x) < (y)) ? (x) : (y))
#define HTTP_CLIENT_MAX(x, y) (((x) > (y)) ? (x) : (y))
#define HTTP_CLIENT_AUTHB_SIZE 128
#define HTTP_CLIENT_CHUNK_SIZE 1024
#define HTTP_CLIENT_SEND_BUF_SIZE 1024
#define HTTP_CLIENT_MAX_HOST_LEN 64
#define HTTP_CLIENT_MAX_URL_LEN 1024
#define HTTP_RETRIEVE_MORE_DATA (1)
#if defined(MBEDTLS_DEBUG_C)
#define DEBUG_LEVEL 2
#endif
static void _http_client_base64enc(char *out, const char *in)
{
const char code[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
int i = 0, x = 0, l = 0;
for (; *in; in++) {
x = x << 8 | *in;
for (l += 8; l >= 6; l -= 6) {
out[i++] = code[(x >> (l - 6)) & 0x3f];
}
}
if (l > 0) {
x <<= 6 - l;
out[i++] = code[x & 0x3f];
}
for (; i % 4;) {
out[i++] = '=';
}
out[i] = '\0';
}
static int _http_client_parse_url(const char *url, char *scheme, uint32_t max_scheme_len, char *host,
uint32_t maxhost_len, int *port, char *path, uint32_t max_path_len)
{
char * scheme_ptr = (char *)url;
char * host_ptr = (char *)strstr(url, "://");
uint32_t host_len = 0;
uint32_t path_len;
char *path_ptr;
char *fragment_ptr;
if (host_ptr == NULL) {
Log_e("Could not find host");
return QCLOUD_ERR_HTTP_PARSE;
}
if (max_scheme_len < host_ptr - scheme_ptr + 1) {
Log_e("Scheme str is too small (%u >= %u)", max_scheme_len, (uint32_t)(host_ptr - scheme_ptr + 1));
return QCLOUD_ERR_HTTP_PARSE;
}
memcpy(scheme, scheme_ptr, host_ptr - scheme_ptr);
scheme[host_ptr - scheme_ptr] = '\0';
host_ptr += 3;
*port = 0;
path_ptr = strchr(host_ptr, '/');
if (NULL == path_ptr) {
path_ptr = scheme_ptr + (int)strlen(url);
host_len = path_ptr - host_ptr;
memcpy(host, host_ptr, host_len);
host[host_len] = '\0';
memcpy(path, "/", 1);
path[1] = '\0';
return QCLOUD_RET_SUCCESS;
}
if (host_len == 0) {
host_len = path_ptr - host_ptr;
}
if (maxhost_len < host_len + 1) {
Log_e("Host str is too long (host_len(%d) >= max_len(%d))", host_len + 1, maxhost_len);
return QCLOUD_ERR_HTTP_PARSE;
}
memcpy(host, host_ptr, host_len);
host[host_len] = '\0';
fragment_ptr = strchr(host_ptr, '#');
if (fragment_ptr != NULL) {
path_len = fragment_ptr - path_ptr;
} else {
path_len = strlen(path_ptr);
}
if (max_path_len < path_len + 1) {
Log_e("Path str is too small (%d >= %d)", max_path_len, path_len + 1);
return QCLOUD_ERR_HTTP_PARSE;
}
memcpy(path, path_ptr, path_len);
path[path_len] = '\0';
return QCLOUD_RET_SUCCESS;
}
static int _http_client_parse_host(const char *url, char *host, uint32_t host_max_len)
{
const char *host_ptr = (const char *)strstr(url, "://");
uint32_t host_len = 0;
char * path_ptr;
if (host_ptr == NULL) {
Log_e("Could not find host");
return QCLOUD_ERR_HTTP_PARSE;
}
host_ptr += 3;
uint32_t pro_len = 0;
pro_len = host_ptr - url;
path_ptr = strchr(host_ptr, '/');
if (path_ptr != NULL)
host_len = path_ptr - host_ptr;
else
host_len = strlen(url) - pro_len;
if (host_max_len < host_len + 1) {
Log_e("Host str is too small (%d >= %d)", host_max_len, host_len + 1);
return QCLOUD_ERR_HTTP_PARSE;
}
memcpy(host, host_ptr, host_len);
host[host_len] = '\0';
return QCLOUD_RET_SUCCESS;
}
static int _http_client_get_info(HTTPClient *client, unsigned char *send_buf, int *send_idx, char *buf, uint32_t len)
{
int rc = QCLOUD_RET_SUCCESS;
int cp_len;
int idx = *send_idx;
if (len == 0) {
len = strlen(buf);
}
do {
if ((HTTP_CLIENT_SEND_BUF_SIZE - idx) >= len) {
cp_len = len;
} else {
cp_len = HTTP_CLIENT_SEND_BUF_SIZE - idx;
}
memcpy(send_buf + idx, buf, cp_len);
idx += cp_len;
len -= cp_len;
if (idx == HTTP_CLIENT_SEND_BUF_SIZE) {
size_t byte_written_len = 0;
rc = client->network_stack.write(&(client->network_stack), send_buf, HTTP_CLIENT_SEND_BUF_SIZE, 5000,
&byte_written_len);
if (byte_written_len) {
return (byte_written_len);
}
}
} while (len);
*send_idx = idx;
return rc;
}
static int _http_client_send_auth(HTTPClient *client, unsigned char *send_buf, int *send_idx)
{
char b_auth[(int)((HTTP_CLIENT_AUTHB_SIZE + 3) * 4 / 3 + 1)];
char base64buff[HTTP_CLIENT_AUTHB_SIZE + 3];
_http_client_get_info(client, send_buf, send_idx, "Authorization: Basic ", 0);
HAL_Snprintf(base64buff, sizeof(base64buff), "%s:%s", client->auth_user, client->auth_password);
_http_client_base64enc(b_auth, base64buff);
b_auth[strlen(b_auth) + 1] = '\0';
b_auth[strlen(b_auth)] = '\n';
_http_client_get_info(client, send_buf, send_idx, b_auth, 0);
return QCLOUD_RET_SUCCESS;
}
static int _http_client_send_header(HTTPClient *client, const char *url, HttpMethod method, HTTPClientData *client_data)
{
char scheme[8] = {0};
char host[HTTP_CLIENT_MAX_HOST_LEN] = {0};
char path[HTTP_CLIENT_MAX_URL_LEN] = {0};
int len;
unsigned char send_buf[HTTP_CLIENT_SEND_BUF_SIZE] = {0};
char buf[HTTP_CLIENT_SEND_BUF_SIZE] = {0};
char * meth = (method == HTTP_GET)
? "GET"
: (method == HTTP_POST)
? "POST"
: (method == HTTP_PUT)
? "PUT"
: (method == HTTP_DELETE) ? "DELETE" : (method == HTTP_HEAD) ? "HEAD" : "";
int rc;
int port;
int res = _http_client_parse_url(url, scheme, sizeof(scheme), host, sizeof(host), &port, path, sizeof(path));
if (res != QCLOUD_RET_SUCCESS) {
Log_e("httpclient_parse_url returned %d", res);
return res;
}
if (strcmp(scheme, "http") == 0) {
} else if (strcmp(scheme, "https") == 0) {
}
memset(send_buf, 0, HTTP_CLIENT_SEND_BUF_SIZE);
len = 0;
HAL_Snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\nHost: %s\r\n", meth, path, host);
rc = _http_client_get_info(client, send_buf, &len, buf, strlen(buf));
if (rc) {
Log_e("Could not write request");
return QCLOUD_ERR_HTTP_CONN;
}
if (client->auth_user) {
_http_client_send_auth(client, send_buf, &len);
}
if (client->header) {
_http_client_get_info(client, send_buf, &len, (char *)client->header, strlen(client->header));
}
if (client_data->post_buf != NULL) {
HAL_Snprintf(buf, sizeof(buf), "Content-Length: %d\r\n", client_data->post_buf_len);
_http_client_get_info(client, send_buf, &len, buf, strlen(buf));
if (client_data->post_content_type != NULL) {
HAL_Snprintf(buf, sizeof(buf), "Content-Type: %s\r\n", client_data->post_content_type);
_http_client_get_info(client, send_buf, &len, buf, strlen(buf));
}
}
_http_client_get_info(client, send_buf, &len, "\r\n", 0);
// Log_d("REQUEST:\n%s", send_buf);
size_t written_len = 0;
rc = client->network_stack.write(&client->network_stack, send_buf, len, 5000, &written_len);
if (written_len > 0) {
// Log_d("Written %lu bytes", written_len);
} else if (written_len == 0) {
Log_e("written_len == 0,Connection was closed by server");
return QCLOUD_ERR_HTTP_CLOSED; /* Connection was closed by server */
} else {
Log_e("Connection error (send returned %d)", rc);
return QCLOUD_ERR_HTTP_CONN;
}
return QCLOUD_RET_SUCCESS;
}
static int _http_client_send_userdata(HTTPClient *client, HTTPClientData *client_data)
{
if (client_data->post_buf && client_data->post_buf_len) {
// Log_d("client_data->post_buf: %s", client_data->post_buf);
{
size_t written_len = 0;
int rc = client->network_stack.write(&client->network_stack, (unsigned char *)client_data->post_buf,
client_data->post_buf_len, 5000, &written_len);
if (written_len > 0) {
// Log_d("Written %d bytes", written_len);
} else if (written_len == 0) {
Log_e("written_len == 0,Connection was closed by server");
return QCLOUD_ERR_HTTP_CLOSED;
} else {
Log_e("Connection error (send returned %d)", rc);
return QCLOUD_ERR_HTTP_CONN;
}
}
}
return QCLOUD_RET_SUCCESS;
}
static int _http_client_recv(HTTPClient *client, char *buf, int min_len, int max_len, int *p_read_len,
uint32_t timeout_ms, HTTPClientData *client_data)
{
IOT_FUNC_ENTRY;
int rc = 0;
Timer timer;
size_t recv_size = 0;
InitTimer(&timer);
countdown_ms(&timer, (unsigned int)timeout_ms);
*p_read_len = 0;
rc = client->network_stack.read(&client->network_stack, (unsigned char *)buf, max_len, (uint32_t)left_ms(&timer),
&recv_size);
*p_read_len = (int)recv_size;
if (rc == QCLOUD_ERR_SSL_NOTHING_TO_READ || rc == QCLOUD_ERR_TCP_NOTHING_TO_READ) {
Log_d("HTTP read nothing and timeout");
rc = QCLOUD_RET_SUCCESS;
} else if (rc == QCLOUD_ERR_SSL_READ_TIMEOUT || rc == QCLOUD_ERR_TCP_READ_TIMEOUT) {
if (*p_read_len == client_data->retrieve_len || client_data->retrieve_len == 0)
rc = QCLOUD_RET_SUCCESS;
else
Log_e("network_stack read timeout");
} else if (rc == QCLOUD_ERR_TCP_PEER_SHUTDOWN && *p_read_len > 0) {
/* HTTP server give response and close this connection */
client->network_stack.disconnect(&client->network_stack);
rc = QCLOUD_RET_SUCCESS;
} else if (rc != QCLOUD_RET_SUCCESS) {
Log_e("Connection error rc = %d (recv returned %d)", rc, *p_read_len);
IOT_FUNC_EXIT_RC(rc);
}
// IOT_FUNC_EXIT_RC(rc);
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
static int _http_client_retrieve_content(HTTPClient *client, char *data, int len, uint32_t timeout_ms,
HTTPClientData *client_data)
{
IOT_FUNC_ENTRY;
int count = 0;
int templen = 0;
int crlf_pos;
Timer timer;
InitTimer(&timer);
countdown_ms(&timer, (unsigned int)timeout_ms);
client_data->is_more = IOT_TRUE;
if (client_data->response_content_len == -1 && client_data->is_chunked == IOT_FALSE) {
while (1) {
int rc, max_len;
if (count + len < client_data->response_buf_len - 1) {
memcpy(client_data->response_buf + count, data, len);
count += len;
client_data->response_buf[count] = '\0';
} else {
memcpy(client_data->response_buf + count, data, client_data->response_buf_len - 1 - count);
client_data->response_buf[client_data->response_buf_len - 1] = '\0';
return HTTP_RETRIEVE_MORE_DATA;
}
max_len = HTTP_CLIENT_MIN(HTTP_CLIENT_CHUNK_SIZE - 1, client_data->response_buf_len - 1 - count);
rc = _http_client_recv(client, data, 1, max_len, &len, (uint32_t)left_ms(&timer), client_data);
/* Receive data */
// Log_d("data len: %d %d", len, count);
if (rc != QCLOUD_RET_SUCCESS) {
IOT_FUNC_EXIT_RC(rc);
}
if (0 == left_ms(&timer)) {
Log_e("HTTP read timeout!");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP_TIMEOUT);
}
if (len == 0) {
/* read no more data */
Log_d("no more data, len == 0");
client_data->is_more = IOT_FALSE;
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
}
}
while (1) {
uint32_t readLen = 0;
if (client_data->is_chunked && client_data->retrieve_len <= 0) {
/* Read chunk header */
bool foundCrlf;
int n;
do {
foundCrlf = IOT_FALSE;
crlf_pos = 0;
data[len] = 0;
if (len >= 2) {
for (; crlf_pos < len - 2; crlf_pos++) {
if (data[crlf_pos] == '\r' && data[crlf_pos + 1] == '\n') {
foundCrlf = IOT_TRUE;
break;
}
}
}
if (!foundCrlf) {
/* Try to read more */
if (len < HTTP_CLIENT_CHUNK_SIZE) {
int new_trf_len, rc;
rc = _http_client_recv(client, data + len, 0, HTTP_CLIENT_CHUNK_SIZE - len - 1, &new_trf_len,
left_ms(&timer), client_data);
len += new_trf_len;
if (rc != QCLOUD_RET_SUCCESS) {
IOT_FUNC_EXIT_RC(rc);
} else {
continue;
}
} else {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP);
}
}
} while (!foundCrlf);
data[crlf_pos] = '\0';
// n = sscanf(data, "%x", &readLen);/* chunk length */
readLen = strtoul(data, NULL, 16);
n = (0 == readLen) ? 0 : 1;
client_data->retrieve_len = readLen;
client_data->response_content_len += client_data->retrieve_len;
if (readLen == 0) {
client_data->is_more = IOT_FALSE;
Log_d("no more (last chunk)");
}
if (n != 1) {
Log_e("Could not read chunk length");
return QCLOUD_ERR_HTTP_UNRESOLVED_DNS;
}
memmove(data, &data[crlf_pos + 2], len - (crlf_pos + 2));
len -= (crlf_pos + 2);
} else {
readLen = client_data->retrieve_len;
}
do {
templen = HTTP_CLIENT_MIN(len, readLen);
if (count + templen < client_data->response_buf_len - 1) {
memcpy(client_data->response_buf + count, data, templen);
count += templen;
client_data->response_buf[count] = '\0';
client_data->retrieve_len -= templen;
} else {
memcpy(client_data->response_buf + count, data, client_data->response_buf_len - 1 - count);
client_data->response_buf[client_data->response_buf_len - 1] = '\0';
client_data->retrieve_len -= (client_data->response_buf_len - 1 - count);
IOT_FUNC_EXIT_RC(HTTP_RETRIEVE_MORE_DATA);
}
if (len > readLen) {
Log_d("memmove %d %d %d\n", readLen, len, client_data->retrieve_len);
memmove(data, &data[readLen], len - readLen); /* chunk case, read between two chunks */
len -= readLen;
readLen = 0;
client_data->retrieve_len = 0;
} else {
readLen -= len;
}
if (readLen) {
int rc;
int max_len = HTTP_CLIENT_MIN(HTTP_CLIENT_CHUNK_SIZE - 1, client_data->response_buf_len - 1 - count);
max_len = HTTP_CLIENT_MIN(max_len, readLen);
rc = _http_client_recv(client, data, 1, max_len, &len, left_ms(&timer), client_data);
if (rc != QCLOUD_RET_SUCCESS) {
IOT_FUNC_EXIT_RC(rc);
}
if (left_ms(&timer) == 0) {
Log_e("HTTP read timeout!");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP_TIMEOUT);
}
}
} while (readLen);
if (client_data->is_chunked) {
if (len < 2) {
int new_trf_len, rc;
/* Read missing chars to find end of chunk */
rc = _http_client_recv(client, data + len, 2 - len, HTTP_CLIENT_CHUNK_SIZE - len - 1, &new_trf_len,
left_ms(&timer), client_data);
if ((rc != QCLOUD_RET_SUCCESS) || (0 == left_ms(&timer))) {
IOT_FUNC_EXIT_RC(rc);
}
len += new_trf_len;
}
if ((data[0] != '\r') || (data[1] != '\n')) {
Log_e("Format error, %s", data); /* after memmove, the beginning of next chunk */
IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP_UNRESOLVED_DNS);
}
memmove(data, &data[2], len - 2); /* remove the \r\n */
len -= 2;
} else {
// Log_d("no more (content-length)");
client_data->is_more = IOT_FALSE;
break;
}
}
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
static int _http_client_response_parse(HTTPClient *client, char *data, int len, uint32_t timeout_ms,
HTTPClientData *client_data)
{
IOT_FUNC_ENTRY;
int crlf_pos;
Timer timer;
char *tmp_ptr, *ptr_body_end;
InitTimer(&timer);
countdown_ms(&timer, timeout_ms);
client_data->response_content_len = -1;
char *crlf_ptr = strstr(data, "\r\n");
if (crlf_ptr == NULL) {
Log_e("\\r\\n not found");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP_UNRESOLVED_DNS);
}
crlf_pos = crlf_ptr - data;
data[crlf_pos] = '\0';
#if 0
if (sscanf(data, "HTTP/%*d.%*d %d %*[^\r\n]", &(client->response_code)) != 1) {
Log_e("Not a correct HTTP answer : %s\n", data);
return QCLOUD_ERR_HTTP_UNRESOLVED_DNS;
}
#endif
client->response_code = atoi(data + 9);
if ((client->response_code < 200) || (client->response_code >= 400)) {
Log_w("Response code %d", client->response_code);
if (client->response_code == 403)
IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP_AUTH);
if (client->response_code == 404)
IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP_NOT_FOUND);
}
// Log_d("Reading headers : %s", data);
// remove null character
memmove(data, &data[crlf_pos + 2], len - (crlf_pos + 2) + 1);
len -= (crlf_pos + 2);
client_data->is_chunked = IOT_FALSE;
if (NULL == (ptr_body_end = strstr(data, "\r\n\r\n"))) {
int new_trf_len, rc;
rc = _http_client_recv(client, data + len, 1, HTTP_CLIENT_CHUNK_SIZE - len - 1, &new_trf_len, left_ms(&timer),
client_data);
if (rc != QCLOUD_RET_SUCCESS) {
IOT_FUNC_EXIT_RC(rc);
}
len += new_trf_len;
data[len] = '\0';
if (NULL == (ptr_body_end = strstr(data, "\r\n\r\n"))) {
Log_e("parse error: no end of the request body");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
}
if (NULL != (tmp_ptr = strstr(data, "Content-Length"))) {
client_data->response_content_len = atoi(tmp_ptr + strlen("Content-Length: "));
client_data->retrieve_len = client_data->response_content_len;
} else if (NULL != (tmp_ptr = strstr(data, "Transfer-Encoding"))) {
int len_chunk = strlen("Chunked");
char *chunk_value = data + strlen("Transfer-Encoding: ");
if ((!memcmp(chunk_value, "Chunked", len_chunk)) || (!memcmp(chunk_value, "chunked", len_chunk))) {
client_data->is_chunked = IOT_TRUE;
client_data->response_content_len = 0;
client_data->retrieve_len = 0;
}
} else {
Log_e("Could not parse header");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP);
}
len = len - (ptr_body_end + 4 - data);
memmove(data, ptr_body_end + 4, len + 1);
int rc = _http_client_retrieve_content(client, data, len, left_ms(&timer), client_data);
IOT_FUNC_EXIT_RC(rc);
}
static int _http_client_connect(HTTPClient *client)
{
if (QCLOUD_RET_SUCCESS != client->network_stack.connect(&client->network_stack)) {
return QCLOUD_ERR_HTTP_CONN;
}
return QCLOUD_RET_SUCCESS;
}
static int _http_client_send_request(HTTPClient *client, const char *url, HttpMethod method,
HTTPClientData *client_data)
{
int rc;
rc = _http_client_send_header(client, url, method, client_data);
if (rc != 0) {
Log_e("httpclient_send_header is error, rc = %d", rc);
return rc;
}
if (method == HTTP_POST || method == HTTP_PUT) {
rc = _http_client_send_userdata(client, client_data);
}
return rc;
}
static int _http_client_recv_response(HTTPClient *client, uint32_t timeout_ms, HTTPClientData *client_data)
{
IOT_FUNC_ENTRY;
int reclen = 0, rc = QCLOUD_ERR_HTTP_CONN;
char buf[HTTP_CLIENT_CHUNK_SIZE] = {0};
Timer timer;
InitTimer(&timer);
countdown_ms(&timer, timeout_ms);
if (0 == client->network_stack.handle) {
Log_e("Connection has not been established");
IOT_FUNC_EXIT_RC(rc);
}
if (client_data->is_more) {
client_data->response_buf[0] = '\0';
rc = _http_client_retrieve_content(client, buf, reclen, left_ms(&timer), client_data);
} else {
client_data->is_more = IOT_TRUE;
rc = _http_client_recv(client, buf, 1, HTTP_CLIENT_CHUNK_SIZE - 1, &reclen, left_ms(&timer), client_data);
if (rc != QCLOUD_RET_SUCCESS) {
IOT_FUNC_EXIT_RC(rc);
}
// else if(0 == left_ms(&timer)){
// IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP_TIMEOUT);
//}
buf[reclen] = '\0';
if (reclen) {
// HAL_Printf("RESPONSE:\n%s", buf);
rc = _http_client_response_parse(client, buf, reclen, left_ms(&timer), client_data);
}
}
IOT_FUNC_EXIT_RC(rc);
}
static int _http_network_init(Network *pNetwork, const char *host, int port, const char *ca_crt_dir)
{
int rc = QCLOUD_RET_SUCCESS;
if (pNetwork == NULL) {
return QCLOUD_ERR_INVAL;
}
pNetwork->type = NETWORK_TCP;
#ifndef AUTH_WITH_NOTLS
if (ca_crt_dir != NULL) {
pNetwork->ssl_connect_params.ca_crt = ca_crt_dir;
pNetwork->ssl_connect_params.ca_crt_len = strlen(pNetwork->ssl_connect_params.ca_crt);
pNetwork->ssl_connect_params.timeout_ms = 10000;
pNetwork->type = NETWORK_TLS;
}
#endif
pNetwork->host = host;
pNetwork->port = port;
rc = network_init(pNetwork);
return rc;
}
int qcloud_http_client_connect(HTTPClient *client, const char *url, int port, const char *ca_crt)
{
if (client->network_stack.handle != 0) {
Log_e("http client has connected to host!");
return QCLOUD_ERR_HTTP_CONN;
}
int rc;
char host[HTTP_CLIENT_MAX_HOST_LEN] = {0};
rc = _http_client_parse_host(url, host, sizeof(host));
if (rc != QCLOUD_RET_SUCCESS)
return rc;
rc = _http_network_init(&client->network_stack, host, port, ca_crt);
if (rc != QCLOUD_RET_SUCCESS)
return rc;
rc = _http_client_connect(client);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("http_client_connect is error,rc = %d", rc);
qcloud_http_client_close(client);
} else {
/* reduce log print due to frequent log server connect/disconnect */
if (0 == strcmp(url, LOG_UPLOAD_SERVER_URL))
UPLOAD_DBG("http client connect success");
else
Log_d("http client connect success");
}
return rc;
}
void qcloud_http_client_close(HTTPClient *client)
{
if (client->network_stack.handle != 0) {
client->network_stack.disconnect(&client->network_stack);
}
}
int qcloud_http_client_common(HTTPClient *client, const char *url, int port, const char *ca_crt, HttpMethod method,
HTTPClientData *client_data)
{
int rc;
if (client->network_stack.handle == 0) {
rc = qcloud_http_client_connect(client, url, port, ca_crt);
if (rc != QCLOUD_RET_SUCCESS)
return rc;
}
rc = _http_client_send_request(client, url, method, client_data);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("http_client_send_request is error,rc = %d", rc);
qcloud_http_client_close(client);
return rc;
}
return QCLOUD_RET_SUCCESS;
}
int qcloud_http_recv_data(HTTPClient *client, uint32_t timeout_ms, HTTPClientData *client_data)
{
IOT_FUNC_ENTRY;
int rc = QCLOUD_RET_SUCCESS;
Timer timer;
InitTimer(&timer);
countdown_ms(&timer, (unsigned int)timeout_ms);
if ((NULL != client_data->response_buf) && (0 != client_data->response_buf_len)) {
rc = _http_client_recv_response(client, left_ms(&timer), client_data);
if (rc < 0) {
Log_e("http_client_recv_response is error,rc = %d", rc);
qcloud_http_client_close(client);
IOT_FUNC_EXIT_RC(rc);
}
}
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,583 @@
/*
* 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 <ctype.h>
#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 "log_upload.h"
#include "mqtt_client.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_base64.h"
#include "utils_list.h"
static uint16_t _get_random_start_packet_id(void)
{
srand((unsigned)HAL_GetTimeMs());
return rand() % 65536 + 1;
}
DeviceInfo *IOT_MQTT_GetDeviceInfo(void *pClient)
{
POINTER_SANITY_CHECK(pClient, NULL);
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
return &mqtt_client->device_info;
}
// currently return a constant value
int IOT_MQTT_GetErrCode(void)
{
return QCLOUD_ERR_FAILURE;
}
void *IOT_MQTT_Construct(MQTTInitParams *pParams)
{
POINTER_SANITY_CHECK(pParams, NULL);
STRING_PTR_SANITY_CHECK(pParams->product_id, NULL);
STRING_PTR_SANITY_CHECK(pParams->device_name, NULL);
Qcloud_IoT_Client *mqtt_client = NULL;
// create and init MQTTClient
if ((mqtt_client = (Qcloud_IoT_Client *)HAL_Malloc(sizeof(Qcloud_IoT_Client))) == NULL) {
Log_e("malloc MQTTClient failed");
return NULL;
}
int rc = qcloud_iot_mqtt_init(mqtt_client, pParams);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("mqtt init failed: %d", rc);
HAL_Free(mqtt_client);
return NULL;
}
MQTTConnectParams connect_params = DEFAULT_MQTTCONNECT_PARAMS;
connect_params.client_id = mqtt_client->device_info.client_id;
// Upper limit of keep alive interval is (11.5 * 60) seconds
connect_params.keep_alive_interval = Min(pParams->keep_alive_interval_ms / 1000, 690);
connect_params.clean_session = pParams->clean_session;
connect_params.auto_connect_enable = pParams->auto_connect_enable;
#if defined(AUTH_WITH_NOTLS) && defined(AUTH_MODE_KEY)
if (pParams->device_secret == NULL) {
Log_e("Device secret is null!");
qcloud_iot_mqtt_fini(mqtt_client);
HAL_Free(mqtt_client);
return NULL;
}
size_t src_len = strlen(pParams->device_secret);
size_t len;
memset(mqtt_client->psk_decode, 0x00, DECODE_PSK_LENGTH);
rc = qcloud_iot_utils_base64decode(mqtt_client->psk_decode, DECODE_PSK_LENGTH, &len,
(unsigned char *)pParams->device_secret, src_len);
connect_params.device_secret = (char *)mqtt_client->psk_decode;
connect_params.device_secret_len = len;
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("Device secret decode err, secret:%s", pParams->device_secret);
qcloud_iot_mqtt_fini(mqtt_client);
HAL_Free(mqtt_client);
return NULL;
}
#endif
rc = qcloud_iot_mqtt_connect(mqtt_client, &connect_params);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("mqtt connect with id: %s failed: %d", mqtt_client->options.conn_id, rc);
qcloud_iot_mqtt_fini(mqtt_client);
HAL_Free(mqtt_client);
return NULL;
} else {
Log_i("mqtt connect with id: %s success", mqtt_client->options.conn_id);
}
#ifdef LOG_UPLOAD
// log subscribe topics
if (is_log_uploader_init()) {
int log_level;
rc = qcloud_get_log_level(mqtt_client, &log_level);
// rc = qcloud_log_topic_subscribe(mqtt_client);
if (rc < 0) {
Log_e("client get log topic failed: %d", rc);
}
set_log_mqtt_client((void *)mqtt_client);
IOT_Log_Upload(true);
}
#endif
return mqtt_client;
}
int IOT_MQTT_Destroy(void **pClient)
{
POINTER_SANITY_CHECK(*pClient, QCLOUD_ERR_INVAL);
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)(*pClient);
int rc = qcloud_iot_mqtt_disconnect(mqtt_client);
// disconnect network stack by force
if (rc != QCLOUD_RET_SUCCESS) {
mqtt_client->network_stack.disconnect(&(mqtt_client->network_stack));
set_client_conn_state(mqtt_client, NOTCONNECTED);
}
int i = 0;
for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
/* notify this event to topic subscriber */
if (NULL != mqtt_client->sub_handles[i].topic_filter && NULL != mqtt_client->sub_handles[i].sub_event_handler)
mqtt_client->sub_handles[i].sub_event_handler(mqtt_client, MQTT_EVENT_CLIENT_DESTROY,
mqtt_client->sub_handles[i].handler_user_data);
if (NULL != mqtt_client->sub_handles[i].topic_filter) {
HAL_Free((void *)mqtt_client->sub_handles[i].topic_filter);
mqtt_client->sub_handles[i].topic_filter = NULL;
}
}
#ifdef MQTT_RMDUP_MSG_ENABLED
reset_repeat_packet_id_buffer(mqtt_client);
#endif
HAL_MutexDestroy(mqtt_client->lock_generic);
HAL_MutexDestroy(mqtt_client->lock_write_buf);
HAL_MutexDestroy(mqtt_client->lock_list_sub);
HAL_MutexDestroy(mqtt_client->lock_list_pub);
list_destroy(mqtt_client->list_pub_wait_ack);
list_destroy(mqtt_client->list_sub_wait_ack);
HAL_Free(*pClient);
*pClient = NULL;
#ifdef LOG_UPLOAD
set_log_mqtt_client(NULL);
#endif
Log_i("mqtt release!");
return rc;
}
int IOT_MQTT_Yield(void *pClient, uint32_t timeout_ms)
{
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
#ifdef MULTITHREAD_ENABLED
/* only one instance of yield is allowed in running state*/
if (mqtt_client->thread_running) {
HAL_SleepMs(timeout_ms);
return QCLOUD_RET_SUCCESS;
}
#endif
int rc = qcloud_iot_mqtt_yield(mqtt_client, timeout_ms);
#ifdef LOG_UPLOAD
/* do instant log uploading if MQTT communication error */
if (rc == QCLOUD_RET_SUCCESS)
IOT_Log_Upload(false);
else
IOT_Log_Upload(true);
#endif
return rc;
}
int IOT_MQTT_Publish(void *pClient, char *topicName, PublishParams *pParams)
{
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
return qcloud_iot_mqtt_publish(mqtt_client, topicName, pParams);
}
int IOT_MQTT_Subscribe(void *pClient, char *topicFilter, SubscribeParams *pParams)
{
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
return qcloud_iot_mqtt_subscribe(mqtt_client, topicFilter, pParams);
}
int IOT_MQTT_Unsubscribe(void *pClient, char *topicFilter)
{
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
return qcloud_iot_mqtt_unsubscribe(mqtt_client, topicFilter);
}
bool IOT_MQTT_IsSubReady(void *pClient, char *topicFilter)
{
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
return qcloud_iot_mqtt_is_sub_ready(mqtt_client, topicFilter);
}
bool IOT_MQTT_IsConnected(void *pClient)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
IOT_FUNC_EXIT_RC(get_client_conn_state(mqtt_client) == 1)
}
#ifdef MULTITHREAD_ENABLED
static void _mqtt_yield_thread(void *ptr)
{
int rc = QCLOUD_RET_SUCCESS;
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)ptr;
Log_i("MQTT client %s start loop", mqtt_client->device_info.client_id);
while (mqtt_client->thread_running) {
int rc = qcloud_iot_mqtt_yield(mqtt_client, 500);
#ifdef LOG_UPLOAD
/* do instant log uploading if MQTT communication error */
if (rc == QCLOUD_RET_SUCCESS)
IOT_Log_Upload(false);
else
IOT_Log_Upload(true);
#endif
if (rc == QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT) {
HAL_SleepMs(500);
continue;
} else if (rc == QCLOUD_RET_MQTT_MANUALLY_DISCONNECTED || rc == QCLOUD_ERR_MQTT_RECONNECT_TIMEOUT) {
Log_e("MQTT Yield thread exit with error: %d", rc);
break;
} else if (rc != QCLOUD_RET_SUCCESS && rc != QCLOUD_RET_MQTT_RECONNECTED) {
Log_e("MQTT Yield thread error: %d", rc);
}
HAL_SleepMs(200);
}
mqtt_client->thread_running = false;
mqtt_client->thread_exit_code = rc;
#ifdef LOG_UPLOAD
IOT_Log_Upload(true);
#endif
Log_i("MQTT client %s stop loop", mqtt_client->device_info.client_id);
}
int IOT_MQTT_StartLoop(void *pClient)
{
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
ThreadParams thread_params = {0};
thread_params.thread_func = _mqtt_yield_thread;
thread_params.thread_name = "MQTT_yield_thread";
thread_params.user_arg = pClient;
thread_params.stack_size = 4096;
thread_params.priority = 1;
mqtt_client->thread_running = true;
int rc = HAL_ThreadCreate(&thread_params);
if (rc) {
Log_e("create mqtt yield thread fail: %d", rc);
return QCLOUD_ERR_FAILURE;
}
HAL_SleepMs(500);
return QCLOUD_RET_SUCCESS;
}
void IOT_MQTT_StopLoop(void *pClient)
{
POINTER_SANITY_CHECK_RTN(pClient);
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
mqtt_client->thread_running = false;
HAL_SleepMs(1000);
return;
}
bool IOT_MQTT_GetLoopStatus(void *pClient, int *exit_code)
{
POINTER_SANITY_CHECK(pClient, false);
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
*exit_code = mqtt_client->thread_exit_code;
return mqtt_client->thread_running;
}
#endif
#if 0
static inline void _strlowr(char *str)
{
while (*str != '\0') {
*str = tolower(*str);
str++;
}
}
#endif
int qcloud_iot_mqtt_init(Qcloud_IoT_Client *pClient, MQTTInitParams *pParams)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(pParams, QCLOUD_ERR_INVAL);
memset(pClient, 0x0, sizeof(Qcloud_IoT_Client));
int rc = iot_device_info_set(&(pClient->device_info), pParams->product_id, pParams->device_name);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("failed to set device info: %d", rc);
return rc;
}
int size =
HAL_Snprintf(pClient->host_addr, HOST_STR_LENGTH, "%s.%s", pParams->product_id, QCLOUD_IOT_MQTT_DIRECT_DOMAIN);
if (size < 0 || size > HOST_STR_LENGTH - 1) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
// enable below code for some special platform
//_strlowr(s_qcloud_iot_host);
int i = 0;
for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
pClient->sub_handles[i].topic_filter = NULL;
pClient->sub_handles[i].message_handler = NULL;
pClient->sub_handles[i].sub_event_handler = NULL;
pClient->sub_handles[i].qos = QOS0;
pClient->sub_handles[i].handler_user_data = NULL;
}
if (pParams->command_timeout < MIN_COMMAND_TIMEOUT)
pParams->command_timeout = MIN_COMMAND_TIMEOUT;
if (pParams->command_timeout > MAX_COMMAND_TIMEOUT)
pParams->command_timeout = MAX_COMMAND_TIMEOUT;
pClient->command_timeout_ms = pParams->command_timeout;
// packet id, random from [1 - 65536]
pClient->next_packet_id = _get_random_start_packet_id();
pClient->write_buf_size = QCLOUD_IOT_MQTT_TX_BUF_LEN;
pClient->read_buf_size = QCLOUD_IOT_MQTT_RX_BUF_LEN;
pClient->is_ping_outstanding = 0;
pClient->was_manually_disconnected = 0;
pClient->counter_network_disconnected = 0;
pClient->event_handle = pParams->event_handle;
pClient->lock_generic = HAL_MutexCreate();
if (NULL == pClient->lock_generic) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
set_client_conn_state(pClient, NOTCONNECTED);
if ((pClient->lock_write_buf = HAL_MutexCreate()) == NULL) {
Log_e("create write buf lock failed.");
goto error;
}
if ((pClient->lock_list_sub = HAL_MutexCreate()) == NULL) {
Log_e("create sub list lock failed.");
goto error;
}
if ((pClient->lock_list_pub = HAL_MutexCreate()) == NULL) {
Log_e("create pub list lock failed.");
goto error;
}
if ((pClient->list_pub_wait_ack = list_new()) == NULL) {
Log_e("create pub wait list failed.");
goto error;
}
pClient->list_pub_wait_ack->free = HAL_Free;
if ((pClient->list_sub_wait_ack = list_new()) == NULL) {
Log_e("create sub wait list failed.");
goto error;
}
pClient->list_sub_wait_ack->free = HAL_Free;
#ifndef AUTH_WITH_NOTLS
// device param for TLS connection
#ifdef AUTH_MODE_CERT
Log_d("cert file: %s", pParams->cert_file);
Log_d("key file: %s", pParams->key_file);
strncpy(pClient->cert_file_path, pParams->cert_file, FILE_PATH_MAX_LEN - 1);
strncpy(pClient->key_file_path, pParams->key_file, FILE_PATH_MAX_LEN - 1);
pClient->network_stack.ssl_connect_params.cert_file = pClient->cert_file_path;
pClient->network_stack.ssl_connect_params.key_file = pClient->key_file_path;
pClient->network_stack.ssl_connect_params.ca_crt = iot_ca_get();
pClient->network_stack.ssl_connect_params.ca_crt_len = strlen(pClient->network_stack.ssl_connect_params.ca_crt);
#else
if (pParams->device_secret != NULL) {
size_t src_len = strlen(pParams->device_secret);
size_t len;
memset(pClient->psk_decode, 0x00, DECODE_PSK_LENGTH);
qcloud_iot_utils_base64decode(pClient->psk_decode, DECODE_PSK_LENGTH, &len,
(unsigned char *)pParams->device_secret, src_len);
pClient->network_stack.ssl_connect_params.psk = (char *)pClient->psk_decode;
pClient->network_stack.ssl_connect_params.psk_length = len;
} else {
Log_e("psk is empty!");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
}
if (strnlen(pClient->device_info.client_id, MAX_SIZE_OF_CLIENT_ID) == 0) {
Log_e("psk id is empty!");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
}
pClient->network_stack.ssl_connect_params.psk_id = pClient->device_info.client_id;
pClient->network_stack.ssl_connect_params.ca_crt = NULL;
pClient->network_stack.ssl_connect_params.ca_crt_len = 0;
#endif
pClient->network_stack.host = pClient->host_addr;
pClient->network_stack.port = MQTT_SERVER_PORT_TLS;
pClient->network_stack.ssl_connect_params.timeout_ms =
pClient->command_timeout_ms > QCLOUD_IOT_TLS_HANDSHAKE_TIMEOUT ? pClient->command_timeout_ms
: QCLOUD_IOT_TLS_HANDSHAKE_TIMEOUT;
#else
pClient->network_stack.host = pClient->host_addr;
pClient->network_stack.port = MQTT_SERVER_PORT_NOTLS;
#endif
// init network stack
qcloud_iot_mqtt_network_init(&(pClient->network_stack));
// ping timer and reconnect delay timer
InitTimer(&(pClient->ping_timer));
InitTimer(&(pClient->reconnect_delay_timer));
#ifdef SYSTEM_COMM
pClient->sys_state.result_recv_ok = false;
pClient->sys_state.topic_sub_ok = false;
pClient->sys_state.time = 0;
#endif
#ifdef MULTITHREAD_ENABLED
pClient->thread_running = false;
#endif
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
error:
if (pClient->list_pub_wait_ack) {
pClient->list_pub_wait_ack->free(pClient->list_pub_wait_ack);
pClient->list_pub_wait_ack = NULL;
}
if (pClient->list_sub_wait_ack) {
pClient->list_sub_wait_ack->free(pClient->list_sub_wait_ack);
pClient->list_sub_wait_ack = NULL;
}
if (pClient->lock_generic) {
HAL_MutexDestroy(pClient->lock_generic);
pClient->lock_generic = NULL;
}
if (pClient->lock_list_sub) {
HAL_MutexDestroy(pClient->lock_list_sub);
pClient->lock_list_sub = NULL;
}
if (pClient->lock_list_pub) {
HAL_MutexDestroy(pClient->lock_list_pub);
pClient->lock_list_pub = NULL;
}
if (pClient->lock_write_buf) {
HAL_MutexDestroy(pClient->lock_write_buf);
pClient->lock_write_buf = NULL;
}
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE)
}
int qcloud_iot_mqtt_fini(Qcloud_IoT_Client *mqtt_client)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(mqtt_client, QCLOUD_ERR_INVAL);
HAL_MutexDestroy(mqtt_client->lock_generic);
HAL_MutexDestroy(mqtt_client->lock_write_buf);
HAL_MutexDestroy(mqtt_client->lock_list_sub);
HAL_MutexDestroy(mqtt_client->lock_list_pub);
list_destroy(mqtt_client->list_pub_wait_ack);
list_destroy(mqtt_client->list_sub_wait_ack);
Log_i("release mqtt client resources");
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
int qcloud_iot_mqtt_set_autoreconnect(Qcloud_IoT_Client *pClient, bool value)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
pClient->options.auto_connect_enable = (uint8_t)value;
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
bool qcloud_iot_mqtt_is_autoreconnect_enabled(Qcloud_IoT_Client *pClient)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
bool is_enabled = false;
if (pClient->options.auto_connect_enable == 1) {
is_enabled = true;
}
IOT_FUNC_EXIT_RC(is_enabled);
}
int qcloud_iot_mqtt_get_network_disconnected_count(Qcloud_IoT_Client *pClient)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
IOT_FUNC_EXIT_RC(pClient->counter_network_disconnected);
}
int qcloud_iot_mqtt_reset_network_disconnected_count(Qcloud_IoT_Client *pClient)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
pClient->counter_network_disconnected = 0;
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,477 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Allan Stockdill-Mander/Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
#include <limits.h>
#include <string.h>
#include "mqtt_client.h"
#include "qcloud_iot_common.h"
#include "utils_hmac.h"
#define MQTT_CONNECT_FLAG_USERNAME 0x80
#define MQTT_CONNECT_FLAG_PASSWORD 0x40
#define MQTT_CONNECT_FLAG_WILL_RETAIN 0x20
#define MQTT_CONNECT_FLAG_WILL_QOS2 0x18
#define MQTT_CONNECT_FLAG_WILL_QOS1 0x08
#define MQTT_CONNECT_FLAG_WILL_QOS0 0x00
#define MQTT_CONNECT_FLAG_WILL_FLAG 0x04
#define MQTT_CONNECT_FLAG_CLEAN_SES 0x02
#define MQTT_CONNACK_FLAG_SES_PRE 0x01
/**
* Connect return code
*/
typedef enum {
CONNACK_CONNECTION_ACCEPTED = 0, // connection accepted
CONANCK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR = 1, // connection refused: unaccpeted protocol verison
CONNACK_IDENTIFIER_REJECTED_ERROR = 2, // connection refused: identifier rejected
CONNACK_SERVER_UNAVAILABLE_ERROR = 3, // connection refused: server unavailable
CONNACK_BAD_USERDATA_ERROR = 4, // connection refused: bad user name or password
CONNACK_NOT_AUTHORIZED_ERROR = 5 // connection refused: not authorized
} MQTTConnackReturnCodes;
/**
* Determines the length of the MQTT connect packet that would be produced using the supplied connect options.
* @param options the options to be used to build the connect packet
* @param the length of buffer needed to contain the serialized version of the packet
* @return int indicating function execution status
*/
static uint32_t _get_packet_connect_rem_len(MQTTConnectParams *options)
{
size_t len = 0;
/* variable depending on MQTT or MQIsdp */
if (3 == options->mqtt_version) {
len = 12;
} else if (4 == options->mqtt_version) {
len = 10;
}
len += strlen(options->client_id) + 2;
if (options->username) {
len += strlen(options->username) + 2;
}
if (options->password) {
len += strlen(options->password) + 2;
}
return (uint32_t)len;
}
static void _copy_connect_params(MQTTConnectParams *destination, MQTTConnectParams *source)
{
POINTER_SANITY_CHECK_RTN(destination);
POINTER_SANITY_CHECK_RTN(source);
/* In case of reconnecting, source == destination */
if (source == destination) {
return;
}
destination->mqtt_version = source->mqtt_version;
destination->client_id = source->client_id;
destination->username = source->username;
destination->keep_alive_interval = source->keep_alive_interval;
destination->clean_session = source->clean_session;
destination->auto_connect_enable = source->auto_connect_enable;
#ifdef AUTH_WITH_NOTLS
destination->device_secret = source->device_secret;
destination->device_secret_len = source->device_secret_len;
#endif
}
/**
* Serializes the connect options into the buffer.
* @param buf the buffer into which the packet will be serialized
* @param len the length in bytes of the supplied buffer
* @param options the options to be used to build the connect packet
* @param serialized length
* @return int indicating function execution status
*/
static int _serialize_connect_packet(unsigned char *buf, size_t buf_len, MQTTConnectParams *options,
uint32_t *serialized_len)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(options, QCLOUD_ERR_INVAL);
STRING_PTR_SANITY_CHECK(options->client_id, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(serialized_len, QCLOUD_ERR_INVAL);
unsigned char *ptr = buf;
unsigned char header = 0;
unsigned char flags = 0;
uint32_t rem_len = 0;
int rc;
long cur_timesec = HAL_Timer_current_sec() + MAX_ACCESS_EXPIRE_TIMEOUT / 1000;
if (cur_timesec <= 0 || MAX_ACCESS_EXPIRE_TIMEOUT <= 0) {
cur_timesec = LONG_MAX;
}
long cur_timesec_bak = cur_timesec;
int cur_timesec_len = 0;
while (cur_timesec_bak != 0) {
cur_timesec_bak /= 10;
++cur_timesec_len;
}
int username_len =
strlen(options->client_id) + strlen(QCLOUD_IOT_DEVICE_SDK_APPID) + MAX_CONN_ID_LEN + cur_timesec_len + 4;
options->username = (char *)HAL_Malloc(username_len);
if (options->username == NULL) {
Log_e("malloc username failed!");
rc = QCLOUD_ERR_MALLOC;
goto err_exit;
}
get_next_conn_id(options->conn_id);
HAL_Snprintf(options->username, username_len, "%s;%s;%s;%ld", options->client_id, QCLOUD_IOT_DEVICE_SDK_APPID,
options->conn_id, cur_timesec);
#if defined(AUTH_WITH_NOTLS) && defined(AUTH_MODE_KEY)
if (options->device_secret != NULL && options->username != NULL) {
char sign[41] = {0};
utils_hmac_sha1(options->username, strlen(options->username), sign, options->device_secret,
options->device_secret_len);
options->password = (char *)HAL_Malloc(51);
if (options->password == NULL) {
Log_e("malloc password failed!");
rc = QCLOUD_ERR_MALLOC;
goto err_exit;
}
HAL_Snprintf(options->password, 51, "%s;hmacsha1", sign);
}
#endif
rem_len = _get_packet_connect_rem_len(options);
if (get_mqtt_packet_len(rem_len) > buf_len) {
Log_e("get_mqtt_packet_len failed!");
rc = QCLOUD_ERR_BUF_TOO_SHORT;
goto err_exit;
}
rc = mqtt_init_packet_header(&header, CONNECT, QOS0, 0, 0);
if (QCLOUD_RET_SUCCESS != rc) {
Log_e("mqtt_init_packet_header failed!");
goto err_exit;
}
// 1st byte in fixed header
mqtt_write_char(&ptr, header);
// remaining length
ptr += mqtt_write_packet_rem_len(ptr, rem_len);
// MQTT protocol name and version in variable header
if (4 == options->mqtt_version) {
mqtt_write_utf8_string(&ptr, "MQTT");
mqtt_write_char(&ptr, (unsigned char)4);
} else {
mqtt_write_utf8_string(&ptr, "MQIsdp");
mqtt_write_char(&ptr, (unsigned char)3);
}
// flags in variable header
flags |= (options->clean_session) ? MQTT_CONNECT_FLAG_CLEAN_SES : 0;
flags |= (options->username != NULL) ? MQTT_CONNECT_FLAG_USERNAME : 0;
#if defined(AUTH_WITH_NOTLS) && defined(AUTH_MODE_KEY)
flags |= MQTT_CONNECT_FLAG_PASSWORD;
#endif
mqtt_write_char(&ptr, flags);
// keep alive interval (unit:ms) in variable header
mqtt_write_uint_16(&ptr, options->keep_alive_interval);
// client id
mqtt_write_utf8_string(&ptr, options->client_id);
if ((flags & MQTT_CONNECT_FLAG_USERNAME) && options->username != NULL) {
mqtt_write_utf8_string(&ptr, options->username);
HAL_Free(options->username);
options->username = NULL;
}
if ((flags & MQTT_CONNECT_FLAG_PASSWORD) && options->password != NULL) {
mqtt_write_utf8_string(&ptr, options->password);
HAL_Free(options->password);
options->password = NULL;
}
*serialized_len = (uint32_t)(ptr - buf);
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
err_exit:
HAL_Free(options->username);
options->username = NULL;
HAL_Free(options->password);
options->password = NULL;
IOT_FUNC_EXIT_RC(rc);
}
/**
* Deserializes the supplied (wire) buffer into connack data - return code
* @param sessionPresent the session present flag returned (only for MQTT 3.1.1)
* @param connack_rc returned integer value of the connack return code
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @return int indicating function execution status
*/
static int _deserialize_connack_packet(uint8_t *sessionPresent, int *connack_rc, unsigned char *buf, size_t buflen)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(sessionPresent, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(connack_rc, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL);
unsigned char header, type = 0;
unsigned char *curdata = buf;
unsigned char *enddata = NULL;
int rc;
uint32_t decodedLen = 0, readBytesLen = 0;
unsigned char flags = 0;
unsigned char connack_rc_char;
// CONNACK: 2 bytes in fixed header and 2 bytes in variable header, no payload
if (4 > buflen) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_BUF_TOO_SHORT);
}
header = mqtt_read_char(&curdata);
type = (header & MQTT_HEADER_TYPE_MASK) >> MQTT_HEADER_TYPE_SHIFT;
if (CONNACK != type) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
rc = mqtt_read_packet_rem_len_form_buf(curdata, &decodedLen, &readBytesLen);
if (QCLOUD_RET_SUCCESS != rc) {
IOT_FUNC_EXIT_RC(rc);
}
curdata += (readBytesLen);
enddata = curdata + decodedLen;
if (enddata - curdata != 2) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
// variable header - connack flag, refer to MQTT spec 3.2.2.1
flags = mqtt_read_char(&curdata);
*sessionPresent = flags & MQTT_CONNACK_FLAG_SES_PRE;
// variable header - return code, refer to MQTT spec 3.2.2.3
connack_rc_char = mqtt_read_char(&curdata);
switch (connack_rc_char) {
case CONNACK_CONNECTION_ACCEPTED:
*connack_rc = QCLOUD_RET_MQTT_CONNACK_CONNECTION_ACCEPTED;
break;
case CONANCK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR:
*connack_rc = QCLOUD_ERR_MQTT_CONNACK_UNACCEPTABLE_PROTOCOL_VERSION;
break;
case CONNACK_IDENTIFIER_REJECTED_ERROR:
*connack_rc = QCLOUD_ERR_MQTT_CONNACK_IDENTIFIER_REJECTED;
break;
case CONNACK_SERVER_UNAVAILABLE_ERROR:
*connack_rc = QCLOUD_ERR_MQTT_CONNACK_SERVER_UNAVAILABLE;
break;
case CONNACK_BAD_USERDATA_ERROR:
*connack_rc = QCLOUD_ERR_MQTT_CONNACK_BAD_USERDATA;
break;
case CONNACK_NOT_AUTHORIZED_ERROR:
*connack_rc = QCLOUD_ERR_MQTT_CONNACK_NOT_AUTHORIZED;
break;
default:
*connack_rc = QCLOUD_ERR_MQTT_CONNACK_UNKNOWN;
break;
}
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
/**
* @brief Setup connection with MQTT server
*
* @param pClient
* @param options
* @return
*/
static int _mqtt_connect(Qcloud_IoT_Client *pClient, MQTTConnectParams *options)
{
IOT_FUNC_ENTRY;
Timer connect_timer;
int connack_rc = QCLOUD_ERR_FAILURE, rc = QCLOUD_ERR_FAILURE;
uint8_t sessionPresent = 0;
uint32_t len = 0;
InitTimer(&connect_timer);
countdown_ms(&connect_timer, pClient->command_timeout_ms);
if (NULL != options) {
_copy_connect_params(&(pClient->options), options);
}
// TCP or TLS network connect
rc = pClient->network_stack.connect(&(pClient->network_stack));
if (QCLOUD_RET_SUCCESS != rc) {
IOT_FUNC_EXIT_RC(rc);
}
HAL_MutexLock(pClient->lock_write_buf);
// serialize CONNECT packet
rc = _serialize_connect_packet(pClient->write_buf, pClient->write_buf_size, &(pClient->options), &len);
if (QCLOUD_RET_SUCCESS != rc || 0 == len) {
HAL_MutexUnlock(pClient->lock_write_buf);
IOT_FUNC_EXIT_RC(rc);
}
// send CONNECT packet
rc = send_mqtt_packet(pClient, len, &connect_timer);
if (QCLOUD_RET_SUCCESS != rc) {
HAL_MutexUnlock(pClient->lock_write_buf);
IOT_FUNC_EXIT_RC(rc);
}
HAL_MutexUnlock(pClient->lock_write_buf);
// wait for CONNACK
rc = wait_for_read(pClient, CONNACK, &connect_timer, QOS0);
if (QCLOUD_RET_SUCCESS != rc) {
IOT_FUNC_EXIT_RC(rc);
}
// deserialize CONNACK and check reture code
rc = _deserialize_connack_packet(&sessionPresent, &connack_rc, pClient->read_buf, pClient->read_buf_size);
if (QCLOUD_RET_SUCCESS != rc) {
IOT_FUNC_EXIT_RC(rc);
}
if (QCLOUD_RET_MQTT_CONNACK_CONNECTION_ACCEPTED != connack_rc) {
IOT_FUNC_EXIT_RC(connack_rc);
}
set_client_conn_state(pClient, CONNECTED);
HAL_MutexLock(pClient->lock_generic);
pClient->was_manually_disconnected = 0;
pClient->is_ping_outstanding = 0;
countdown(&pClient->ping_timer, pClient->options.keep_alive_interval);
HAL_MutexUnlock(pClient->lock_generic);
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
int qcloud_iot_mqtt_connect(Qcloud_IoT_Client *pClient, MQTTConnectParams *pParams)
{
IOT_FUNC_ENTRY;
int rc;
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(pParams, QCLOUD_ERR_INVAL);
// check connection state first
if (get_client_conn_state(pClient)) {
IOT_FUNC_EXIT_RC(QCLOUD_RET_MQTT_ALREADY_CONNECTED);
}
rc = _mqtt_connect(pClient, pParams);
// disconnect network if connect fail
if (rc != QCLOUD_RET_SUCCESS) {
pClient->network_stack.disconnect(&(pClient->network_stack));
}
IOT_FUNC_EXIT_RC(rc);
}
int qcloud_iot_mqtt_attempt_reconnect(Qcloud_IoT_Client *pClient)
{
IOT_FUNC_ENTRY;
int rc;
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
Log_i("attempt to reconnect...");
if (get_client_conn_state(pClient)) {
IOT_FUNC_EXIT_RC(QCLOUD_RET_MQTT_ALREADY_CONNECTED);
}
rc = qcloud_iot_mqtt_connect(pClient, &pClient->options);
if (!get_client_conn_state(pClient)) {
IOT_FUNC_EXIT_RC(rc);
}
rc = qcloud_iot_mqtt_resubscribe(pClient);
if (rc != QCLOUD_RET_SUCCESS) {
IOT_FUNC_EXIT_RC(rc);
}
IOT_FUNC_EXIT_RC(QCLOUD_RET_MQTT_RECONNECTED);
}
int qcloud_iot_mqtt_disconnect(Qcloud_IoT_Client *pClient)
{
IOT_FUNC_ENTRY;
int rc;
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
Timer timer;
uint32_t serialized_len = 0;
if (get_client_conn_state(pClient) == 0) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
}
HAL_MutexLock(pClient->lock_write_buf);
rc = serialize_packet_with_zero_payload(pClient->write_buf, pClient->write_buf_size, DISCONNECT, &serialized_len);
if (rc != QCLOUD_RET_SUCCESS) {
HAL_MutexUnlock(pClient->lock_write_buf);
IOT_FUNC_EXIT_RC(rc);
}
InitTimer(&timer);
countdown_ms(&timer, pClient->command_timeout_ms);
if (serialized_len > 0) {
rc = send_mqtt_packet(pClient, serialized_len, &timer);
if (rc != QCLOUD_RET_SUCCESS) {
HAL_MutexUnlock(pClient->lock_write_buf);
IOT_FUNC_EXIT_RC(rc);
}
}
HAL_MutexUnlock(pClient->lock_write_buf);
pClient->network_stack.disconnect(&(pClient->network_stack));
set_client_conn_state(pClient, NOTCONNECTED);
pClient->was_manually_disconnected = 1;
Log_i("mqtt disconnect!");
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,60 @@
/*
* 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 "mqtt_client_net.h"
// TODO: how to implement
/**
* @brief Check if TLS connection is valid
*
* @param pNetwork
* @return
*/
int qcloud_iot_mqtt_tls_is_connected(Network *pNetwork)
{
return 1;
}
/**
* @brief Init network stack
*
* @param pNetwork
* @param pConnectParams
* @return
*/
int qcloud_iot_mqtt_network_init(Network *pNetwork)
{
int rc;
/* first choice: TLS */
pNetwork->type = NETWORK_TLS;
#ifdef AUTH_WITH_NOTLS
pNetwork->type = NETWORK_TCP;
#endif
rc = network_init(pNetwork);
pNetwork->is_connected = qcloud_iot_mqtt_tls_is_connected;
return rc;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,383 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Ian Craggs - fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=453144
*******************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
#include <string.h>
#include "mqtt_client.h"
#include "utils_list.h"
/**
* @param mqttstring the MQTTString structure into which the data is to be read
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
* @param enddata pointer to the end of the data: do not read beyond
* @return SUCCESS if successful, FAILURE if not
*/
static int _read_string_with_len(char **string, uint16_t *stringLen, unsigned char **pptr, unsigned char *enddata)
{
int rc = QCLOUD_ERR_FAILURE;
/* the first two bytes are the length of the string */
/* enough length to read the integer? */
if (enddata - (*pptr) > 1) {
*stringLen = mqtt_read_uint16_t(pptr); /* increments pptr to point past length */
if (*stringLen > QCLOUD_IOT_MQTT_RX_BUF_LEN) {
Log_e("stringLen exceed QCLOUD_IOT_MQTT_RX_BUF_LEN");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
if (&(*pptr)[*stringLen] <= enddata) {
*string = (char *)*pptr;
*pptr += *stringLen;
rc = QCLOUD_RET_SUCCESS;
}
}
return rc;
}
/**
* Determines the length of the MQTT publish packet that would be produced using the supplied parameters
* @param qos the MQTT QoS of the publish (packetid is omitted for QoS 0)
* @param topicName the topic name to be used in the publish
* @param payload_len the length of the payload to be sent
* @return the length of buffer needed to contain the serialized version of the packet
*/
static uint32_t _get_publish_packet_len(uint8_t qos, char *topicName, size_t payload_len)
{
size_t len = 0;
len += 2 + strlen(topicName) + payload_len;
if (qos > 0) {
len += 2; /* packetid */
}
return (uint32_t)len;
}
static int _mask_push_pubInfo_to(Qcloud_IoT_Client *c, int len, unsigned short msgId, ListNode **node)
{
IOT_FUNC_ENTRY;
if (!c || !node) {
Log_e("invalid parameters!");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_PUSH_TO_LIST_FAILED);
}
if ((len < 0) || (len > c->write_buf_size)) {
Log_e("the param of len is error!");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
HAL_MutexLock(c->lock_list_pub);
if (c->list_pub_wait_ack->len >= MAX_REPUB_NUM) {
HAL_MutexUnlock(c->lock_list_pub);
Log_e("more than %u elements in republish list. List overflow!", c->list_pub_wait_ack->len);
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
QcloudIotPubInfo *repubInfo = (QcloudIotPubInfo *)HAL_Malloc(sizeof(QcloudIotPubInfo) + len);
if (NULL == repubInfo) {
HAL_MutexUnlock(c->lock_list_pub);
Log_e("memory malloc failed!");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
repubInfo->node_state = MQTT_NODE_STATE_NORMANL;
repubInfo->msg_id = msgId;
repubInfo->len = len;
InitTimer(&repubInfo->pub_start_time);
countdown_ms(&repubInfo->pub_start_time, c->command_timeout_ms);
repubInfo->buf = (unsigned char *)repubInfo + sizeof(QcloudIotPubInfo);
memcpy(repubInfo->buf, c->write_buf, len);
*node = list_node_new(repubInfo);
if (NULL == *node) {
HAL_MutexUnlock(c->lock_list_pub);
HAL_Free(repubInfo);
Log_e("list_node_new failed!");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
list_rpush(c->list_pub_wait_ack, *node);
HAL_MutexUnlock(c->lock_list_pub);
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
/**
* Deserializes the supplied (wire) buffer into publish data
* @param dup returned integer - the MQTT dup flag
* @param qos returned integer - the MQTT QoS value
* @param retained returned integer - the MQTT retained flag
* @param packet_id returned integer - the MQTT packet identifier
* @param topicName returned MQTTString - the MQTT topic in the publish
* @param payload returned byte buffer - the MQTT publish payload
* @param payload_len returned integer - the length of the MQTT payload
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buf_len the length in bytes of the data in the supplied buffer
* @return error code. 1 is success
*/
int deserialize_publish_packet(uint8_t *dup, QoS *qos, uint8_t *retained, uint16_t *packet_id, char **topicName,
uint16_t *topicNameLen, unsigned char **payload, size_t *payload_len, unsigned char *buf,
size_t buf_len)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(dup, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(qos, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(retained, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(packet_id, QCLOUD_ERR_INVAL);
unsigned char header, type = 0;
unsigned char *curdata = buf;
unsigned char *enddata = NULL;
int rc;
uint32_t decodedLen = 0;
uint32_t readBytesLen = 0;
/* Publish header size is at least four bytes.
* Fixed header is two bytes.
* Variable header size depends on QoS And Topic Name.
* QoS level 0 doesn't have a message identifier (0 - 2 bytes)
* Topic Name length fields decide size of topic name field (at least 2 bytes)
* MQTT v3.1.1 Specification 3.3.1 */
if (4 > buf_len) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_BUF_TOO_SHORT);
}
header = mqtt_read_char(&curdata);
type = (header & MQTT_HEADER_TYPE_MASK) >> MQTT_HEADER_TYPE_SHIFT;
*dup = (header & MQTT_HEADER_DUP_MASK) >> MQTT_HEADER_DUP_SHIFT;
*qos = (QoS)((header & MQTT_HEADER_QOS_MASK) >> MQTT_HEADER_QOS_SHIFT);
*retained = header & MQTT_HEADER_RETAIN_MASK;
if (PUBLISH != type) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
/* read remaining length */
rc = mqtt_read_packet_rem_len_form_buf(curdata, &decodedLen, &readBytesLen);
if (QCLOUD_RET_SUCCESS != rc) {
IOT_FUNC_EXIT_RC(rc);
}
curdata += (readBytesLen);
enddata = curdata + decodedLen;
/* do we have enough data to read the protocol version byte? */
if (QCLOUD_RET_SUCCESS != _read_string_with_len(topicName, topicNameLen, &curdata, enddata) ||
(0 > (enddata - curdata))) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
if (QOS0 != *qos) {
*packet_id = mqtt_read_uint16_t(&curdata);
}
*payload_len = (size_t)(enddata - curdata);
*payload = curdata;
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
/**
* Serializes the ack packet into the supplied buffer.
* @param buf the buffer into which the packet will be serialized
* @param buf_len the length in bytes of the supplied buffer
* @param packet_type the MQTT packet type: 1.PUBACK; 2.PUBREL; 3.PUBCOMP
* @param dup the MQTT dup flag
* @param packet_id the MQTT packet identifier
* @return serialized length, or error if 0
*/
int serialize_pub_ack_packet(unsigned char *buf, size_t buf_len, MessageTypes packet_type, uint8_t dup,
uint16_t packet_id, uint32_t *serialized_len)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(serialized_len, QCLOUD_ERR_INVAL);
unsigned char header = 0;
unsigned char *ptr = buf;
QoS requestQoS = (PUBREL == packet_type) ? QOS1 : QOS0; // refer to MQTT spec 3.6.1
int rc = mqtt_init_packet_header(&header, packet_type, requestQoS, dup, 0);
/* Minimum byte length required by ACK headers is
* 2 for fixed and 2 for variable part */
if (4 > buf_len) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_BUF_TOO_SHORT);
}
if (QCLOUD_RET_SUCCESS != rc) {
IOT_FUNC_EXIT_RC(rc);
}
mqtt_write_char(&ptr, header); /* write header */
ptr += mqtt_write_packet_rem_len(ptr, 2); /* write remaining length */
mqtt_write_uint_16(&ptr, packet_id);
*serialized_len = (uint32_t)(ptr - buf);
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
/**
* Serializes the supplied publish data into the supplied buffer, ready for sending
* @param buf the buffer into which the packet will be serialized
* @param buf_len the length in bytes of the supplied buffer
* @param dup integer - the MQTT dup flag
* @param qos integer - the MQTT QoS value
* @param retained integer - the MQTT retained flag
* @param packet_id integer - the MQTT packet identifier
* @param topicName MQTTString - the MQTT topic in the publish
* @param payload byte buffer - the MQTT publish payload
* @param payload_len integer - the length of the MQTT payload
* @return the length of the serialized data. <= 0 indicates error
*/
static int _serialize_publish_packet(unsigned char *buf, size_t buf_len, uint8_t dup, QoS qos, uint8_t retained,
uint16_t packet_id, char *topicName, unsigned char *payload, size_t payload_len,
uint32_t *serialized_len)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(serialized_len, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(payload, QCLOUD_ERR_INVAL);
unsigned char *ptr = buf;
unsigned char header = 0;
uint32_t rem_len = 0;
int rc;
rem_len = _get_publish_packet_len(qos, topicName, payload_len);
if (get_mqtt_packet_len(rem_len) > buf_len) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_BUF_TOO_SHORT);
}
rc = mqtt_init_packet_header(&header, PUBLISH, qos, dup, retained);
if (QCLOUD_RET_SUCCESS != rc) {
IOT_FUNC_EXIT_RC(rc);
}
mqtt_write_char(&ptr, header); /* write header */
ptr += mqtt_write_packet_rem_len(ptr, rem_len); /* write remaining length */
;
mqtt_write_utf8_string(&ptr, topicName); /* Variable Header: Topic Name */
if (qos > 0) {
mqtt_write_uint_16(&ptr, packet_id); /* Variable Header: Topic Name */
}
memcpy(ptr, payload, payload_len);
ptr += payload_len;
*serialized_len = (uint32_t)(ptr - buf);
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
int qcloud_iot_mqtt_publish(Qcloud_IoT_Client *pClient, char *topicName, PublishParams *pParams)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(pParams, QCLOUD_ERR_INVAL);
STRING_PTR_SANITY_CHECK(topicName, QCLOUD_ERR_INVAL);
Timer timer;
uint32_t len = 0;
int rc;
ListNode *node = NULL;
size_t topicLen = strlen(topicName);
if (topicLen > MAX_SIZE_OF_CLOUD_TOPIC) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MAX_TOPIC_LENGTH);
}
if (pParams->qos == QOS2) {
Log_e("QoS2 is not supported currently");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_QOS_NOT_SUPPORT);
}
if (!get_client_conn_state(pClient)) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
}
InitTimer(&timer);
countdown_ms(&timer, pClient->command_timeout_ms);
HAL_MutexLock(pClient->lock_write_buf);
if (pParams->qos == QOS1) {
pParams->id = get_next_packet_id(pClient);
if (IOT_Log_Get_Level() <= eLOG_DEBUG) {
Log_d("publish topic seq=%d|topicName=%s|payload=%s", pParams->id, topicName, (char *)pParams->payload);
} else {
Log_i("publish topic seq=%d|topicName=%s", pParams->id, topicName);
}
} else {
if (IOT_Log_Get_Level() <= eLOG_DEBUG) {
Log_d("publish packetID=%d|topicName=%s|payload=%s", pParams->id, topicName, (char *)pParams->payload);
} else {
Log_i("publish packetID=%d|topicName=%s", pParams->id, topicName);
}
}
rc = _serialize_publish_packet(pClient->write_buf, pClient->write_buf_size, 0, pParams->qos, pParams->retained,
pParams->id, topicName, (unsigned char *)pParams->payload, pParams->payload_len,
&len);
if (QCLOUD_RET_SUCCESS != rc) {
HAL_MutexUnlock(pClient->lock_write_buf);
IOT_FUNC_EXIT_RC(rc);
}
if (pParams->qos > QOS0) {
rc = _mask_push_pubInfo_to(pClient, len, pParams->id, &node);
if (QCLOUD_RET_SUCCESS != rc) {
Log_e("push publish into to pubInfolist failed!");
HAL_MutexUnlock(pClient->lock_write_buf);
IOT_FUNC_EXIT_RC(rc);
}
}
/* send the publish packet */
rc = send_mqtt_packet(pClient, len, &timer);
if (QCLOUD_RET_SUCCESS != rc) {
if (pParams->qos > QOS0) {
HAL_MutexLock(pClient->lock_list_pub);
list_remove(pClient->list_pub_wait_ack, node);
HAL_MutexUnlock(pClient->lock_list_pub);
}
HAL_MutexUnlock(pClient->lock_write_buf);
IOT_FUNC_EXIT_RC(rc);
}
HAL_MutexUnlock(pClient->lock_write_buf);
IOT_FUNC_EXIT_RC(pParams->id);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,251 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
#include <string.h>
#include "mqtt_client.h"
/**
* Determines the length of the MQTT subscribe packet that would be produced using the supplied parameters
* @param count the number of topic filter strings in topicFilters
* @param topicFilters the array of topic filter strings to be used in the publish
* @return the length of buffer needed to contain the serialized version of the packet
*/
static uint32_t _get_subscribe_packet_rem_len(uint32_t count, char **topicFilters)
{
size_t i;
size_t len = 2; /* packetid */
for (i = 0; i < count; ++i) {
len += 2 + strlen(*topicFilters + i) + 1; /* length + topic + req_qos */
}
return (uint32_t)len;
}
/**
* Serializes the supplied subscribe data into the supplied buffer, ready for sending
* @param buf the buffer into which the packet will be serialized
* @param buf_len the length in bytes of the supplied bufferr
* @param dup integer - the MQTT dup flag
* @param packet_id integer - the MQTT packet identifier
* @param count - number of members in the topicFilters and reqQos arrays
* @param topicFilters - array of topic filter names
* @param requestedQoSs - array of requested QoS
* @return the length of the serialized data. <= 0 indicates error
*/
static int _serialize_subscribe_packet(unsigned char *buf, size_t buf_len, uint8_t dup, uint16_t packet_id,
uint32_t count, char **topicFilters, QoS *requestedQoSs,
uint32_t *serialized_len)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(serialized_len, QCLOUD_ERR_INVAL);
unsigned char *ptr = buf;
unsigned char header = 0;
uint32_t rem_len = 0;
uint32_t i = 0;
int rc;
// remaining length of SUBSCRIBE packet = packet type(2 byte) + count * (remaining length(2 byte) + topicLen + qos(1
// byte))
rem_len = _get_subscribe_packet_rem_len(count, topicFilters);
if (get_mqtt_packet_len(rem_len) > buf_len) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_BUF_TOO_SHORT);
}
// init header
rc = mqtt_init_packet_header(&header, SUBSCRIBE, QOS1, dup, 0);
if (QCLOUD_RET_SUCCESS != rc) {
IOT_FUNC_EXIT_RC(rc);
}
// 1st byte in fixed header
mqtt_write_char(&ptr, header);
// remaining length
ptr += mqtt_write_packet_rem_len(ptr, rem_len);
// variable header
mqtt_write_uint_16(&ptr, packet_id);
// payload
for (i = 0; i < count; ++i) {
mqtt_write_utf8_string(&ptr, *topicFilters + i);
mqtt_write_char(&ptr, (unsigned char)requestedQoSs[i]);
}
*serialized_len = (uint32_t)(ptr - buf);
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
int qcloud_iot_mqtt_subscribe(Qcloud_IoT_Client *pClient, char *topicFilter, SubscribeParams *pParams)
{
IOT_FUNC_ENTRY;
int rc;
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(pParams, QCLOUD_ERR_INVAL);
// POINTER_SANITY_CHECK(pParams->on_message_handler, QCLOUD_ERR_INVAL);
STRING_PTR_SANITY_CHECK(topicFilter, QCLOUD_ERR_INVAL);
Timer timer;
uint32_t len = 0;
uint16_t packet_id = 0;
ListNode *node = NULL;
size_t topicLen = strlen(topicFilter);
if (topicLen > MAX_SIZE_OF_CLOUD_TOPIC) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MAX_TOPIC_LENGTH);
}
if (pParams->qos == QOS2) {
Log_e("QoS2 is not supported currently");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_QOS_NOT_SUPPORT);
}
if (!get_client_conn_state(pClient)) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN)
}
/* topic filter should be valid in the whole sub life */
char *topic_filter_stored = HAL_Malloc(topicLen + 1);
if (topic_filter_stored == NULL) {
Log_e("malloc failed");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
strcpy(topic_filter_stored, topicFilter);
topic_filter_stored[topicLen] = 0;
InitTimer(&timer);
countdown_ms(&timer, pClient->command_timeout_ms);
HAL_MutexLock(pClient->lock_write_buf);
packet_id = get_next_packet_id(pClient);
Log_d("topicName=%s|packet_id=%d", topic_filter_stored, packet_id);
rc = _serialize_subscribe_packet(pClient->write_buf, pClient->write_buf_size, 0, packet_id, 1, &topic_filter_stored,
&pParams->qos, &len);
if (QCLOUD_RET_SUCCESS != rc) {
HAL_MutexUnlock(pClient->lock_write_buf);
HAL_Free(topic_filter_stored);
IOT_FUNC_EXIT_RC(rc);
}
/* add node into sub ack wait list */
SubTopicHandle sub_handle;
sub_handle.topic_filter = topic_filter_stored;
sub_handle.message_handler = pParams->on_message_handler;
sub_handle.sub_event_handler = pParams->on_sub_event_handler;
sub_handle.qos = pParams->qos;
sub_handle.handler_user_data = pParams->user_data;
rc = push_sub_info_to(pClient, len, (unsigned int)packet_id, SUBSCRIBE, &sub_handle, &node);
if (QCLOUD_RET_SUCCESS != rc) {
Log_e("push publish into to pubInfolist failed!");
HAL_MutexUnlock(pClient->lock_write_buf);
HAL_Free(topic_filter_stored);
IOT_FUNC_EXIT_RC(rc);
}
// send SUBSCRIBE packet
rc = send_mqtt_packet(pClient, len, &timer);
if (QCLOUD_RET_SUCCESS != rc) {
HAL_MutexLock(pClient->lock_list_sub);
list_remove(pClient->list_sub_wait_ack, node);
HAL_MutexUnlock(pClient->lock_list_sub);
HAL_MutexUnlock(pClient->lock_write_buf);
HAL_Free(topic_filter_stored);
IOT_FUNC_EXIT_RC(rc);
}
HAL_MutexUnlock(pClient->lock_write_buf);
IOT_FUNC_EXIT_RC(packet_id);
}
int qcloud_iot_mqtt_resubscribe(Qcloud_IoT_Client *pClient)
{
IOT_FUNC_ENTRY;
int rc;
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
uint32_t itr = 0;
char * topic = NULL;
SubscribeParams temp_param;
if (NULL == pClient) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
}
if (!get_client_conn_state(pClient)) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
}
for (itr = 0; itr < MAX_MESSAGE_HANDLERS; itr++) {
topic = (char *)pClient->sub_handles[itr].topic_filter;
if (topic == NULL) {
continue;
}
temp_param.on_message_handler = pClient->sub_handles[itr].message_handler;
temp_param.on_sub_event_handler = pClient->sub_handles[itr].sub_event_handler;
temp_param.qos = pClient->sub_handles[itr].qos;
temp_param.user_data = pClient->sub_handles[itr].handler_user_data;
rc = qcloud_iot_mqtt_subscribe(pClient, topic, &temp_param);
if (rc < 0) {
Log_e("resubscribe failed %d, topic: %s", rc, topic);
IOT_FUNC_EXIT_RC(rc);
}
}
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
bool qcloud_iot_mqtt_is_sub_ready(Qcloud_IoT_Client *pClient, char *topicFilter)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(pClient, false);
STRING_PTR_SANITY_CHECK(topicFilter, false);
size_t topicLen = strlen(topicFilter);
if (topicLen > MAX_SIZE_OF_CLOUD_TOPIC) {
return false;
}
int i = 0;
HAL_MutexLock(pClient->lock_generic);
for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
if ((pClient->sub_handles[i].topic_filter != NULL &&
!strcmp(pClient->sub_handles[i].topic_filter, topicFilter)) ||
strstr(topicFilter, "/#") != NULL || strstr(topicFilter, "/+") != NULL) {
HAL_MutexUnlock(pClient->lock_generic);
return true;
}
}
HAL_MutexUnlock(pClient->lock_generic);
return false;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,199 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
#include <string.h>
#include "mqtt_client.h"
/**
* Determines the length of the MQTT unsubscribe packet that would be produced using the supplied parameters
* @param count the number of topic filter strings in topicFilters
* @param topicFilters the array of topic filter strings to be used in the publish
* @return the length of buffer needed to contain the serialized version of the packet
*/
static uint32_t _get_unsubscribe_packet_rem_len(uint32_t count, char **topicFilters)
{
size_t i;
size_t len = 2; /* packetid */
for (i = 0; i < count; ++i) {
len += 2 + strlen(*topicFilters + i); /* length + topic*/
}
return (uint32_t)len;
}
/**
* Serializes the supplied unsubscribe data into the supplied buffer, ready for sending
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buf_len the length in bytes of the data in the supplied buffer
* @param dup integer - the MQTT dup flag
* @param packet_id integer - the MQTT packet identifier
* @param count - number of members in the topicFilters array
* @param topicFilters - array of topic filter names
* @param serialized_len - the length of the serialized data
* @return int indicating function execution status
*/
static int _serialize_unsubscribe_packet(unsigned char *buf, size_t buf_len, uint8_t dup, uint16_t packet_id,
uint32_t count, char **topicFilters, uint32_t *serialized_len)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(serialized_len, QCLOUD_ERR_INVAL);
unsigned char *ptr = buf;
unsigned char header = 0;
uint32_t rem_len = 0;
uint32_t i = 0;
int rc;
rem_len = _get_unsubscribe_packet_rem_len(count, topicFilters);
if (get_mqtt_packet_len(rem_len) > buf_len) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_BUF_TOO_SHORT);
}
rc = mqtt_init_packet_header(&header, UNSUBSCRIBE, QOS1, dup, 0);
if (QCLOUD_RET_SUCCESS != rc) {
IOT_FUNC_EXIT_RC(rc);
}
mqtt_write_char(&ptr, header); /* write header */
ptr += mqtt_write_packet_rem_len(ptr, rem_len); /* write remaining length */
mqtt_write_uint_16(&ptr, packet_id);
for (i = 0; i < count; ++i) {
mqtt_write_utf8_string(&ptr, *topicFilters + i);
}
*serialized_len = (uint32_t)(ptr - buf);
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
int qcloud_iot_mqtt_unsubscribe(Qcloud_IoT_Client *pClient, char *topicFilter)
{
IOT_FUNC_ENTRY;
int rc;
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
STRING_PTR_SANITY_CHECK(topicFilter, QCLOUD_ERR_INVAL);
int i = 0;
Timer timer;
uint32_t len = 0;
uint16_t packet_id = 0;
bool suber_exists = false;
ListNode *node = NULL;
size_t topicLen = strlen(topicFilter);
if (topicLen > MAX_SIZE_OF_CLOUD_TOPIC) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MAX_TOPIC_LENGTH);
}
/* Remove from message handler array */
HAL_MutexLock(pClient->lock_generic);
for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
if ((pClient->sub_handles[i].topic_filter != NULL &&
!strcmp(pClient->sub_handles[i].topic_filter, topicFilter)) ||
strstr(topicFilter, "/#") != NULL || strstr(topicFilter, "/+") != NULL) {
/* notify this event to topic subscriber */
if (NULL != pClient->sub_handles[i].sub_event_handler)
pClient->sub_handles[i].sub_event_handler(pClient, MQTT_EVENT_UNSUBSCRIBE,
pClient->sub_handles[i].handler_user_data);
/* Free the topic filter malloced in qcloud_iot_mqtt_subscribe */
HAL_Free((void *)pClient->sub_handles[i].topic_filter);
pClient->sub_handles[i].topic_filter = NULL;
/* We don't want to break here, if the same topic is registered
* with 2 callbacks. Unlikely scenario */
suber_exists = true;
}
}
HAL_MutexUnlock(pClient->lock_generic);
if (suber_exists == false) {
Log_e("subscription does not exists: %s", topicFilter);
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_UNSUB_FAIL);
}
if (!get_client_conn_state(pClient)) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
}
/* topic filter should be valid in the whole sub life */
char *topic_filter_stored = HAL_Malloc(topicLen + 1);
if (topic_filter_stored == NULL) {
Log_e("malloc failed");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
strcpy(topic_filter_stored, topicFilter);
topic_filter_stored[topicLen] = 0;
InitTimer(&timer);
countdown_ms(&timer, pClient->command_timeout_ms);
HAL_MutexLock(pClient->lock_write_buf);
packet_id = get_next_packet_id(pClient);
rc = _serialize_unsubscribe_packet(pClient->write_buf, pClient->write_buf_size, 0, packet_id, 1,
&topic_filter_stored, &len);
if (QCLOUD_RET_SUCCESS != rc) {
HAL_MutexUnlock(pClient->lock_write_buf);
HAL_Free(topic_filter_stored);
IOT_FUNC_EXIT_RC(rc);
}
SubTopicHandle sub_handle;
sub_handle.topic_filter = topic_filter_stored;
sub_handle.sub_event_handler = NULL;
sub_handle.message_handler = NULL;
sub_handle.handler_user_data = NULL;
rc = push_sub_info_to(pClient, len, (unsigned int)packet_id, UNSUBSCRIBE, &sub_handle, &node);
if (QCLOUD_RET_SUCCESS != rc) {
Log_e("push publish into to pubInfolist failed: %d", rc);
HAL_MutexUnlock(pClient->lock_write_buf);
HAL_Free(topic_filter_stored);
IOT_FUNC_EXIT_RC(rc);
}
/* send the unsubscribe packet */
rc = send_mqtt_packet(pClient, len, &timer);
if (QCLOUD_RET_SUCCESS != rc) {
HAL_MutexLock(pClient->lock_list_sub);
list_remove(pClient->list_sub_wait_ack, node);
HAL_MutexUnlock(pClient->lock_list_sub);
HAL_MutexUnlock(pClient->lock_write_buf);
HAL_Free(topic_filter_stored);
IOT_FUNC_EXIT_RC(rc);
}
HAL_MutexUnlock(pClient->lock_write_buf);
IOT_FUNC_EXIT_RC(packet_id);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,501 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Allan Stockdill-Mander/Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
#include "log_upload.h"
#include "mqtt_client.h"
#include "qcloud_iot_import.h"
static uint32_t _get_random_interval(void)
{
srand((unsigned)HAL_GetTimeMs());
/* range: 1000 - 2000 ms, in 10ms unit */
return (rand() % 100 + 100) * 10;
}
static void _iot_disconnect_callback(Qcloud_IoT_Client *pClient)
{
if (NULL != pClient->event_handle.h_fp) {
MQTTEventMsg msg;
msg.event_type = MQTT_EVENT_DISCONNECT;
msg.msg = NULL;
pClient->event_handle.h_fp(pClient, pClient->event_handle.context, &msg);
}
}
static void _reconnect_callback(Qcloud_IoT_Client *pClient)
{
if (NULL != pClient->event_handle.h_fp) {
MQTTEventMsg msg;
msg.event_type = MQTT_EVENT_RECONNECT;
msg.msg = NULL;
pClient->event_handle.h_fp(pClient, pClient->event_handle.context, &msg);
}
}
/**
* @brief handle exceptional disconnection
*
* @param pClient
* @return
*/
static int _handle_disconnect(Qcloud_IoT_Client *pClient)
{
IOT_FUNC_ENTRY;
int rc;
if (0 == get_client_conn_state(pClient)) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
}
rc = qcloud_iot_mqtt_disconnect(pClient);
// disconnect network stack by force
if (rc != QCLOUD_RET_SUCCESS) {
pClient->network_stack.disconnect(&(pClient->network_stack));
set_client_conn_state(pClient, NOTCONNECTED);
}
Log_e("disconnect MQTT for some reasons..");
_iot_disconnect_callback(pClient);
// exceptional disconnection
pClient->was_manually_disconnected = 0;
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
}
/**
* @brief handle reconnect
*
* @param pClient
* @return
*/
static int _handle_reconnect(Qcloud_IoT_Client *pClient)
{
IOT_FUNC_ENTRY;
int8_t isPhysicalLayerConnected = 1;
int rc = QCLOUD_RET_MQTT_RECONNECTED;
// reconnect control by delay timer (increase interval exponentially )
if (!expired(&(pClient->reconnect_delay_timer))) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT);
}
if (NULL != pClient->network_stack.is_connected) {
isPhysicalLayerConnected =
(int8_t)pClient->network_stack.is_connected(&(pClient->network_stack)); // always return 1
}
if (isPhysicalLayerConnected) {
rc = qcloud_iot_mqtt_attempt_reconnect(pClient);
if (rc == QCLOUD_RET_MQTT_RECONNECTED) {
Log_e("attempt to reconnect success.");
_reconnect_callback(pClient);
#ifdef LOG_UPLOAD
if (is_log_uploader_init()) {
int log_level;
if (qcloud_get_log_level(pClient, &log_level) < 0) {
Log_e("client get log topic failed: %d", rc);
}
}
#endif
IOT_FUNC_EXIT_RC(rc);
} else {
Log_e("attempt to reconnect failed, errCode: %d", rc);
rc = QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT;
}
}
pClient->current_reconnect_wait_interval *= 2;
if (MAX_RECONNECT_WAIT_INTERVAL < pClient->current_reconnect_wait_interval) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_RECONNECT_TIMEOUT);
}
countdown_ms(&(pClient->reconnect_delay_timer), pClient->current_reconnect_wait_interval);
IOT_FUNC_EXIT_RC(rc);
}
/**
* @brief handle MQTT keep alive (hearbeat with server)
*
* @param pClient
* @return
*/
static int _mqtt_keep_alive(Qcloud_IoT_Client *pClient)
{
#define MQTT_PING_RETRY_TIMES 2
IOT_FUNC_ENTRY;
int rc;
Timer timer;
uint32_t serialized_len = 0;
if (0 == pClient->options.keep_alive_interval) {
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
if (!expired(&pClient->ping_timer)) {
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
if (pClient->is_ping_outstanding >= MQTT_PING_RETRY_TIMES) {
// Reaching here means we haven't received any MQTT packet for a long time (keep_alive_interval)
Log_e("Fail to recv MQTT msg. Something wrong with the connection.");
rc = _handle_disconnect(pClient);
IOT_FUNC_EXIT_RC(rc);
}
/* there is no ping outstanding - send one */
HAL_MutexLock(pClient->lock_write_buf);
rc = serialize_packet_with_zero_payload(pClient->write_buf, pClient->write_buf_size, PINGREQ, &serialized_len);
if (QCLOUD_RET_SUCCESS != rc) {
HAL_MutexUnlock(pClient->lock_write_buf);
IOT_FUNC_EXIT_RC(rc);
}
/* send the ping packet */
int i = 0;
InitTimer(&timer);
do {
countdown_ms(&timer, pClient->command_timeout_ms);
rc = send_mqtt_packet(pClient, serialized_len, &timer);
} while (QCLOUD_RET_SUCCESS != rc && (i++ < 3));
if (QCLOUD_RET_SUCCESS != rc) {
HAL_MutexUnlock(pClient->lock_write_buf);
// If sending a PING fails, propably the connection is not OK and we decide to disconnect and begin reconnection
// attempts
Log_e("Fail to send PING request. Something wrong with the connection.");
rc = _handle_disconnect(pClient);
IOT_FUNC_EXIT_RC(rc);
}
HAL_MutexUnlock(pClient->lock_write_buf);
HAL_MutexLock(pClient->lock_generic);
pClient->is_ping_outstanding++;
/* start a timer to wait for PINGRESP from server */
countdown(&pClient->ping_timer, Min(5, pClient->options.keep_alive_interval / 2));
HAL_MutexUnlock(pClient->lock_generic);
Log_d("PING request %u has been sent...", pClient->is_ping_outstanding);
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
/**
* @brief Check connection and keep alive state, read/handle MQTT message in synchronized way
*
* @param pClient handle to MQTT client
* @param timeout_ms timeout value (unit: ms) for this operation
*
* @return QCLOUD_RET_SUCCESS when success, QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT when try reconnecing, or err code for
* failure
*/
int qcloud_iot_mqtt_yield(Qcloud_IoT_Client *pClient, uint32_t timeout_ms)
{
IOT_FUNC_ENTRY;
int rc = QCLOUD_RET_SUCCESS;
Timer timer;
uint8_t packet_type;
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
NUMBERIC_SANITY_CHECK(timeout_ms, QCLOUD_ERR_INVAL);
// 1. check if manually disconnect
if (!get_client_conn_state(pClient) && pClient->was_manually_disconnected == 1) {
IOT_FUNC_EXIT_RC(QCLOUD_RET_MQTT_MANUALLY_DISCONNECTED);
}
// 2. check connection state and if auto reconnect is enabled
if (!get_client_conn_state(pClient) && pClient->options.auto_connect_enable == 0) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
}
InitTimer(&timer);
countdown_ms(&timer, timeout_ms);
// 3. main loop for packet reading/handling and keep alive maintainance
while (!expired(&timer)) {
if (!get_client_conn_state(pClient)) {
if (pClient->current_reconnect_wait_interval > MAX_RECONNECT_WAIT_INTERVAL) {
rc = QCLOUD_ERR_MQTT_RECONNECT_TIMEOUT;
break;
}
rc = _handle_reconnect(pClient);
continue;
}
rc = cycle_for_read(pClient, &timer, &packet_type, QOS0);
if (rc == QCLOUD_RET_SUCCESS) {
/* check list of wait publish ACK to remove node that is ACKED or timeout */
qcloud_iot_mqtt_pub_info_proc(pClient);
/* check list of wait subscribe(or unsubscribe) ACK to remove node that is ACKED or timeout */
qcloud_iot_mqtt_sub_info_proc(pClient);
rc = _mqtt_keep_alive(pClient);
} else if (rc == QCLOUD_ERR_SSL_READ_TIMEOUT || rc == QCLOUD_ERR_SSL_READ ||
rc == QCLOUD_ERR_TCP_PEER_SHUTDOWN || rc == QCLOUD_ERR_TCP_READ_FAIL) {
Log_e("network read failed, rc: %d. MQTT Disconnect.", rc);
rc = _handle_disconnect(pClient);
}
if (rc == QCLOUD_ERR_MQTT_NO_CONN) {
pClient->counter_network_disconnected++;
if (pClient->options.auto_connect_enable == 1) {
pClient->current_reconnect_wait_interval = _get_random_interval();
countdown_ms(&(pClient->reconnect_delay_timer), pClient->current_reconnect_wait_interval);
// reconnect timeout
rc = QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT;
} else {
break;
}
} else if (rc != QCLOUD_RET_SUCCESS) {
break;
}
}
IOT_FUNC_EXIT_RC(rc);
}
// workaround wrapper for qcloud_iot_mqtt_yield for multi-thread mode
int qcloud_iot_mqtt_yield_mt(Qcloud_IoT_Client *mqtt_client, uint32_t timeout_ms)
{
POINTER_SANITY_CHECK(mqtt_client, QCLOUD_ERR_INVAL);
NUMBERIC_SANITY_CHECK(timeout_ms, QCLOUD_ERR_INVAL);
#ifdef MULTITHREAD_ENABLED
/* only one instance of yield is allowed in running state*/
if (mqtt_client->thread_running) {
HAL_SleepMs(timeout_ms);
return QCLOUD_RET_SUCCESS;
}
#endif
return qcloud_iot_mqtt_yield(mqtt_client, timeout_ms);
}
/**
* @brief puback waiting timeout process
*
* @param pClient reference to MQTTClient
*
*/
int qcloud_iot_mqtt_pub_info_proc(Qcloud_IoT_Client *pClient)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
HAL_MutexLock(pClient->lock_list_pub);
do {
if (0 == pClient->list_pub_wait_ack->len) {
break;
}
ListIterator *iter;
ListNode * node = NULL;
ListNode * temp_node = NULL;
if (NULL == (iter = list_iterator_new(pClient->list_pub_wait_ack, LIST_TAIL))) {
Log_e("new list failed");
break;
}
for (;;) {
node = list_iterator_next(iter);
if (NULL != temp_node) {
list_remove(pClient->list_pub_wait_ack, temp_node);
temp_node = NULL;
}
if (NULL == node) {
break; /* end of list */
}
QcloudIotPubInfo *repubInfo = (QcloudIotPubInfo *)node->val;
if (NULL == repubInfo) {
Log_e("node's value is invalid!");
temp_node = node;
continue;
}
/* remove invalid node */
if (MQTT_NODE_STATE_INVALID == repubInfo->node_state) {
temp_node = node;
continue;
}
if (!pClient->is_connected) {
continue;
}
/* check the request if timeout or not */
if (left_ms(&repubInfo->pub_start_time) > 0) {
continue;
}
HAL_MutexUnlock(pClient->lock_list_pub);
/* If wait ACK timeout, remove the node from list */
/* It is up to user to do republishing or not */
temp_node = node;
countdown_ms(&repubInfo->pub_start_time, pClient->command_timeout_ms);
HAL_MutexLock(pClient->lock_list_pub);
/* notify timeout event */
if (NULL != pClient->event_handle.h_fp) {
MQTTEventMsg msg;
msg.event_type = MQTT_EVENT_PUBLISH_TIMEOUT;
msg.msg = (void *)(uintptr_t)repubInfo->msg_id;
pClient->event_handle.h_fp(pClient, pClient->event_handle.context, &msg);
}
}
list_iterator_destroy(iter);
} while (0);
HAL_MutexUnlock(pClient->lock_list_pub);
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
/**
* @brief suback waiting timeout process
*
* @param pClient reference to MQTTClient
*
*/
int qcloud_iot_mqtt_sub_info_proc(Qcloud_IoT_Client *pClient)
{
IOT_FUNC_ENTRY;
int rc = QCLOUD_RET_SUCCESS;
if (!pClient) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
}
HAL_MutexLock(pClient->lock_list_sub);
do {
if (0 == pClient->list_sub_wait_ack->len) {
break;
}
ListIterator *iter;
ListNode * node = NULL;
ListNode * temp_node = NULL;
uint16_t packet_id = 0;
MessageTypes msg_type;
if (NULL == (iter = list_iterator_new(pClient->list_sub_wait_ack, LIST_TAIL))) {
Log_e("new list failed");
HAL_MutexUnlock(pClient->lock_list_sub);
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
for (;;) {
node = list_iterator_next(iter);
if (NULL != temp_node) {
list_remove(pClient->list_sub_wait_ack, temp_node);
temp_node = NULL;
}
if (NULL == node) {
break; /* end of list */
}
QcloudIotSubInfo *sub_info = (QcloudIotSubInfo *)node->val;
if (NULL == sub_info) {
Log_e("node's value is invalid!");
temp_node = node;
continue;
}
/* remove invalid node */
if (MQTT_NODE_STATE_INVALID == sub_info->node_state) {
temp_node = node;
continue;
}
if (pClient->is_connected <= 0) {
continue;
}
/* check the request if timeout or not */
if (left_ms(&sub_info->sub_start_time) > 0) {
continue;
}
/* When arrive here, it means timeout to wait ACK */
packet_id = sub_info->msg_id;
msg_type = sub_info->type;
/* Wait MQTT SUBSCRIBE ACK timeout */
if (NULL != pClient->event_handle.h_fp) {
MQTTEventMsg msg;
if (SUBSCRIBE == msg_type) {
/* subscribe timeout */
msg.event_type = MQTT_EVENT_SUBCRIBE_TIMEOUT;
msg.msg = (void *)(uintptr_t)packet_id;
/* notify this event to topic subscriber */
if (NULL != sub_info->handler.sub_event_handler)
sub_info->handler.sub_event_handler(pClient, MQTT_EVENT_SUBCRIBE_TIMEOUT,
sub_info->handler.handler_user_data);
} else {
/* unsubscribe timeout */
msg.event_type = MQTT_EVENT_UNSUBCRIBE_TIMEOUT;
msg.msg = (void *)(uintptr_t)packet_id;
}
pClient->event_handle.h_fp(pClient, pClient->event_handle.context, &msg);
}
if (NULL != sub_info->handler.topic_filter)
HAL_Free((void *)(sub_info->handler.topic_filter));
temp_node = node;
}
list_iterator_destroy(iter);
} while (0);
HAL_MutexUnlock(pClient->lock_list_sub);
IOT_FUNC_EXIT_RC(rc);
}
#ifdef __cplusplus
}
#endif

View 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&timestamp=%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

View 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, &param);
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, &params, &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, &params, &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);
}

View 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);
}

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View File

@@ -0,0 +1,253 @@
/*
* 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 "json_parser.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lite-utils.h"
#include "qcloud_iot_export_log.h"
#define json_debug Log_d
typedef struct JSON_NV {
int nLen;
int vLen;
int vType;
char *pN;
char *pV;
} JSON_NV;
char *json_get_object(int type, char *str)
{
char *pos = 0;
char ch = (type == JSOBJECT) ? '{' : '[';
while (str != 0 && *str != 0) {
if (*str == ' ') {
str++;
continue;
}
pos = (*str == ch) ? str : 0;
break;
}
return pos;
}
char *json_get_next_object(int type, char *str, char **key, int *key_len, char **val, int *val_len, int *val_type)
{
char JsonMark[JSTYPEMAX][2] = {{'\"', '\"'}, {'{', '}'}, {'[', ']'}, {'0', ' '}};
int iMarkDepth = 0, iValueType = JSNONE, iNameLen = 0, iValueLen = 0;
char *p_cName = 0, *p_cValue = 0, *p_cPos = str;
char lastchr = ' ';
if (type == JSOBJECT) {
/* Get Key */
p_cPos = strchr(p_cPos, '"');
if (!p_cPos) {
return 0;
}
p_cName = ++p_cPos;
p_cPos = strchr(p_cPos, '"');
if (!p_cPos) {
return 0;
}
iNameLen = p_cPos - p_cName;
/* Get Value */
p_cPos = strchr(p_cPos, ':');
}
while (p_cPos && *p_cPos) {
if (*p_cPos == '"') {
iValueType = JSSTRING;
lastchr = *p_cPos;
p_cValue = ++p_cPos;
break;
} else if (*p_cPos == '{') {
iValueType = JSOBJECT;
p_cValue = p_cPos++;
break;
} else if (*p_cPos == '[') {
iValueType = JSARRAY;
p_cValue = p_cPos++;
break;
} else if ((*p_cPos == '-') || (*p_cPos >= '0' && *p_cPos <= '9')) {
iValueType = JSNUMBER;
p_cValue = p_cPos++;
break;
} else if (*p_cPos == 't' || *p_cPos == 'T' || *p_cPos == 'f' || *p_cPos == 'F') {
iValueType = JSBOOLEAN;
p_cValue = p_cPos;
break;
} else if (*p_cPos == 'n' || *p_cPos == 'N') {
iValueType = JSNULL;
p_cValue = p_cPos;
break;
}
p_cPos++;
}
while (p_cPos && *p_cPos && iValueType > JSNONE) {
if (iValueType == JSBOOLEAN) {
int len = strlen(p_cValue);
if ((*p_cValue == 't' || *p_cValue == 'T') && len >= 4 &&
(!strncmp(p_cValue, "true", 4) || !strncmp(p_cValue, "TRUE", 4))) {
iValueLen = 4;
// p_cPos = p_cValue + iValueLen;
break;
} else if ((*p_cValue == 'f' || *p_cValue == 'F') && len >= 5 &&
(!strncmp(p_cValue, "false", 5) || !strncmp(p_cValue, "FALSE", 5))) {
iValueLen = 5;
// p_cPos = p_cValue + iValueLen;
break;
}
} else if (iValueType == JSNULL) { // support null/NULL
int nlen = strlen(p_cValue);
if ((*p_cValue == 'n' || *p_cValue == 'N') && nlen >= 4 &&
(!strncmp(p_cValue, "null", 4) || !strncmp(p_cValue, "NULL", 4))) {
iValueLen = 4;
// p_cPos = p_cValue + iValueLen;
break;
}
} else if (iValueType == JSNUMBER) {
// if (*p_cPos < '0' || *p_cPos > '9') {
if ((*p_cPos < '0' || *p_cPos > '9') && (*p_cPos != '.')) { // support float
iValueLen = p_cPos - p_cValue;
break;
}
} else if (*p_cPos == JsonMark[iValueType][1]) {
if (iMarkDepth == 0) {
iValueLen = p_cPos - p_cValue + (iValueType == JSSTRING ? 0 : 1);
p_cPos++;
if ((iValueType == JSSTRING) && (lastchr == '\\')) {
lastchr = *p_cPos;
continue;
} else {
break;
}
} else {
iMarkDepth--;
}
} else if (*p_cPos == JsonMark[iValueType][0]) {
iMarkDepth++;
}
lastchr = *p_cPos;
p_cPos++;
}
if (type == JSOBJECT) {
*key = p_cName;
*key_len = iNameLen;
}
*val = p_cValue;
*val_len = iValueLen;
*val_type = iValueType;
if (iValueType == JSSTRING) {
return p_cValue + iValueLen + 1;
} else {
return p_cValue + iValueLen;
}
}
int json_parse_name_value(char *p_cJsonStr, int iStrLen, json_parse_cb pfnCB, void *p_CBData)
{
char *pos = 0, *key = 0, *val = 0;
int klen = 0, vlen = 0, vtype = 0;
char last_char = 0;
int ret = JSON_RESULT_ERR;
if (p_cJsonStr == NULL || iStrLen == 0 || pfnCB == NULL) {
return ret;
}
if (iStrLen != strlen(p_cJsonStr)) {
Log_w("Backup last_char since %d != %d", iStrLen, (int)strlen(p_cJsonStr));
backup_json_str_last_char(p_cJsonStr, iStrLen, last_char);
}
json_object_for_each_kv(p_cJsonStr, pos, key, klen, val, vlen, vtype)
{
if (key && klen && val && vlen) {
ret = JSON_RESULT_OK;
if (JSON_PARSE_FINISH == pfnCB(key, klen, val, vlen, vtype, p_CBData)) {
break;
}
}
}
if (iStrLen != strlen(p_cJsonStr)) {
restore_json_str_last_char(p_cJsonStr, iStrLen, last_char);
}
return ret;
}
int json_get_value_by_name_cb(char *p_cName, int iNameLen, char *p_cValue, int iValueLen, int iValueType,
void *p_CBData)
{
JSON_NV *p_stNameValue = (JSON_NV *)p_CBData;
#if (JSON_DEBUG == 1)
int i;
if (p_cName) {
json_debug("Name:");
for (i = 0; i < iNameLen; i++) {
json_debug("%c", *(p_cName + i));
}
}
if (p_cValue) {
json_debug("Value:");
for (i = 0; i < iValueLen; i++) {
json_debug("%c", *(p_cValue + i));
}
}
#endif
if ((iNameLen == p_stNameValue->nLen) && !strncmp(p_cName, p_stNameValue->pN, p_stNameValue->nLen)) {
p_stNameValue->pV = p_cValue;
p_stNameValue->vLen = iValueLen;
p_stNameValue->vType = iValueType;
return JSON_PARSE_FINISH;
} else {
return JSON_PARSE_OK;
}
}
char *json_get_value_by_name(char *p_cJsonStr, int iStrLen, char *p_cName, int *p_iValueLen, int *p_iValueType)
{
JSON_NV stNV;
memset(&stNV, 0, sizeof(stNV));
stNV.pN = p_cName;
stNV.nLen = strlen(p_cName);
if (JSON_RESULT_OK == json_parse_name_value(p_cJsonStr, iStrLen, json_get_value_by_name_cb, (void *)&stNV)) {
if (p_iValueLen) {
*p_iValueLen = stNV.vLen;
}
if (p_iValueType) {
*p_iValueType = stNV.vType;
if (JSNULL == stNV.vType) {
stNV.pV = NULL;
}
}
}
return stNV.pV;
}

View File

@@ -0,0 +1,208 @@
/*
* 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 "json_parser.h"
#include "lite-utils.h"
#include "qcloud_iot_export_error.h"
#ifndef SCNi8
#define SCNi8 "hhi"
#endif
#ifndef SCNu8
#define SCNu8 "hhu"
#endif
char *LITE_json_value_of(char *key, char *src)
{
char *value = NULL;
int value_len = -1;
char *ret = NULL;
char *delim = NULL;
char *key_iter;
char *key_next;
int key_len;
char *src_iter;
src_iter = src;
key_iter = key;
do {
if ((delim = strchr(key_iter, '.')) != NULL) {
key_len = delim - key_iter;
key_next = HAL_Malloc(key_len + 1);
strncpy(key_next, key_iter, key_len);
key_next[key_len] = '\0';
value = json_get_value_by_name(src_iter, strlen(src_iter), key_next, &value_len, 0);
if (value == NULL) {
HAL_Free(key_next);
return NULL;
}
src_iter = value;
key_iter = delim + 1;
HAL_Free(key_next);
}
} while (delim);
value = json_get_value_by_name(src_iter, strlen(src_iter), key_iter, &value_len, 0);
if (NULL == value) {
return NULL;
}
ret = HAL_Malloc((value_len + 1) * sizeof(char));
if (NULL == ret) {
return NULL;
}
HAL_Snprintf(ret, value_len + 1, "%s", value);
return ret;
}
list_head_t *LITE_json_keys_of(char *src, char *prefix)
{
static LIST_HEAD(keylist);
char *pos = 0, *key = 0, *val = 0;
int klen = 0, vlen = 0, vtype = 0;
if (src == NULL || prefix == NULL) {
return NULL;
}
if (!strcmp("", prefix)) {
INIT_LIST_HEAD(&keylist);
}
json_object_for_each_kv(src, pos, key, klen, val, vlen, vtype)
{
if (key && klen && val && vlen) {
json_key_t *entry = NULL;
entry = HAL_Malloc(sizeof(json_key_t));
memset(entry, 0, sizeof(json_key_t));
entry->key = LITE_format_string("%s%.*s", prefix, klen, key);
list_add_tail(&entry->list, &keylist);
if (JSOBJECT == vtype) {
char *iter_val = LITE_format_string("%.*s", vlen, val);
char *iter_pre = LITE_format_string("%s%.*s.", prefix, klen, key);
LITE_json_keys_of(iter_val, iter_pre);
HAL_Free(iter_val);
HAL_Free(iter_pre);
}
}
}
if (!strcmp("", prefix)) {
json_key_t *entry = NULL;
entry = HAL_Malloc(sizeof(json_key_t));
memset(entry, 0, sizeof(json_key_t));
list_add_tail(&entry->list, &keylist);
return &keylist;
}
return NULL;
}
void LITE_json_keys_release(list_head_t *keylist)
{
json_key_t *pos, *tmp;
list_for_each_entry_safe(pos, tmp, keylist, list, json_key_t)
{
if (pos->key) {
HAL_Free(pos->key);
}
list_del(&pos->list);
HAL_Free(pos);
}
}
static void _strip_transfer(char *src)
{
char *end = src + strlen(src) + 1;
while (*src != '\0') {
if (*src == '\\') {
memmove(src, src + 1, end - src);
end--;
}
src++;
}
}
char *LITE_json_string_value_strip_transfer(char *key, char *src)
{
char *str = LITE_json_value_of(key, src);
if (NULL != str) {
_strip_transfer(str);
}
return str;
}
int LITE_get_int32(int32_t *value, char *src)
{
return (sscanf(src, "%" SCNi32, value) == 1) ? QCLOUD_RET_SUCCESS : QCLOUD_ERR_FAILURE;
}
int LITE_get_int16(int16_t *value, char *src)
{
return (sscanf(src, "%" SCNi16, value) == 1) ? QCLOUD_RET_SUCCESS : QCLOUD_ERR_FAILURE;
}
int LITE_get_int8(int8_t *value, char *src)
{
return (sscanf(src, "%" SCNi8, value) == 1) ? QCLOUD_RET_SUCCESS : QCLOUD_ERR_FAILURE;
}
int LITE_get_uint32(uint32_t *value, char *src)
{
return (sscanf(src, "%" SCNu32, value) == 1) ? QCLOUD_RET_SUCCESS : QCLOUD_ERR_FAILURE;
}
int LITE_get_uint16(uint16_t *value, char *src)
{
return (sscanf(src, "%" SCNu16, value) == 1) ? QCLOUD_RET_SUCCESS : QCLOUD_ERR_FAILURE;
}
int LITE_get_uint8(uint8_t *value, char *src)
{
return (sscanf(src, "%" SCNu8, value) == 1) ? QCLOUD_RET_SUCCESS : QCLOUD_ERR_FAILURE;
}
int LITE_get_float(float *value, char *src)
{
return (sscanf(src, "%f", value) == 1) ? QCLOUD_RET_SUCCESS : QCLOUD_ERR_FAILURE;
}
int LITE_get_double(double *value, char *src)
{
return (sscanf(src, "%lf", value) == 1) ? QCLOUD_RET_SUCCESS : QCLOUD_ERR_FAILURE;
}
int LITE_get_boolean(bool *value, char *src)
{
if (!strcmp(src, "false")) {
*value = false;
} else {
*value = true;
}
return QCLOUD_RET_SUCCESS;
}

View File

@@ -0,0 +1,136 @@
/*
* 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_ca.h"
#include <stdlib.h>
#include "qcloud_iot_import.h"
#ifndef AUTH_WITH_NOTLS
#if defined(AUTH_MODE_CERT) || defined(DEV_DYN_REG_ENABLED)
static const char *iot_ca_crt = {
"-----BEGIN CERTIFICATE-----\r\n"
"MIIDxTCCAq2gAwIBAgIJALM1winYO2xzMA0GCSqGSIb3DQEBCwUAMHkxCzAJBgNV\r\n"
"BAYTAkNOMRIwEAYDVQQIDAlHdWFuZ0RvbmcxETAPBgNVBAcMCFNoZW5aaGVuMRAw\r\n"
"DgYDVQQKDAdUZW5jZW50MRcwFQYDVQQLDA5UZW5jZW50IElvdGh1YjEYMBYGA1UE\r\n"
"AwwPd3d3LnRlbmNlbnQuY29tMB4XDTE3MTEyNzA0MjA1OVoXDTMyMTEyMzA0MjA1\r\n"
"OVoweTELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nRG9uZzERMA8GA1UEBwwI\r\n"
"U2hlblpoZW4xEDAOBgNVBAoMB1RlbmNlbnQxFzAVBgNVBAsMDlRlbmNlbnQgSW90\r\n"
"aHViMRgwFgYDVQQDDA93d3cudGVuY2VudC5jb20wggEiMA0GCSqGSIb3DQEBAQUA\r\n"
"A4IBDwAwggEKAoIBAQDVxwDZRVkU5WexneBEkdaKs4ehgQbzpbufrWo5Lb5gJ3i0\r\n"
"eukbOB81yAaavb23oiNta4gmMTq2F6/hAFsRv4J2bdTs5SxwEYbiYU1teGHuUQHO\r\n"
"iQsZCdNTJgcikga9JYKWcBjFEnAxKycNsmqsq4AJ0CEyZbo//IYX3czEQtYWHjp7\r\n"
"FJOlPPd1idKtFMVNG6LGXEwS/TPElE+grYOxwB7Anx3iC5ZpE5lo5tTioFTHzqbT\r\n"
"qTN7rbFZRytAPk/JXMTLgO55fldm4JZTP3GQsPzwIh4wNNKhi4yWG1o2u3hAnZDv\r\n"
"UVFV7al2zFdOfuu0KMzuLzrWrK16SPadRDd9eT17AgMBAAGjUDBOMB0GA1UdDgQW\r\n"
"BBQrr48jv4FxdKs3r0BkmJO7zH4ALzAfBgNVHSMEGDAWgBQrr48jv4FxdKs3r0Bk\r\n"
"mJO7zH4ALzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQDRSjXnBc3T\r\n"
"d9VmtTCuALXrQELY8KtM+cXYYNgtodHsxmrRMpJofsPGiqPfb82klvswpXxPK8Xx\r\n"
"SuUUo74Fo+AEyJxMrRKlbJvlEtnpSilKmG6rO9+bFq3nbeOAfat4lPl0DIscWUx3\r\n"
"ajXtvMCcSwTlF8rPgXbOaSXZidRYNqSyUjC2Q4m93Cv+KlyB+FgOke8x4aKAkf5p\r\n"
"XR8i1BN1OiMTIRYhGSfeZbVRq5kTdvtahiWFZu9DGO+hxDZObYGIxGHWPftrhBKz\r\n"
"RT16Amn780rQLWojr70q7o7QP5tO0wDPfCdFSc6CQFq/ngOzYag0kJ2F+O5U6+kS\r\n"
"QVrcRBDxzx/G\r\n"
"-----END CERTIFICATE-----"};
#endif
#ifdef OTA_USE_HTTPS
static const char *iot_https_ca_crt = {
"-----BEGIN CERTIFICATE-----\r\n"
"MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG\r\n"
"A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\r\n"
"b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw\r\n"
"MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\r\n"
"YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT\r\n"
"aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ\r\n"
"jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp\r\n"
"xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp\r\n"
"1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\r\n"
"snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ\r\n"
"U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8\r\n"
"9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E\r\n"
"BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B\r\n"
"AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz\r\n"
"yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE\r\n"
"38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP\r\n"
"AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad\r\n"
"DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME\r\n"
"HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\r\n"
"-----END CERTIFICATE-----\r\n"
"-----BEGIN CERTIFICATE-----\r\n"
"MIIEaTCCA1GgAwIBAgILBAAAAAABRE7wQkcwDQYJKoZIhvcNAQELBQAwVzELMAkG\r\n"
"A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\r\n"
"b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xNDAyMjAxMDAw\r\n"
"MDBaFw0yNDAyMjAxMDAwMDBaMGYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\r\n"
"YWxTaWduIG52LXNhMTwwOgYDVQQDEzNHbG9iYWxTaWduIE9yZ2FuaXphdGlvbiBW\r\n"
"YWxpZGF0aW9uIENBIC0gU0hBMjU2IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IB\r\n"
"DwAwggEKAoIBAQDHDmw/I5N/zHClnSDDDlM/fsBOwphJykfVI+8DNIV0yKMCLkZc\r\n"
"C33JiJ1Pi/D4nGyMVTXbv/Kz6vvjVudKRtkTIso21ZvBqOOWQ5PyDLzm+ebomchj\r\n"
"SHh/VzZpGhkdWtHUfcKc1H/hgBKueuqI6lfYygoKOhJJomIZeg0k9zfrtHOSewUj\r\n"
"mxK1zusp36QUArkBpdSmnENkiN74fv7j9R7l/tyjqORmMdlMJekYuYlZCa7pnRxt\r\n"
"Nw9KHjUgKOKv1CGLAcRFrW4rY6uSa2EKTSDtc7p8zv4WtdufgPDWi2zZCHlKT3hl\r\n"
"2pK8vjX5s8T5J4BO/5ZS5gIg4Qdz6V0rvbLxAgMBAAGjggElMIIBITAOBgNVHQ8B\r\n"
"Af8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUlt5h8b0cFilT\r\n"
"HMDMfTuDAEDmGnwwRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0\r\n"
"dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMDMGA1UdHwQsMCow\r\n"
"KKAmoCSGImh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5uZXQvcm9vdC5jcmwwPQYIKwYB\r\n"
"BQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vb2NzcC5nbG9iYWxzaWduLmNv\r\n"
"bS9yb290cjEwHwYDVR0jBBgwFoAUYHtmGkUNl8qJUC99BM00qP/8/UswDQYJKoZI\r\n"
"hvcNAQELBQADggEBAEYq7l69rgFgNzERhnF0tkZJyBAW/i9iIxerH4f4gu3K3w4s\r\n"
"32R1juUYcqeMOovJrKV3UPfvnqTgoI8UV6MqX+x+bRDmuo2wCId2Dkyy2VG7EQLy\r\n"
"XN0cvfNVlg/UBsD84iOKJHDTu/B5GqdhcIOKrwbFINihY9Bsrk8y1658GEV1BSl3\r\n"
"30JAZGSGvip2CTFvHST0mdCF/vIhCPnG9vHQWe3WVjwIKANnuvD58ZAWR65n5ryA\r\n"
"SOlCdjSXVWkkDoPWoC209fN5ikkodBpBocLTJIg1MGCUF7ThBCIxPTsvFwayuJ2G\r\n"
"K1pp74P1S8SqtCr4fKGxhZSM9AyHDPSsQPhZSZg=\r\n"
"-----END CERTIFICATE-----"};
#endif
#endif
const char *iot_ca_get()
{
#ifndef AUTH_WITH_NOTLS
#if defined(AUTH_MODE_CERT) || defined(DEV_DYN_REG_ENABLED)
return iot_ca_crt;
#else
return NULL;
#endif
#else
return NULL;
#endif
}
const char *iot_https_ca_get()
{
#ifndef AUTH_WITH_NOTLS
#ifdef OTA_USE_HTTPS
return iot_https_ca_crt;
#else
return NULL;
#endif
#else
return NULL;
#endif
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,56 @@
/*
* 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_device.h"
#include <stdbool.h>
#include <string.h>
#include "qcloud_iot_export.h"
int iot_device_info_set(DeviceInfo *device_info, const char *product_id, const char *device_name)
{
memset(device_info, 0x0, sizeof(DeviceInfo));
if ((MAX_SIZE_OF_PRODUCT_ID) < strlen(product_id)) {
Log_e("product name(%s) length:(%lu) exceeding limitation", product_id, strlen(product_id));
return QCLOUD_ERR_FAILURE;
}
if ((MAX_SIZE_OF_DEVICE_NAME) < strlen(device_name)) {
Log_e("device name(%s) length:(%lu) exceeding limitation", device_name, strlen(device_name));
return QCLOUD_ERR_FAILURE;
}
strncpy(device_info->product_id, product_id, MAX_SIZE_OF_PRODUCT_ID);
strncpy(device_info->device_name, device_name, MAX_SIZE_OF_DEVICE_NAME);
/* construct device-id(@product_id+@device_name) */
memset(device_info->client_id, 0x0, MAX_SIZE_OF_CLIENT_ID);
int ret = HAL_Snprintf(device_info->client_id, MAX_SIZE_OF_CLIENT_ID, "%s%s", product_id, device_name);
if ((ret < 0) || (ret >= MAX_SIZE_OF_CLIENT_ID)) {
Log_e("set device info failed");
return QCLOUD_ERR_FAILURE;
}
Log_i("SDK_Ver: %s, Product_ID: %s, Device_Name: %s", QCLOUD_IOT_DEVICE_SDK_VERSION, device_info->product_id,
device_info->device_name);
return QCLOUD_RET_SUCCESS;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,154 @@
/*
* 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 <string.h>
#include "log_upload.h"
#include "qcloud_iot_export_log.h"
#include "qcloud_iot_import.h"
static char *level_str[] = {"DIS", "ERR", "WRN", "INF", "DBG"};
static LogMessageHandler sg_log_message_handler = NULL;
LOG_LEVEL g_log_print_level = eLOG_INFO;
#ifdef LOG_UPLOAD
LOG_LEVEL g_log_upload_level = eLOG_ERROR;
#else
LOG_LEVEL g_log_upload_level = eLOG_DISABLE;
#endif
static const char *_get_filename(const char *p)
{
#ifdef WIN32
char ch = '\\';
#else
char ch = '/';
#endif
const char *q = strrchr(p, ch);
if (q == NULL) {
q = p;
} else {
q++;
}
return q;
}
void IOT_Log_Set_Level(LOG_LEVEL logLevel)
{
g_log_print_level = logLevel;
}
LOG_LEVEL IOT_Log_Get_Level(void)
{
return g_log_print_level;
}
void IOT_Log_Set_MessageHandler(LogMessageHandler handler)
{
sg_log_message_handler = handler;
}
void IOT_Log_Set_Upload_Level(LOG_LEVEL logLevel)
{
g_log_upload_level = logLevel;
}
LOG_LEVEL IOT_Log_Get_Upload_Level(void)
{
return g_log_upload_level;
}
int IOT_Log_Init_Uploader(LogUploadInitParams *init_params)
{
#ifdef LOG_UPLOAD
return init_log_uploader(init_params);
#else
return 0;
#endif
}
void IOT_Log_Fini_Uploader(void)
{
#ifdef LOG_UPLOAD
fini_log_uploader();
return;
#else
return;
#endif
}
int IOT_Log_Upload(bool force_upload)
{
#ifdef LOG_UPLOAD
return do_log_upload(force_upload);
#else
return 0;
#endif
}
void IOT_Log_Gen(const char *file, const char *func, const int line, const int level, const char *fmt, ...)
{
if (level > g_log_print_level && level > g_log_upload_level) {
return;
}
/* format log content */
const char *file_name = _get_filename(file);
char sg_text_buf[MAX_LOG_MSG_LEN + 1];
char *tmp_buf = sg_text_buf;
char *o = tmp_buf;
memset(tmp_buf, 0, sizeof(sg_text_buf));
char time_str[TIME_FORMAT_STR_LEN] = {0};
o += HAL_Snprintf(o, sizeof(sg_text_buf), "%s|%s|%s|%s(%d): ", level_str[level], HAL_Timer_current(time_str),
file_name, func, line);
va_list ap;
va_start(ap, fmt);
HAL_Vsnprintf(o, MAX_LOG_MSG_LEN - 2 - strlen(tmp_buf), fmt, ap);
va_end(ap);
strcat(tmp_buf, "\r\n");
#ifdef LOG_UPLOAD
/* append to upload buffer */
if (level <= g_log_upload_level) {
append_to_upload_buffer(tmp_buf, strlen(tmp_buf));
}
#endif
if (level <= g_log_print_level) {
/* customer defined log print handler */
if (sg_log_message_handler != NULL && sg_log_message_handler(tmp_buf)) {
return;
}
/* default log handler: print to console */
HAL_Printf("%s", tmp_buf);
}
return;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,165 @@
/*
* 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 "lite-utils.h"
#include "qcloud_iot_export_log.h"
#include "qcloud_iot_import.h"
char *LITE_format_string(const char *fmt, ...)
{
#define TEMP_STRING_MAXLEN (512)
va_list ap;
char * tmp = NULL;
char * dst;
int rc = -1;
va_start(ap, fmt);
tmp = HAL_Malloc(TEMP_STRING_MAXLEN);
memset(tmp, 0, TEMP_STRING_MAXLEN);
rc = HAL_Vsnprintf(tmp, TEMP_STRING_MAXLEN, fmt, ap);
va_end(ap);
LITE_ASSERT(tmp);
LITE_ASSERT(rc < 1024);
dst = LITE_strdup(tmp);
HAL_Free(tmp);
return dst;
#undef TEMP_STRING_MAXLEN
}
char *LITE_format_nstring(const int len, const char *fmt, ...)
{
va_list ap;
char * tmp = NULL;
char * dst;
int rc = -1;
va_start(ap, fmt);
tmp = HAL_Malloc(len + 2);
memset(tmp, 0, len + 2);
rc = HAL_Vsnprintf(tmp, len + 1, fmt, ap);
va_end(ap);
LITE_ASSERT(tmp);
LITE_ASSERT(rc < 1024);
dst = HAL_Malloc(len + 1);
HAL_Snprintf(dst, (len + 1), "%s", tmp);
HAL_Free(tmp);
return dst;
}
char *LITE_strdup(const char *src)
{
int len = 0;
char *dst = NULL;
if (!src) {
return NULL;
}
len = strlen(src) + 1;
if (len > 1024) {
Log_e("Too long string to duplicate, abort! len = %d", len);
return NULL;
}
dst = (char *)HAL_Malloc(sizeof(char) * len);
if (!dst) {
return NULL;
}
strncpy(dst, src, len);
return dst;
}
void LITE_hexbuf_convert(unsigned char *digest, char *out, int in_len, int uppercase)
{
static char *zEncode[] = {"0123456789abcdef", "0123456789ABCDEF"};
int j = 0;
int i = 0;
int idx = uppercase ? 1 : 0;
for (i = 0; i < in_len; i++) {
int a = digest[i];
out[j++] = zEncode[idx][(a >> 4) & 0xf];
out[j++] = zEncode[idx][a & 0xf];
}
}
static uint8_t _hexval_of_char(char hex)
{
if (LITE_isdigit(hex)) {
return (hex - '0');
}
if (hex >= 'a' && hex <= 'f') {
return (hex - 'a' + 10);
}
if (hex >= 'A' && hex <= 'F') {
return (hex - 'A' + 10);
}
return 0;
}
void LITE_hexstr_convert(char *hexstr, uint8_t *out_buf, int in_len)
{
int i = 0;
uint8_t ch0, ch1;
if (in_len % 2 != 0) {
Log_e("hexstr length (%d) is not even", in_len);
return;
}
while (i < (in_len / 2)) {
ch0 = _hexval_of_char((char)hexstr[2 * i]);
ch1 = _hexval_of_char((char)hexstr[2 * i + 1]);
out_buf[i] = (ch0 << 4 | ch1);
i++;
}
}
void LITE_replace_substr(char originalString[], char key[], char swap[])
{
int lengthOfOriginalString, lengthOfKey, lengthOfSwap, i, j, flag;
char tmp[512];
lengthOfOriginalString = strlen(originalString);
lengthOfKey = strlen(key);
lengthOfSwap = strlen(swap);
for (i = 0; i <= lengthOfOriginalString - lengthOfKey; i++) {
flag = 1;
for (j = 0; j < lengthOfKey; j++) {
if (originalString[i + j] != key[j]) {
flag = 0;
break;
}
}
if (flag) {
strcpy(tmp, originalString);
strcpy(&tmp[i], swap);
strcpy(&tmp[i + lengthOfSwap], &originalString[i + lengthOfKey]);
strcpy(originalString, tmp);
i += lengthOfSwap - 1;
lengthOfOriginalString = strlen(originalString);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,178 @@
/*
* 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 "utils_base64.h"
#include <stdint.h>
#include <stdlib.h>
static const unsigned char base64_enc_map[64] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
static const unsigned char base64_dec_map[128] = {
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 62,
127, 127, 127, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 127, 127, 127, 64, 127, 127, 127, 0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 127, 127, 127, 127, 127, 127, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 127, 127, 127, 127, 127};
#define BASE64_SIZE_T_MAX ((size_t)-1) /* SIZE_T_MAX is not standard */
int qcloud_iot_utils_base64encode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen)
{
size_t i, n;
unsigned char *p;
if (slen == 0) {
*olen = 0;
return (0);
}
n = slen / 3 + (slen % 3 != 0);
if (n > (BASE64_SIZE_T_MAX - 1) / 4) {
*olen = BASE64_SIZE_T_MAX;
return (QCLOUD_ERR_FAILURE);
}
n *= 4;
if ((dlen < n + 1) || (NULL == dst)) {
*olen = n + 1;
return (QCLOUD_ERR_FAILURE);
}
n = (slen / 3) * 3;
int C1, C2, C3;
for (i = 0, p = dst; i < n; i += 3) {
C1 = *src++;
C2 = *src++;
C3 = *src++;
*p++ = base64_enc_map[(C1 >> 2) & 0x3F];
*p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
*p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
*p++ = base64_enc_map[C3 & 0x3F];
}
if (i < slen) {
C1 = *src++;
C2 = ((i + 1) < slen) ? *src++ : 0;
*p++ = base64_enc_map[(C1 >> 2) & 0x3F];
*p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
if ((i + 1) < slen)
*p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
else
*p++ = '=';
*p++ = '=';
}
*olen = p - dst;
*p = 0;
return (0);
}
int qcloud_iot_utils_base64decode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen)
{
size_t i, n;
uint32_t j, x;
unsigned char *p;
/* First pass: check for validity and get output length */
for (i = n = j = 0; i < slen; i++) {
/* Skip spaces before checking for EOL */
x = 0;
while (i < slen && src[i] == ' ') {
++i;
++x;
}
/* Spaces at end of buffer are OK */
if (i == slen)
break;
if ((slen - i) >= 2 && src[i] == '\r' && src[i + 1] == '\n')
continue;
if (src[i] == '\n')
continue;
/* Space inside a line is an error */
if (x != 0)
return (QCLOUD_ERR_FAILURE);
if (src[i] == '=' && ++j > 2)
return (QCLOUD_ERR_FAILURE);
if (src[i] > 127 || base64_dec_map[src[i]] == 127)
return (QCLOUD_ERR_FAILURE);
if (base64_dec_map[src[i]] < 64 && j != 0)
return (QCLOUD_ERR_FAILURE);
n++;
}
if (n == 0) {
*olen = 0;
return (0);
}
n = ((n * 6) + 7) >> 3;
n -= j;
if (dst == NULL || dlen < n) {
*olen = n;
return (QCLOUD_ERR_FAILURE);
}
for (j = 3, n = x = 0, p = dst; i > 0; i--, src++) {
if (*src == '\r' || *src == '\n' || *src == ' ')
continue;
j -= (base64_dec_map[*src] == 64);
x = (x << 6) | (base64_dec_map[*src] & 0x3F);
if (++n == 4) {
n = 0;
if (j > 0)
*p++ = (unsigned char)(x >> 16);
if (j > 1)
*p++ = (unsigned char)(x >> 8);
if (j > 2)
*p++ = (unsigned char)(x);
}
}
*olen = p - dst;
return (0);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,95 @@
/*
* 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 "utils_getopt.h"
#include <stdio.h>
#include <string.h>
#include "qcloud_iot_import.h"
static int utils_opterr = 1; /* if error message should be printed */
static int utils_optind = 1; /* index into parent argv vector */
static int utils_optopt; /* character checked for validity */
static int utils_optreset = 1; /* reset getopt */
char* utils_optarg; /* argument associated with option */
int utils_getopt(int nargc, char* const* nargv, const char* options)
{
#define BADCH (int)'?'
#define BADARG (int)':'
#define EMSG ""
static char* place = EMSG; /* option letter processing */
const char* oli; /* option letter list index */
if (utils_optreset || !*place) { /* update scanning pointer */
utils_optreset = 0;
if (utils_optind >= nargc || *(place = nargv[utils_optind]) != '-') {
utils_optind = 1;
utils_optreset = 1;
place = EMSG;
return (-1);
}
place++;
}
/* option letter okay? */
if ((utils_optopt = (int)*place++) == (int)':' || !(oli = strchr(options, utils_optopt))) {
/*
* if the user didn't specify '-' as an option,
* assume it means -1.
*/
if (utils_optopt == (int)'-')
return (-1);
if (!*place)
++utils_optind;
if (utils_opterr && *options != ':')
HAL_Printf("illegal option - %c\n", utils_optopt);
return (BADCH);
}
if (*++oli != ':') { /* don't need argument */
utils_optarg = NULL;
if (!*place)
++utils_optind;
} else {
/* need an argument */
if (*place) { /* no white space */
utils_optarg = place;
} else if (nargc <= ++utils_optind) { /* no arg */
place = EMSG;
if (*options == ':')
return (BADARG);
if (utils_opterr)
HAL_Printf("option requires an argument - %c\n", utils_optopt);
return (BADCH);
} else { /* white space */
utils_optarg = nargv[utils_optind];
}
place = EMSG;
++utils_optind;
}
/* dump back option letter */
return (utils_optopt);
}

View File

@@ -0,0 +1,127 @@
/*
* 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 "utils_hmac.h"
#include <string.h>
#include "qcloud_iot_export_log.h"
#include "utils_md5.h"
#include "utils_sha1.h"
#define KEY_IOPAD_SIZE 64
#define MD5_DIGEST_SIZE 16
#define SHA1_DIGEST_SIZE 20
void utils_hmac_md5(const char *msg, int msg_len, char *digest, const char *key, int key_len)
{
if ((NULL == msg) || (NULL == digest) || (NULL == key)) {
Log_e("parameter is Null,failed!");
return;
}
if (key_len > KEY_IOPAD_SIZE) {
Log_e("key_len > size(%d) of array", KEY_IOPAD_SIZE);
return;
}
iot_md5_context context;
unsigned char k_ipad[KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad */
unsigned char k_opad[KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */
unsigned char out[MD5_DIGEST_SIZE];
int i;
/* start out by storing key in pads */
memset(k_ipad, 0, sizeof(k_ipad));
memset(k_opad, 0, sizeof(k_opad));
memcpy(k_ipad, key, key_len);
memcpy(k_opad, key, key_len);
/* XOR key with ipad and opad values */
for (i = 0; i < KEY_IOPAD_SIZE; i++) {
k_ipad[i] ^= 0x36;
k_opad[i] ^= 0x5c;
}
/* perform inner MD5 */
utils_md5_init(&context); /* init context for 1st pass */
utils_md5_starts(&context); /* setup context for 1st pass */
utils_md5_update(&context, k_ipad, KEY_IOPAD_SIZE); /* start with inner pad */
utils_md5_update(&context, (unsigned char *)msg, msg_len); /* then text of datagram */
utils_md5_finish(&context, out); /* finish up 1st pass */
/* perform outer MD5 */
utils_md5_init(&context); /* init context for 2nd pass */
utils_md5_starts(&context); /* setup context for 2nd pass */
utils_md5_update(&context, k_opad, KEY_IOPAD_SIZE); /* start with outer pad */
utils_md5_update(&context, out, MD5_DIGEST_SIZE); /* then results of 1st hash */
utils_md5_finish(&context, out); /* finish up 2nd pass */
for (i = 0; i < MD5_DIGEST_SIZE; ++i) {
digest[i * 2] = utils_hb2hex(out[i] >> 4);
digest[i * 2 + 1] = utils_hb2hex(out[i]);
}
}
void utils_hmac_sha1(const char *msg, int msg_len, char *digest, const char *key, int key_len)
{
if ((NULL == msg) || (NULL == digest) || (NULL == key)) {
Log_e("parameter is Null,failed!");
return;
}
if (key_len > KEY_IOPAD_SIZE) {
Log_e("key_len > size(%d) of array", KEY_IOPAD_SIZE);
return;
}
iot_sha1_context context;
unsigned char k_ipad[KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad */
unsigned char k_opad[KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */
unsigned char out[SHA1_DIGEST_SIZE];
int i;
/* start out by storing key in pads */
memset(k_ipad, 0, sizeof(k_ipad));
memset(k_opad, 0, sizeof(k_opad));
memcpy(k_ipad, key, key_len);
memcpy(k_opad, key, key_len);
/* XOR key with ipad and opad values */
for (i = 0; i < KEY_IOPAD_SIZE; i++) {
k_ipad[i] ^= 0x36;
k_opad[i] ^= 0x5c;
}
/* perform inner SHA */
utils_sha1_init(&context); /* init context for 1st pass */
utils_sha1_starts(&context); /* setup context for 1st pass */
utils_sha1_update(&context, k_ipad, KEY_IOPAD_SIZE); /* start with inner pad */
utils_sha1_update(&context, (unsigned char *)msg, msg_len); /* then text of datagram */
utils_sha1_finish(&context, out); /* finish up 1st pass */
/* perform outer SHA */
utils_sha1_init(&context); /* init context for 2nd pass */
utils_sha1_starts(&context); /* setup context for 2nd pass */
utils_sha1_update(&context, k_opad, KEY_IOPAD_SIZE); /* start with outer pad */
utils_sha1_update(&context, out, SHA1_DIGEST_SIZE); /* then results of 1st hash */
utils_sha1_finish(&context, out); /* finish up 2nd pass */
for (i = 0; i < SHA1_DIGEST_SIZE; ++i) {
digest[i * 2] = utils_hb2hex(out[i] >> 4);
digest[i * 2 + 1] = utils_hb2hex(out[i]);
}
}

View File

@@ -0,0 +1,297 @@
/*
* 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 "utils_list.h"
#include "qcloud_iot_export_log.h"
#include "qcloud_iot_import.h"
/*
* create list, return NULL if fail
*/
List *list_new(void)
{
List *self;
self = (List *)HAL_Malloc(sizeof(List));
if (!self) {
return NULL;
}
self->head = NULL;
self->tail = NULL;
self->free = NULL;
self->match = NULL;
self->len = 0;
return self;
}
/*
* destroy list
*/
void list_destroy(List *self)
{
unsigned int len = self->len;
ListNode * next;
ListNode * curr = self->head;
while (len--) {
next = curr->next;
if (self->free) {
self->free(curr->val);
}
HAL_Free(curr);
curr = next;
}
HAL_Free(self);
}
/*
* push the node to list tail, return NULL if node invalid
*/
ListNode *list_rpush(List *self, ListNode *node)
{
if (!node) {
return NULL;
}
if (self->len) {
node->prev = self->tail;
node->next = NULL;
self->tail->next = node;
self->tail = node;
} else {
self->head = self->tail = node;
node->prev = node->next = NULL;
}
++self->len;
return node;
}
/*
* pop the node from list tail, return NULL if list empty
*/
ListNode *list_rpop(List *self)
{
ListNode *node = NULL;
if (!self->len) {
return NULL;
}
node = self->tail;
if (--self->len) {
(self->tail = node->prev)->next = NULL;
} else {
self->tail = self->head = NULL;
}
node->next = node->prev = NULL;
return node;
}
/*
* pop the node from list headl, return NULL if list empty
*/
ListNode *list_lpop(List *self)
{
ListNode *node = NULL;
if (!self->len) {
return NULL;
}
node = self->head;
if (--self->len) {
(self->head = node->next)->prev = NULL;
} else {
self->head = self->tail = NULL;
}
node->next = node->prev = NULL;
return node;
}
/*
* push the node to list head, return NULL if node invalid
*/
ListNode *list_lpush(List *self, ListNode *node)
{
if (!node) {
return NULL;
}
if (self->len) {
node->next = self->head;
node->prev = NULL;
self->head->prev = node;
self->head = node;
} else {
self->head = self->tail = node;
node->prev = node->next = NULL;
}
++self->len;
return node;
}
/*
* find the node via node value, return NULL if not found
*/
ListNode *list_find(List *self, void *val)
{
ListIterator *it;
ListNode * node;
if (NULL == (it = list_iterator_new(self, LIST_HEAD))) {
return NULL;
}
node = list_iterator_next(it);
while (node) {
if (self->match) {
if (self->match(val, node->val)) {
list_iterator_destroy(it);
return node;
}
} else {
if (val == node->val) {
list_iterator_destroy(it);
return node;
}
}
node = list_iterator_next(it);
}
list_iterator_destroy(it);
return NULL;
}
/*
* find the node via list index, return NULL if not found
*/
ListNode *list_at(List *self, int index)
{
ListDirection direction = LIST_HEAD;
if (index < 0) {
direction = LIST_TAIL;
index = ~index;
}
if ((unsigned)index < self->len) {
ListIterator *it;
ListNode * node;
if (NULL == (it = list_iterator_new(self, direction))) {
return NULL;
}
node = list_iterator_next(it);
while (index--) {
node = list_iterator_next(it);
}
list_iterator_destroy(it);
return node;
}
return NULL;
}
/*
* delete the node in list and release the resource
*/
void list_remove(List *self, ListNode *node)
{
node->prev ? (node->prev->next = node->next) : (self->head = node->next);
node->next ? (node->next->prev = node->prev) : (self->tail = node->prev);
if (self->free) {
self->free(node->val);
}
HAL_Free(node);
if (self->len)
--self->len;
}
/*
* create a new ListIterator and set the ListDirection.
*/
ListIterator *list_iterator_new(List *list, ListDirection direction)
{
ListNode *node = direction == LIST_HEAD ? list->head : list->tail;
return list_iterator_new_from_node(node, direction);
}
/*
* create a new ListIterator and set the ListDirection and node
*/
ListIterator *list_iterator_new_from_node(ListNode *node, ListDirection direction)
{
ListIterator *self;
self = HAL_Malloc(sizeof(ListIterator));
if (!self) {
return NULL;
}
self->next = node;
self->direction = direction;
return self;
}
/*
* return next node
*/
ListNode *list_iterator_next(ListIterator *self)
{
ListNode *curr = self->next;
if (curr) {
self->next = self->direction == LIST_HEAD ? curr->next : curr->prev;
}
return curr;
}
/*
* release the ListIterator
*/
void list_iterator_destroy(ListIterator *self)
{
HAL_Free(self);
}
/*
* create a new node and set the value
*/
ListNode *list_node_new(void *val)
{
ListNode *self;
self = HAL_Malloc(sizeof(ListNode));
if (!self) {
return NULL;
}
self->prev = NULL;
self->next = NULL;
self->val = val;
return self;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,309 @@
/*
* 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 "utils_md5.h"
#include <stdlib.h>
#include <string.h>
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#define MD5_DIGEST_SIZE 16
/* Implementation that should never be optimized out by the compiler */
static void _utils_md5_zeroize(void *v, size_t n)
{
volatile unsigned char *p = v;
while (n--) *p++ = 0;
}
/*
* 32-bit integer manipulation macros (little endian)
*/
#ifndef IOT_MD5_GET_UINT32_LE
#define IOT_MD5_GET_UINT32_LE(n, b, i) \
{ \
(n) = ((uint32_t)(b)[(i)]) | ((uint32_t)(b)[(i) + 1] << 8) | ((uint32_t)(b)[(i) + 2] << 16) | \
((uint32_t)(b)[(i) + 3] << 24); \
}
#endif
#ifndef IOT_MD5_PUT_UINT32_LE
#define IOT_MD5_PUT_UINT32_LE(n, b, i) \
{ \
(b)[(i)] = (unsigned char)(((n)) & 0xFF); \
(b)[(i) + 1] = (unsigned char)(((n) >> 8) & 0xFF); \
(b)[(i) + 2] = (unsigned char)(((n) >> 16) & 0xFF); \
(b)[(i) + 3] = (unsigned char)(((n) >> 24) & 0xFF); \
}
#endif
void utils_md5_init(iot_md5_context *ctx)
{
memset(ctx, 0, sizeof(iot_md5_context));
}
void utils_md5_free(iot_md5_context *ctx)
{
if (ctx == NULL) {
return;
}
_utils_md5_zeroize(ctx, sizeof(iot_md5_context));
}
void utils_md5_clone(iot_md5_context *dst, const iot_md5_context *src)
{
*dst = *src;
}
/*
* MD5 context setup
*/
void utils_md5_starts(iot_md5_context *ctx)
{
ctx->total[0] = 0;
ctx->total[1] = 0;
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
}
void utils_md5_process(iot_md5_context *ctx, const unsigned char data[64])
{
uint32_t X[16], A, B, C, D;
IOT_MD5_GET_UINT32_LE(X[0], data, 0);
IOT_MD5_GET_UINT32_LE(X[1], data, 4);
IOT_MD5_GET_UINT32_LE(X[2], data, 8);
IOT_MD5_GET_UINT32_LE(X[3], data, 12);
IOT_MD5_GET_UINT32_LE(X[4], data, 16);
IOT_MD5_GET_UINT32_LE(X[5], data, 20);
IOT_MD5_GET_UINT32_LE(X[6], data, 24);
IOT_MD5_GET_UINT32_LE(X[7], data, 28);
IOT_MD5_GET_UINT32_LE(X[8], data, 32);
IOT_MD5_GET_UINT32_LE(X[9], data, 36);
IOT_MD5_GET_UINT32_LE(X[10], data, 40);
IOT_MD5_GET_UINT32_LE(X[11], data, 44);
IOT_MD5_GET_UINT32_LE(X[12], data, 48);
IOT_MD5_GET_UINT32_LE(X[13], data, 52);
IOT_MD5_GET_UINT32_LE(X[14], data, 56);
IOT_MD5_GET_UINT32_LE(X[15], data, 60);
#define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
#define P(a, b, c, d, k, s, t) \
{ \
a += F(b, c, d) + X[k] + t; \
a = S(a, s) + b; \
}
A = ctx->state[0];
B = ctx->state[1];
C = ctx->state[2];
D = ctx->state[3];
#define F(x, y, z) (z ^ (x & (y ^ z)))
P(A, B, C, D, 0, 7, 0xD76AA478);
P(D, A, B, C, 1, 12, 0xE8C7B756);
P(C, D, A, B, 2, 17, 0x242070DB);
P(B, C, D, A, 3, 22, 0xC1BDCEEE);
P(A, B, C, D, 4, 7, 0xF57C0FAF);
P(D, A, B, C, 5, 12, 0x4787C62A);
P(C, D, A, B, 6, 17, 0xA8304613);
P(B, C, D, A, 7, 22, 0xFD469501);
P(A, B, C, D, 8, 7, 0x698098D8);
P(D, A, B, C, 9, 12, 0x8B44F7AF);
P(C, D, A, B, 10, 17, 0xFFFF5BB1);
P(B, C, D, A, 11, 22, 0x895CD7BE);
P(A, B, C, D, 12, 7, 0x6B901122);
P(D, A, B, C, 13, 12, 0xFD987193);
P(C, D, A, B, 14, 17, 0xA679438E);
P(B, C, D, A, 15, 22, 0x49B40821);
#undef F
#define F(x, y, z) (y ^ (z & (x ^ y)))
P(A, B, C, D, 1, 5, 0xF61E2562);
P(D, A, B, C, 6, 9, 0xC040B340);
P(C, D, A, B, 11, 14, 0x265E5A51);
P(B, C, D, A, 0, 20, 0xE9B6C7AA);
P(A, B, C, D, 5, 5, 0xD62F105D);
P(D, A, B, C, 10, 9, 0x02441453);
P(C, D, A, B, 15, 14, 0xD8A1E681);
P(B, C, D, A, 4, 20, 0xE7D3FBC8);
P(A, B, C, D, 9, 5, 0x21E1CDE6);
P(D, A, B, C, 14, 9, 0xC33707D6);
P(C, D, A, B, 3, 14, 0xF4D50D87);
P(B, C, D, A, 8, 20, 0x455A14ED);
P(A, B, C, D, 13, 5, 0xA9E3E905);
P(D, A, B, C, 2, 9, 0xFCEFA3F8);
P(C, D, A, B, 7, 14, 0x676F02D9);
P(B, C, D, A, 12, 20, 0x8D2A4C8A);
#undef F
#define F(x, y, z) (x ^ y ^ z)
P(A, B, C, D, 5, 4, 0xFFFA3942);
P(D, A, B, C, 8, 11, 0x8771F681);
P(C, D, A, B, 11, 16, 0x6D9D6122);
P(B, C, D, A, 14, 23, 0xFDE5380C);
P(A, B, C, D, 1, 4, 0xA4BEEA44);
P(D, A, B, C, 4, 11, 0x4BDECFA9);
P(C, D, A, B, 7, 16, 0xF6BB4B60);
P(B, C, D, A, 10, 23, 0xBEBFBC70);
P(A, B, C, D, 13, 4, 0x289B7EC6);
P(D, A, B, C, 0, 11, 0xEAA127FA);
P(C, D, A, B, 3, 16, 0xD4EF3085);
P(B, C, D, A, 6, 23, 0x04881D05);
P(A, B, C, D, 9, 4, 0xD9D4D039);
P(D, A, B, C, 12, 11, 0xE6DB99E5);
P(C, D, A, B, 15, 16, 0x1FA27CF8);
P(B, C, D, A, 2, 23, 0xC4AC5665);
#undef F
#define F(x, y, z) (y ^ (x | ~z))
P(A, B, C, D, 0, 6, 0xF4292244);
P(D, A, B, C, 7, 10, 0x432AFF97);
P(C, D, A, B, 14, 15, 0xAB9423A7);
P(B, C, D, A, 5, 21, 0xFC93A039);
P(A, B, C, D, 12, 6, 0x655B59C3);
P(D, A, B, C, 3, 10, 0x8F0CCC92);
P(C, D, A, B, 10, 15, 0xFFEFF47D);
P(B, C, D, A, 1, 21, 0x85845DD1);
P(A, B, C, D, 8, 6, 0x6FA87E4F);
P(D, A, B, C, 15, 10, 0xFE2CE6E0);
P(C, D, A, B, 6, 15, 0xA3014314);
P(B, C, D, A, 13, 21, 0x4E0811A1);
P(A, B, C, D, 4, 6, 0xF7537E82);
P(D, A, B, C, 11, 10, 0xBD3AF235);
P(C, D, A, B, 2, 15, 0x2AD7D2BB);
P(B, C, D, A, 9, 21, 0xEB86D391);
#undef F
ctx->state[0] += A;
ctx->state[1] += B;
ctx->state[2] += C;
ctx->state[3] += D;
}
/*
* MD5 process buffer
*/
void utils_md5_update(iot_md5_context *ctx, const unsigned char *input, size_t ilen)
{
size_t fill;
uint32_t left;
if (ilen == 0) {
return;
}
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += (uint32_t)ilen;
ctx->total[0] &= 0xFFFFFFFF;
if (ctx->total[0] < (uint32_t)ilen) {
ctx->total[1]++;
}
if (left && ilen >= fill) {
memcpy((void *)(ctx->buffer + left), input, fill);
utils_md5_process(ctx, ctx->buffer);
input += fill;
ilen -= fill;
left = 0;
}
while (ilen >= 64) {
utils_md5_process(ctx, input);
input += 64;
ilen -= 64;
}
if (ilen > 0) {
memcpy((void *)(ctx->buffer + left), input, ilen);
}
}
static const unsigned char iot_md5_padding[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
/*
* MD5 final digest
*/
void utils_md5_finish(iot_md5_context *ctx, unsigned char output[16])
{
uint32_t last, padn;
uint32_t high, low;
unsigned char msglen[8];
high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
low = (ctx->total[0] << 3);
IOT_MD5_PUT_UINT32_LE(low, msglen, 0);
IOT_MD5_PUT_UINT32_LE(high, msglen, 4);
last = ctx->total[0] & 0x3F;
padn = (last < 56) ? (56 - last) : (120 - last);
utils_md5_update(ctx, iot_md5_padding, padn);
utils_md5_update(ctx, msglen, 8);
IOT_MD5_PUT_UINT32_LE(ctx->state[0], output, 0);
IOT_MD5_PUT_UINT32_LE(ctx->state[1], output, 4);
IOT_MD5_PUT_UINT32_LE(ctx->state[2], output, 8);
IOT_MD5_PUT_UINT32_LE(ctx->state[3], output, 12);
}
/*
* output = MD5( input buffer )
*/
void utils_md5(const unsigned char *input, size_t ilen, unsigned char output[16])
{
iot_md5_context ctx;
utils_md5_init(&ctx);
utils_md5_starts(&ctx);
utils_md5_update(&ctx, input, ilen);
utils_md5_finish(&ctx, output);
utils_md5_free(&ctx);
}
int8_t utils_hb2hex(uint8_t hb)
{
hb = hb & 0xF;
return (int8_t)(hb < 10 ? '0' + hb : hb - 10 + 'a');
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,90 @@
/*
* 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 "utils_ringbuff.h"
#include <stdio.h>
#include <string.h>
int ring_buff_init(sRingbuff* ring_buff, char* buff, uint32_t size)
{
ring_buff->buffer = buff;
ring_buff->size = size;
ring_buff->readpoint = 0;
ring_buff->writepoint = 0;
memset(ring_buff->buffer, 0, ring_buff->size);
ring_buff->full = false;
return RINGBUFF_OK;
}
int ring_buff_flush(sRingbuff* ring_buff)
{
ring_buff->readpoint = 0;
ring_buff->writepoint = 0;
memset(ring_buff->buffer, 0, ring_buff->size);
ring_buff->full = false;
return RINGBUFF_OK;
}
int ring_buff_push_data(sRingbuff* ring_buff, uint8_t* pData, int len)
{
int i;
if (len > ring_buff->size) {
return RINGBUFF_TOO_SHORT;
}
for (i = 0; i < len; i++) {
if (((ring_buff->writepoint + 1) % ring_buff->size) == ring_buff->readpoint) {
ring_buff->full = true;
return RINGBUFF_FULL;
} else {
if (ring_buff->writepoint < (ring_buff->size - 1)) {
ring_buff->writepoint++;
} else {
ring_buff->writepoint = 0;
}
ring_buff->buffer[ring_buff->writepoint] = pData[i];
}
}
return RINGBUFF_OK;
}
int ring_buff_pop_data(sRingbuff* ring_buff, uint8_t* pData, int len)
{
int i;
if (len > ring_buff->size) {
return RINGBUFF_TOO_SHORT;
}
for (i = 0; i < len; i++) {
if (ring_buff->writepoint == ring_buff->readpoint) {
break;
} else {
if (ring_buff->readpoint == (ring_buff->size - 1)) {
ring_buff->readpoint = 0;
} else {
ring_buff->readpoint++;
}
pData[i] = ring_buff->buffer[ring_buff->readpoint];
}
}
return i;
}

View File

@@ -0,0 +1,326 @@
/*
* 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 "utils_sha1.h"
#include <stdlib.h>
#include <string.h>
#include "qcloud_iot_export_log.h"
#include "qcloud_iot_import.h"
/* Implementation that should never be optimized out by the compiler */
static void utils_sha1_zeroize(void *v, size_t n)
{
volatile unsigned char *p = v;
while (n--) {
*p++ = 0;
}
}
/*
* 32-bit integer manipulation macros (big endian)
*/
#ifndef IOT_SHA1_GET_UINT32_BE
#define IOT_SHA1_GET_UINT32_BE(n, b, i) \
{ \
(n) = ((uint32_t)(b)[(i)] << 24) | ((uint32_t)(b)[(i) + 1] << 16) | ((uint32_t)(b)[(i) + 2] << 8) | \
((uint32_t)(b)[(i) + 3]); \
}
#endif
#ifndef IOT_SHA1_PUT_UINT32_BE
#define IOT_SHA1_PUT_UINT32_BE(n, b, i) \
{ \
(b)[(i)] = (unsigned char)((n) >> 24); \
(b)[(i) + 1] = (unsigned char)((n) >> 16); \
(b)[(i) + 2] = (unsigned char)((n) >> 8); \
(b)[(i) + 3] = (unsigned char)((n)); \
}
#endif
void utils_sha1_init(iot_sha1_context *ctx)
{
memset(ctx, 0, sizeof(iot_sha1_context));
}
void utils_sha1_free(iot_sha1_context *ctx)
{
if (ctx == NULL) {
return;
}
utils_sha1_zeroize(ctx, sizeof(iot_sha1_context));
}
void utils_sha1_clone(iot_sha1_context *dst, const iot_sha1_context *src)
{
*dst = *src;
}
/*
* SHA-1 context setup
*/
void utils_sha1_starts(iot_sha1_context *ctx)
{
ctx->total[0] = 0;
ctx->total[1] = 0;
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
ctx->state[4] = 0xC3D2E1F0;
}
void utils_sha1_process(iot_sha1_context *ctx, const unsigned char data[64])
{
uint32_t temp, W[16], A, B, C, D, E;
IOT_SHA1_GET_UINT32_BE(W[0], data, 0);
IOT_SHA1_GET_UINT32_BE(W[1], data, 4);
IOT_SHA1_GET_UINT32_BE(W[2], data, 8);
IOT_SHA1_GET_UINT32_BE(W[3], data, 12);
IOT_SHA1_GET_UINT32_BE(W[4], data, 16);
IOT_SHA1_GET_UINT32_BE(W[5], data, 20);
IOT_SHA1_GET_UINT32_BE(W[6], data, 24);
IOT_SHA1_GET_UINT32_BE(W[7], data, 28);
IOT_SHA1_GET_UINT32_BE(W[8], data, 32);
IOT_SHA1_GET_UINT32_BE(W[9], data, 36);
IOT_SHA1_GET_UINT32_BE(W[10], data, 40);
IOT_SHA1_GET_UINT32_BE(W[11], data, 44);
IOT_SHA1_GET_UINT32_BE(W[12], data, 48);
IOT_SHA1_GET_UINT32_BE(W[13], data, 52);
IOT_SHA1_GET_UINT32_BE(W[14], data, 56);
IOT_SHA1_GET_UINT32_BE(W[15], data, 60);
#define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
#define R(t) \
(temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ W[(t - 14) & 0x0F] ^ W[t & 0x0F], (W[t & 0x0F] = S(temp, 1)))
#define P(a, b, c, d, e, x) \
{ \
e += S(a, 5) + F(b, c, d) + K + x; \
b = S(b, 30); \
}
A = ctx->state[0];
B = ctx->state[1];
C = ctx->state[2];
D = ctx->state[3];
E = ctx->state[4];
#define F(x, y, z) (z ^ (x & (y ^ z)))
#define K 0x5A827999
P(A, B, C, D, E, W[0]);
P(E, A, B, C, D, W[1]);
P(D, E, A, B, C, W[2]);
P(C, D, E, A, B, W[3]);
P(B, C, D, E, A, W[4]);
P(A, B, C, D, E, W[5]);
P(E, A, B, C, D, W[6]);
P(D, E, A, B, C, W[7]);
P(C, D, E, A, B, W[8]);
P(B, C, D, E, A, W[9]);
P(A, B, C, D, E, W[10]);
P(E, A, B, C, D, W[11]);
P(D, E, A, B, C, W[12]);
P(C, D, E, A, B, W[13]);
P(B, C, D, E, A, W[14]);
P(A, B, C, D, E, W[15]);
P(E, A, B, C, D, R(16));
P(D, E, A, B, C, R(17));
P(C, D, E, A, B, R(18));
P(B, C, D, E, A, R(19));
#undef K
#undef F
#define F(x, y, z) (x ^ y ^ z)
#define K 0x6ED9EBA1
P(A, B, C, D, E, R(20));
P(E, A, B, C, D, R(21));
P(D, E, A, B, C, R(22));
P(C, D, E, A, B, R(23));
P(B, C, D, E, A, R(24));
P(A, B, C, D, E, R(25));
P(E, A, B, C, D, R(26));
P(D, E, A, B, C, R(27));
P(C, D, E, A, B, R(28));
P(B, C, D, E, A, R(29));
P(A, B, C, D, E, R(30));
P(E, A, B, C, D, R(31));
P(D, E, A, B, C, R(32));
P(C, D, E, A, B, R(33));
P(B, C, D, E, A, R(34));
P(A, B, C, D, E, R(35));
P(E, A, B, C, D, R(36));
P(D, E, A, B, C, R(37));
P(C, D, E, A, B, R(38));
P(B, C, D, E, A, R(39));
#undef K
#undef F
#define F(x, y, z) ((x & y) | (z & (x | y)))
#define K 0x8F1BBCDC
P(A, B, C, D, E, R(40));
P(E, A, B, C, D, R(41));
P(D, E, A, B, C, R(42));
P(C, D, E, A, B, R(43));
P(B, C, D, E, A, R(44));
P(A, B, C, D, E, R(45));
P(E, A, B, C, D, R(46));
P(D, E, A, B, C, R(47));
P(C, D, E, A, B, R(48));
P(B, C, D, E, A, R(49));
P(A, B, C, D, E, R(50));
P(E, A, B, C, D, R(51));
P(D, E, A, B, C, R(52));
P(C, D, E, A, B, R(53));
P(B, C, D, E, A, R(54));
P(A, B, C, D, E, R(55));
P(E, A, B, C, D, R(56));
P(D, E, A, B, C, R(57));
P(C, D, E, A, B, R(58));
P(B, C, D, E, A, R(59));
#undef K
#undef F
#define F(x, y, z) (x ^ y ^ z)
#define K 0xCA62C1D6
P(A, B, C, D, E, R(60));
P(E, A, B, C, D, R(61));
P(D, E, A, B, C, R(62));
P(C, D, E, A, B, R(63));
P(B, C, D, E, A, R(64));
P(A, B, C, D, E, R(65));
P(E, A, B, C, D, R(66));
P(D, E, A, B, C, R(67));
P(C, D, E, A, B, R(68));
P(B, C, D, E, A, R(69));
P(A, B, C, D, E, R(70));
P(E, A, B, C, D, R(71));
P(D, E, A, B, C, R(72));
P(C, D, E, A, B, R(73));
P(B, C, D, E, A, R(74));
P(A, B, C, D, E, R(75));
P(E, A, B, C, D, R(76));
P(D, E, A, B, C, R(77));
P(C, D, E, A, B, R(78));
P(B, C, D, E, A, R(79));
#undef K
#undef F
ctx->state[0] += A;
ctx->state[1] += B;
ctx->state[2] += C;
ctx->state[3] += D;
ctx->state[4] += E;
}
/*
* SHA-1 process buffer
*/
void utils_sha1_update(iot_sha1_context *ctx, const unsigned char *input, size_t ilen)
{
size_t fill;
uint32_t left;
if (ilen == 0) {
return;
}
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += (uint32_t)ilen;
ctx->total[0] &= 0xFFFFFFFF;
if (ctx->total[0] < (uint32_t)ilen) {
ctx->total[1]++;
}
if (left && ilen >= fill) {
memcpy((void *)(ctx->buffer + left), input, fill);
utils_sha1_process(ctx, ctx->buffer);
input += fill;
ilen -= fill;
left = 0;
}
while (ilen >= 64) {
utils_sha1_process(ctx, input);
input += 64;
ilen -= 64;
}
if (ilen > 0) {
memcpy((void *)(ctx->buffer + left), input, ilen);
}
}
static const unsigned char iot_sha1_padding[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
/*
* SHA-1 final digest
*/
void utils_sha1_finish(iot_sha1_context *ctx, unsigned char output[20])
{
uint32_t last, padn;
uint32_t high, low;
unsigned char msglen[8];
high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
low = (ctx->total[0] << 3);
IOT_SHA1_PUT_UINT32_BE(high, msglen, 0);
IOT_SHA1_PUT_UINT32_BE(low, msglen, 4);
last = ctx->total[0] & 0x3F;
padn = (last < 56) ? (56 - last) : (120 - last);
utils_sha1_update(ctx, iot_sha1_padding, padn);
utils_sha1_update(ctx, msglen, 8);
IOT_SHA1_PUT_UINT32_BE(ctx->state[0], output, 0);
IOT_SHA1_PUT_UINT32_BE(ctx->state[1], output, 4);
IOT_SHA1_PUT_UINT32_BE(ctx->state[2], output, 8);
IOT_SHA1_PUT_UINT32_BE(ctx->state[3], output, 12);
IOT_SHA1_PUT_UINT32_BE(ctx->state[4], output, 16);
}
/*
* output = SHA-1( input buffer )
*/
void utils_sha1(const unsigned char *input, size_t ilen, unsigned char output[20])
{
iot_sha1_context ctx;
utils_sha1_init(&ctx);
utils_sha1_starts(&ctx);
utils_sha1_update(&ctx, input, ilen);
utils_sha1_finish(&ctx, output);
utils_sha1_free(&ctx);
}

View File

@@ -0,0 +1,49 @@
/*
* 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 "utils_timer.h"
bool expired(Timer *timer)
{
return HAL_Timer_expired(timer);
}
void countdown_ms(Timer *timer, unsigned int timeout_ms)
{
HAL_Timer_countdown_ms(timer, timeout_ms);
}
void countdown(Timer *timer, unsigned int timeout)
{
HAL_Timer_countdown(timer, timeout);
}
int left_ms(Timer *timer)
{
return HAL_Timer_remain(timer);
}
void InitTimer(Timer *timer)
{
HAL_Timer_init(timer);
}
#ifdef __cplusplus
}
#endif