merge new qcloud sdk

1. qcloud has a great revolution, the protocol has been changed to implement data template, so the old TencentCloud_SDK developed by us will not work fine now(mqtt still works, but data template will not works fine for recently created product/devices).

2. I merge the official qlcoud sdk(include both the iot-hub and iot-explorer sdk) into the componet/conectivity to support new protocol of data template

3. iot-hub sdk, supply the fundamental iot protocol(like mqtt coap, etc.)
iot-explorer sdk, supply the high level service like data template based on mqtt

4. To know how it works, see qcloud_iot_explorer_sdk_data_template、qcloud_iot_hub_sdk_mqtt example(keil project in board\TencentOS_tiny_EVB_MX_Plus\KEIL\qcloud_iot_explorer_sdk_data_template and  board\TencentOS_tiny_EVB_MX_Plus\KEIL\qcloud_iot_hub_sdk_mqtt)
This commit is contained in:
daishengdong
2019-11-14 15:09:00 +08:00
parent 5d86548c23
commit 943db74fc7
705 changed files with 297267 additions and 0 deletions

View File

@@ -0,0 +1,61 @@
# <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ã<EFBFBD><C3A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD>ļ<EFBFBD>
# UTILS
file(GLOB src_utils ${CMAKE_CURRENT_SOURCE_DIR}/utils/*.c)
set(src_sdk ${src_utils})
# data_template
file(GLOB src_mqtt ${CMAKE_CURRENT_SOURCE_DIR}/protocol/mqtt/*.c)
list(APPEND src_sdk ${src_mqtt})
file(GLOB src_data_template ${CMAKE_CURRENT_SOURCE_DIR}/services/data_template/*.c)
list(APPEND src_sdk ${src_data_template})
# ota mqtt
if(${FEATURE_OTA_COMM_ENABLED} STREQUAL "ON")
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()
# HTTP
if(${FEATURE_OTA_COMM_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})
# <20><><EFBFBD>ɿ⣬<C9BF><E2A3AC>ȡԴ<C8A1><D4B4>
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,166 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2019 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 "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_eLOG_ERROR = -1, /* AT response end is eLOG_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 'eLOG_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
volatile void *thread_t;
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,105 @@
/*
* Copyright (c) 2019-2021 Tencent Group. All rights reserved.
* License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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,116 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2019 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,49 @@
/*
* Copyright (c) 2019-2021 Tencent Group. All rights reserved.
* License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 <stdlib.h>
#include <stdio.h>
#include <stdarg.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,48 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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 _DATA_TEMPLATE_ACTION_H_
#define _DATA_TEMPLATE_ACTION_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
#include <stddef.h>
#define ACTION_NAME_MAX_LEN (20) // action name max len
#define ACTION_TOKEN_MAX_LEN (32) // action token max len
#define MAX_ACTION_WAIT_REPLY (10)
#define ACTION_MAX_DATA_NUM (255) // input or output max data num
#define REPORT_ACTION "action_reply"
#define CALL_ACTION "action"
int IOT_Action_Init(void *c);
int IOT_Action_Register(void *pTemplate, DeviceAction *pAction, OnActionHandleCallback callback);
int IOT_Action_Remove(void *ptemplate, DeviceAction *pAction);
#ifdef __cplusplus
}
#endif
#endif //_DATA_TEMPLATE_ACTION_H_

View File

@@ -0,0 +1,112 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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.
*
*/
/**
* @brief API of data_template
*
*/
#ifndef IOT_TEMPLATE_CLIENT_H_
#define IOT_TEMPLATE_CLIENT_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "utils_param_check.h"
#include "data_template_client_json.h"
#include "qcloud_iot_device.h"
#include "mqtt_client.h"
#define MAX_CLEAE_DOC_LEN 256
typedef struct _TemplateInnerData {
uint32_t token_num;
int32_t sync_status;
uint32_t eventflags;
List *event_list;
List *reply_list;
List *action_handle_list;
List *property_handle_list;
char *upstream_topic; //upstream topic
char *downstream_topic; //downstream topic
} TemplateInnerData;
typedef struct _Template {
void *mqtt;
void *mutex;
MQTTEventHandler event_handle;
TemplateInnerData inner_data;
} Qcloud_IoT_Template;
/**
* @brief init data template client
*
* @param pTemplate handle to data_template client
*/
int qcloud_iot_template_init(Qcloud_IoT_Template *pTemplate);
/**
* @brief deinit data template client list and topics
*
* @param pClient data template client
*/
void qcloud_iot_template_reset(void *pClient);
/**
* @brief deal upstream msg wait for reply timeout
*
* @param pTemplate data template client
*/
void handle_template_expired_reply(Qcloud_IoT_Template *pTemplate);
/**
* @brief get the clientToken of control message for control_reply
*
* @param void
* @return clientToken
*/
char * get_control_clientToken(void);
/**
* @brief all the upstream data by the way of request
*
* @param pTemplate handle to data_template client
* @param pParams request params
* @param pJsonDoc data buffer for request
* @param sizeOfBuffer length of data buffer
* @return QCLOUD_RET_SUCCESS when success, or err code for failure
*/
int send_template_request(Qcloud_IoT_Template *pTemplate, RequestParams *pParams, char *pJsonDoc, size_t sizeOfBuffer);
/**
* @brief subscribe data_template topic $thing/down/property/%s/%s
*
* @param pShadow shadow client
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int subscribe_template_downstream_topic(Qcloud_IoT_Template *pTemplate);
#ifdef __cplusplus
}
#endif
#endif /* IOT_TEMPLATE_CLIENT_H_ */

View File

@@ -0,0 +1,59 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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_DATA_TEMPLATE_CLIENT_COMMON_H_
#define IOT_DATA_TEMPLATE_CLIENT_COMMON_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "data_template_client.h"
/**
* @brief register a device property
*
* @param pTemplate handle to data_template client
* @param pProperty device property
* @param callback callback when property changes
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int template_common_register_property_on_delta(Qcloud_IoT_Template *pTemplate, DeviceProperty *pProperty, OnPropRegCallback callback);
/**
* @brief remove a device property
*
* @param pTemplate handle to data_template client
* @param pProperty device property
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int template_common_remove_property(Qcloud_IoT_Template *ptemplate, DeviceProperty *pProperty);
/**
* @brief check if a device property exists
*
* @param pShadow handle to data_template client
* @param pProperty device property
* @return 0 = not existed
*/
int template_common_check_property_existence(Qcloud_IoT_Template *ptemplate, DeviceProperty *pProperty);
#ifdef __cplusplus
}
#endif
#endif //IOT_DATA_TEMPLATE_CLIENT_COMMON_H_

View File

@@ -0,0 +1,283 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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_METHOD_H_
#define UTILS_METHOD_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#define min(a,b) (a) < (b) ? (a) : (b)
/* Max number of requests in appending state */
#define MAX_APPENDING_REQUEST_AT_ANY_GIVEN_TIME (10)
/* Size of buffer to receive JSON document from server */
#define CLOUD_IOT_JSON_RX_BUF_LEN (QCLOUD_IOT_MQTT_RX_BUF_LEN + 1)
/* 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)
#define CLIENT_TOKEN_FIELD "clientToken"
#define METHOD_FIELD "method"
#define TYPE_FIELD "type"
#define ACTION_ID_FIELD "actionId"
#define TIME_STAMP_FIELD "timestamp"
#define REPLY_CODE "code"
#define REPLY_STATUS "status"
#define GET_STATUS "get_status" //method field for get_status
#define GET_STATUS_REPLY "get_status_reply" //method field for get_status reply
#define CONTROL_CMD "control" //method field for control msg
#define CONTROL_CMD_REPLY "control_reply" //method field for control msg reply
#define CLEAR_CONTROL "clear_control" //method field for clear control
#define REPORT_CMD "report" //method field for report
#define REPORT_CMD_REPLY "report_reply" //method field for report reply
#define INFO_CMD "report_info" //method field for report system informaiton
#define INFO_CMD_REPLY "report_info_reply" //method field for report system informaiton reply
#define GET_CONTROL_PARA "data.control"
#define CMD_CONTROL_PARA "params"
/**
* @brief define type of request parameters
*/
typedef struct _RequestParam {
Method method; // method type: GET, REPORT, RINFO, REPLY, CLEAR
uint32_t timeout_sec; // request timeout in second
OnReplyCallback request_callback; // request callback
void *user_context; // user context for callback
} RequestParams;
#define DEFAULT_REQUEST_PARAMS {GET, 4, NULL, NULL};
/**
* @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
OnReplyCallback callback; // request response callback
} Request;
/**
* @brief for property and it's callback
*/
typedef struct {
void *property;
OnPropRegCallback callback;
} PropertyHandler;
/**
* @brief save the action registed and its callback
*/
typedef struct {
void *action;
OnActionHandleCallback callback;
} ActionHandler;
/**
* @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
*/
int check_snprintf_return(int32_t returnCode, size_t maxSizeOfWrite);
/**
* @brief insert source string to the dest string with specified position
*
* @param pSourceStr source string
* @param pDestStr dest string
* @param pos dest string positon
*/
void insert_str(char *pDestStr, char *pSourceStr, int pos);
/**
* 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 JSON node to JSON string, data_template's bool type not the same to put_json_node
*
* @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 template_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
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int generate_client_token(char *pStrBuffer, size_t sizeOfBuffer, uint32_t *tokenNumber);
/**
* @brief generate an empty JSON with only clientToken
*
* @param tokenNumber shadow token number, increment every time
* @param pJsonBuffer JSON string buffer
*/
void build_empty_json(uint32_t *tokenNumber, char *pJsonBuffer);
/**
* @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 aciont_id from JSON string
*
* @param pJsonDoc source JSON string
* @param pActionID pointer to field of action_id
* @return true for success
*/
bool parse_action_id(char *pJsonDoc, char **pActionID);
/**
* @brief parse field of timestamp from JSON string
*
* @param pJsonDoc source JSON string
* @param pTimestamp pointer to field of timestamp
* @return true for success
*/
bool parse_time_stamp(char *pJsonDoc, int32_t *pTimestamp);
/**
* @brief parse field of input from JSON string
*
* @param pJsonDoc source JSON string
* @param pActionInput filed of params as action input parameters
* @return true for success
*/
bool parse_action_input(char *pJsonDoc, char **pActionInput);
/**
* @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 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);
/**
* @brief parse field of method from JSON string
*
* @param pJsonDoc source JSON string
* @param pMethod pointer to field of method
* @return true for success
*/
bool parse_template_method_type(char *pJsonDoc, char **pMethod);
/**
* @brief parse field of control from get_status_reply JSON string
*
* @param pJsonDoc source JSON string
* @param control pointer to field of control
* @return true for success
*/
bool parse_template_get_control(char *pJsonDoc, char **control);
/**
* @brief parse field of control from control JSON string
*
* @param pJsonDoc source JSON string
* @param control pointer to field of control
* @return true for success
*/
bool parse_template_cmd_control(char *pJsonDoc, char **control);
#ifdef __cplusplus
}
#endif
#endif /* QCLOUD_IOT_EXPORT_SHADOW_H_ */

View File

@@ -0,0 +1,69 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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 _DATA_TEMPLATE_EVENT_H_
#define _DATA_TEMPLATE_EVENT_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
#include <stddef.h>
#define NAME_MAX_LEN (32)
#define TYPE_MAX_LEN (32)
#define EVENT_TOKEN_MAX_LEN (32)
#define SIGLE_EVENT (1)
#define MUTLTI_EVENTS (2)
#define MAX_EVENT_WAIT_REPLY (10)
#define EVENT_MAX_DATA_NUM (255)
#define POST_EVENT "event_post"
#define POST_EVENTS "events_post"
#define REPLY_EVENT "event_reply"
/**
* @brief event's method, post and reply
*/
typedef enum {
eEVENT_POST,
eEVENT_REPLY,
} eEventMethod;
typedef enum _eEventDealType_{
eDEAL_REPLY_CB = 0,
eDEAL_EXPIRED = 1,
}eEventDealType;
typedef struct _sReply_{
char client_token[EVENT_TOKEN_MAX_LEN]; // clientToken for this event reply
void *user_context; // user context
Timer timer; // timer for request timeout
OnEventReplyCallback callback; // callback for this event reply
} sEventReply;
#ifdef __cplusplus
}
#endif
#endif //_DATA_TEMPLATE_EVENT_H_

View File

@@ -0,0 +1,86 @@
#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;
} 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,162 @@
/*
* Copyright (c) 2017-2019 Tencent Group. All rights reserved.
* License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
*
*/
/**
* Edit by shockcao@tencent.com 2018/3/15
*/
#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,105 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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,513 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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 <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "utils_param_check.h"
#include "mqtt_client_net.h"
#include "utils_timer.h"
#include "utils_list.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)
/**
* @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 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
} 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_deinit(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 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);
/**
* @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(void);
#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) 2016 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,130 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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,59 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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,38 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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,84 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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 <sys/types.h>
#include <stdint.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,33 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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,53 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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,36 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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_init(void);
int iot_device_info_set(const char *product_id, const char *device_name);
DeviceInfo* iot_device_info_get(void);
#ifdef __cplusplus
}
#endif
#endif /* IOT_DEVICE_H_ */

View File

@@ -0,0 +1,317 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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,37 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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_log.h"
#include "qcloud_iot_export_error.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,26 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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,82 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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,97 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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,94 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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) 2016 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,50 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2019 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,90 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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,80 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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,967 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2019 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"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "utils_param_check.h"
#include "utils_timer.h"
#include "at_client.h"
#include "at_utils.h"
#define AT_RESP_END_OK "OK"
#define AT_RESP_END_eLOG_ERROR "eLOG_ERROR"
#define AT_RESP_END_FAIL "FAIL"
#define AT_END_CR_LF "\r\n"
sRingbuff g_ring_buff;
static at_client sg_at_client;
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 'eLOG_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_eLOG_ERROR)
|| (memcmp(client->recv_buffer, AT_RESP_END_FAIL, strlen(AT_RESP_END_FAIL)) == 0))
{
client->resp_status = AT_RESP_eLOG_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");
}
}
return NULL;
}
#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_eLOG_ERROR)
|| (memcmp(client->recv_buffer, AT_RESP_END_FAIL, strlen(AT_RESP_END_FAIL)) == 0))
{
client->resp_status = AT_RESP_eLOG_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)
{
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");
return QCLOUD_ERR_FAILURE;
}
client->parser = client_parser;
#endif
char * ringBuff = HAL_Malloc(RING_BUFF_LEN);
if(NULL == ringBuff)
{
Log_e("malloc ringbuff err");
return QCLOUD_ERR_FAILURE;
}
ring_buff_init(&g_ring_buff, ringBuff, RING_BUFF_LEN);
char * recvBuff = HAL_Malloc(CLINET_BUFF_LEN);
if(NULL == recvBuff)
{
Log_e("malloc recvbuff err");
return QCLOUD_ERR_FAILURE;
}
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;
}
/**
* 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;
#ifdef AT_OS_USED
// create thread for at parser
if(NULL != client->parser)
{
#define AT_PARSER_THREAD_STACK 6144
#define AT_PARSER_THREAD_PRIORITY 0
client->thread_t = HAL_ThreadCreate(
AT_PARSER_THREAD_STACK, \
AT_PARSER_THREAD_PRIORITY,
"at_client_parser",
client->parser, \
client);
result = client->thread_t ? QCLOUD_RET_SUCCESS : QCLOUD_ERR_FAILURE;
if(QCLOUD_RET_SUCCESS == result){
Log_d("create at_parser thread success!");
}else{
Log_d("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,415 @@
/*
* Copyright (c) 2019-2021 Tencent Group. All rights reserved.
* License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 <stdio.h>
#include <string.h>
#include <stdint.h>
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "utils_param_check.h"
#include "at_socket_inf.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,372 @@
/*
* Copyright (c) 2019-2021 Tencent Group. All rights reserved.
* License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 <string.h>
#include "qcloud_iot_import.h"
#include "utils_param_check.h"
#include "at_utils.h"
#include "at_client.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,162 @@
/*
* Copyright (c) 2019-2021 Tencent Group. All rights reserved.
* License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 <stdio.h>
#include <string.h>
#include <stdint.h>
#include "network_interface.h"
#include "utils_param_check.h"
#include "utils_timer.h"
#include "at_socket_inf.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,108 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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) 2016 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) 2016 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,806 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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 <ctype.h>
#include <string.h>
#include "qcloud_iot_import.h"
#include "qcloud_iot_export.h"
#include "qcloud_iot_common.h"
#include "qcloud_iot_ca.h"
#include "utils_httpc.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;
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), (size_t *)p_read_len);
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(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,470 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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 <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "mqtt_client.h"
#include "qcloud_iot_ca.h"
#include "qcloud_iot_device.h"
#include "qcloud_iot_import.h"
#include "qcloud_iot_export.h"
#include "qcloud_iot_common.h"
#include "utils_base64.h"
#include "utils_list.h"
#include "log_upload.h"
#include "lite-utils.h"
static char s_qcloud_iot_host[HOST_STR_LENGTH] = {0};
#ifdef AUTH_WITH_NOTLS
static int s_qcloud_iot_port = MQTT_SERVER_PORT_NOTLS;
#else
static int s_qcloud_iot_port = MQTT_SERVER_PORT_TLS;
#endif
#ifndef AUTH_MODE_CERT
static unsigned char sg_psk_str[DECODE_PSK_LENGTH];
#endif
static int g_last_err_code = 0;
static uint16_t _get_random_start_packet_id(void)
{
srand((unsigned)HAL_GetTimeMs());
return rand() % 65536 + 1;
}
int IOT_MQTT_GetErrCode(void)
{
return g_last_err_code;
}
void* IOT_MQTT_Construct(MQTTInitParams *pParams)
{
g_last_err_code = QCLOUD_ERR_INVAL;
POINTER_SANITY_CHECK(pParams, NULL);
STRING_PTR_SANITY_CHECK(pParams->product_id, NULL);
STRING_PTR_SANITY_CHECK(pParams->device_name, NULL);
int rc = iot_device_info_set(pParams->product_id, pParams->device_name);
if ( rc != QCLOUD_RET_SUCCESS) {
Log_e("failed to set device info: %d", rc);
g_last_err_code = rc;
return 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");
g_last_err_code = QCLOUD_ERR_MALLOC;
return NULL;
}
rc = qcloud_iot_mqtt_init(mqtt_client, pParams);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("mqtt init failed: %d", rc);
HAL_Free(mqtt_client);
g_last_err_code = rc;
return NULL;
}
MQTTConnectParams connect_params = DEFAULT_MQTTCONNECT_PARAMS;
connect_params.client_id = iot_device_info_get()->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)
size_t src_len = strlen(pParams->device_secret);
size_t len;
memset(sg_psk_str, 0x00, DECODE_PSK_LENGTH);
rc = qcloud_iot_utils_base64decode(sg_psk_str, sizeof( sg_psk_str ), &len, (unsigned char *)pParams->device_secret, src_len );
connect_params.device_secret = (char *)sg_psk_str;
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_deinit(mqtt_client);
HAL_Free(mqtt_client);
g_last_err_code = rc;
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_deinit(mqtt_client);
HAL_Free(mqtt_client);
g_last_err_code = rc;
return NULL;
}
else {
Log_i("mqtt connect with id: %s success", mqtt_client->options.conn_id);
g_last_err_code = QCLOUD_RET_SUCCESS;
}
#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);
int i = 0;
for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
/* notify this event to topic subscriber */
if (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();
#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;
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_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)
}
static inline void _strlowr(char *str)
{
while(*str != '\0')
{
*str = tolower(*str);
str++;
}
}
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 size = HAL_Snprintf(s_qcloud_iot_host, 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);
}
_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
bool certEmpty = (pParams->cert_file == NULL || pParams->key_file == NULL);
if (certEmpty) {
Log_e("cert file or key file is empty!");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
}
Log_d("cert file: %s", pParams->cert_file);
Log_d("key file: %s", pParams->key_file);
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
if (pParams->device_secret != NULL) {
size_t src_len = strlen(pParams->device_secret);
size_t len;
memset(sg_psk_str, 0x00, DECODE_PSK_LENGTH);
qcloud_iot_utils_base64decode(sg_psk_str, sizeof( sg_psk_str ), &len, (unsigned char *)pParams->device_secret, src_len );
pClient->network_stack.ssl_connect_params.psk = (char *)sg_psk_str;
pClient->network_stack.ssl_connect_params.psk_length = len;
} else {
Log_e("psk is empty!");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
}
pClient->network_stack.ssl_connect_params.psk_id = iot_device_info_get()->client_id;
if (iot_device_info_get()->client_id == NULL) {
Log_e("psk id is empty!");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
}
pClient->network_stack.ssl_connect_params.ca_crt = NULL; //iot_ca_get();
pClient->network_stack.ssl_connect_params.ca_crt_len = 0; //strlen(pClient->network_stack.ssl_connect_params.ca_crt);
#endif
pClient->network_stack.host = s_qcloud_iot_host;
pClient->network_stack.port = s_qcloud_iot_port;
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 = s_qcloud_iot_host;
pClient->network_stack.port = s_qcloud_iot_port;
#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));
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_deinit(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

View File

@@ -0,0 +1,447 @@
/*******************************************************************************
* 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 <string.h>
#include <limits.h>
#include "qcloud_iot_common.h"
#include "mqtt_client.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);
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);
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) IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
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) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_BUF_TOO_SHORT);
}
rc = mqtt_init_packet_header(&header, CONNECT, QOS0, 0, 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);
// 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);
}
/**
* 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);
// if we have log in console, we need a longer timeout
countdown_ms(&connect_timer, pClient->command_timeout_ms + 10 * 1000);
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,58 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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,380 @@
/*******************************************************************************
* 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);
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,221 @@
/*******************************************************************************
* 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);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,197 @@
/*******************************************************************************
* 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,485 @@
/*******************************************************************************
* 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 "mqtt_client.h"
#include "log_upload.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);
}
/**
* @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,400 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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 "config.h"
#if defined(ACTION_ENABLED)
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include "utils_param_check.h"
#include "lite-utils.h"
#include "data_template_client.h"
#include "data_template_action.h"
#include "data_template_client_json.h"
#include "qcloud_iot_export_data_template.h"
//Action Subscribe
static int _parse_action_input(DeviceAction *pAction, char *pInput)
{
int i;
char *temp;
DeviceProperty *pActionInput = pAction->pInput;
//check and copy
for (i = 0; i < pAction->input_num; i++) {
if (JSTRING == pActionInput[i].type) {
pActionInput[i].data = LITE_json_value_of(pActionInput[i].key, pInput);
if(NULL == pActionInput[i].data) {
Log_e("action input data [%s] not found!", pActionInput[i].key);
return -1;
}
} else {
temp = LITE_json_value_of(pActionInput[i].key, pInput);
if(NULL == temp) {
Log_e("action input data [%s] not found!", pActionInput[i].key);
return -1;
}
if(JINT32 == pActionInput[i].type) {
if (sscanf(temp, "%" SCNi32, (int32_t *)pActionInput[i].data) != 1) {
HAL_Free(temp);
Log_e("parse code failed, errCode: %d", QCLOUD_ERR_JSON_PARSE);
return -1;
}
} else if( JFLOAT == pActionInput[i].type) {
if (sscanf(temp, "%f", (float *)pActionInput[i].data) != 1) {
HAL_Free(temp);
Log_e("parse code failed, errCode: %d", QCLOUD_ERR_JSON_PARSE);
return -1;
}
} else if( JUINT32 == pActionInput[i].type) {
if (sscanf(temp, "%" SCNu32, (uint32_t *) pActionInput[i].data) != 1) {
HAL_Free(temp);
Log_e("parse code failed, errCode: %d", QCLOUD_ERR_JSON_PARSE);
return -1;
}
}
HAL_Free(temp);
}
}
return 0;
}
static void _handle_aciton(Qcloud_IoT_Template *pTemplate, List *list, const char *pClientToken, const char *pActionId, uint32_t timestamp, char *pInput)
{
IOT_FUNC_ENTRY;
HAL_MutexLock(pTemplate->mutex);
if (list->len) {
ListIterator *iter;
ListNode *node = NULL;
if (NULL == (iter = list_iterator_new(list, LIST_TAIL))) {
HAL_MutexUnlock(pTemplate->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;
}
ActionHandler *pActionHandle = (ActionHandler *)node->val;
// check action id and call callback
if(0 == strcmp(pActionId,((DeviceAction*)pActionHandle->action)->pActionId)){
if(NULL != pActionHandle->callback) {
if(!_parse_action_input(pActionHandle->action, pInput)) {
((DeviceAction*)pActionHandle->action)->timestamp = timestamp;
pActionHandle->callback(pTemplate, pClientToken, pActionHandle->action);
}
}
}
}
list_iterator_destroy(iter);
}
HAL_MutexUnlock(pTemplate->mutex);
IOT_FUNC_EXIT;
}
static void _on_action_handle_callback(void *pClient, MQTTMessage *message, void *pUserData)
{
POINTER_SANITY_CHECK_RTN(message);
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
Qcloud_IoT_Template *template_client = (Qcloud_IoT_Template*)mqtt_client->event_handle.context;
char *type_str = NULL;
char* client_token = NULL;
char* action_id = NULL;
char *pInput = NULL;
int timestamp = 0;
Log_d("recv:%.*s",(int) message->payload_len, (char *) message->payload);
// prase_method
if (!parse_template_method_type((char *) message->payload, &type_str))
{
Log_e("Fail to parse method!");
goto EXIT;
}
if (strcmp(type_str, CALL_ACTION)) {
goto EXIT;
}
// prase client Token
if (!parse_client_token((char *) message->payload, &client_token)) {
Log_e("fail to parse client token!");
goto EXIT;
}
// prase action ID
if (!parse_action_id((char *) message->payload, &action_id)) {
Log_e("fail to parse action id!");
goto EXIT;
}
// prase timestamp
if (!parse_time_stamp((char *) message->payload, &timestamp)) {
Log_e("fail to parse timestamp!");
goto EXIT;
}
// prase action input
if (!parse_action_input((char *) message->payload, &pInput)) {
Log_e("fail to parse action input!");
goto EXIT;
}
//find action ID in register list and call handle
if (template_client != NULL)
_handle_aciton(template_client, template_client->inner_data.action_handle_list, client_token, action_id, timestamp, pInput);
EXIT:
HAL_Free(type_str);
HAL_Free(client_token);
HAL_Free(pInput);
return;
}
int IOT_Action_Init(void *c)
{
Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)c;
static char topic_name[MAX_SIZE_OF_CLOUD_TOPIC] = {0};
int size = HAL_Snprintf(topic_name, MAX_SIZE_OF_CLOUD_TOPIC, "$thing/down/action/%s/%s", iot_device_info_get()->product_id, iot_device_info_get()->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 = _on_action_handle_callback;
return IOT_MQTT_Subscribe(pTemplate->mqtt, topic_name, &sub_params);
}
//Action register
static int _add_action_handle_to_template_list(Qcloud_IoT_Template *pTemplate, DeviceAction *pAction, OnActionHandleCallback callback)
{
IOT_FUNC_ENTRY;
ActionHandler *action_handle = (ActionHandler *)HAL_Malloc(sizeof(ActionHandler));
if (NULL == action_handle)
{
Log_e("run memory malloc is error!");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
action_handle->callback = callback;
action_handle->action = pAction;
ListNode *node = list_node_new(action_handle);
if (NULL == node) {
Log_e("run list_node_new is error!");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
list_rpush(pTemplate->inner_data.action_handle_list, node);
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
static int _check_action_existence(Qcloud_IoT_Template *ptemplate, DeviceAction *pAction)
{
ListNode *node;
HAL_MutexLock(ptemplate->mutex);
node = list_find(ptemplate->inner_data.action_handle_list, pAction);
HAL_MutexUnlock(ptemplate->mutex);
return (NULL != node);
}
int IOT_Action_Register(void *pTemplate, DeviceAction *pAction, OnActionHandleCallback callback)
{
IOT_FUNC_ENTRY;
Qcloud_IoT_Template *ptemplate = (Qcloud_IoT_Template *)pTemplate;
POINTER_SANITY_CHECK(pTemplate, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(callback, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(pAction, QCLOUD_ERR_INVAL);
if (_check_action_existence(ptemplate, pAction))
IOT_FUNC_EXIT_RC(QCLOUD_ERR_ACTION_EXIST);
int rc;
HAL_MutexLock(ptemplate->mutex);
rc = _add_action_handle_to_template_list(ptemplate, pAction, callback);
HAL_MutexUnlock(ptemplate->mutex);
IOT_FUNC_EXIT_RC(rc);
}
int IOT_Action_Remove(void *pTemplate, DeviceAction *pAction)
{
Qcloud_IoT_Template *ptemplate = (Qcloud_IoT_Template *)pTemplate;
if (!_check_action_existence(ptemplate, pAction))
IOT_FUNC_EXIT_RC(QCLOUD_ERR_NOT_ACTION_EXIST);
int rc = QCLOUD_RET_SUCCESS;
ListNode *node;
HAL_MutexLock(ptemplate->mutex);
node = list_find(ptemplate->inner_data.action_handle_list, pAction);
if (NULL == node) {
rc = QCLOUD_ERR_NOT_PROPERTY_EXIST;
Log_e("Try to remove a non-existent action.");
} else {
list_remove(ptemplate->inner_data.action_handle_list, node);
}
HAL_MutexUnlock(ptemplate->mutex);
return rc;
}
//Action post to server
static int _iot_action_json_init(void *handle, char *jsonBuffer, size_t sizeOfBuffer, const char *pClientToken, DeviceAction *pAction)
{
POINTER_SANITY_CHECK(jsonBuffer, QCLOUD_ERR_INVAL);
int32_t rc_of_snprintf;
memset(jsonBuffer, 0, sizeOfBuffer);
rc_of_snprintf = HAL_Snprintf(jsonBuffer, sizeOfBuffer, "{\"method\":\"%s\", \"clientToken\":\"%s\", ", REPORT_ACTION, pClientToken);
return check_snprintf_return(rc_of_snprintf, sizeOfBuffer);
}
static int _iot_construct_action_json(void *handle, char *jsonBuffer, size_t sizeOfBuffer, const char *pClientToken, DeviceAction *pAction, sReplyPara *replyPara)
{
size_t remain_size = 0;
int32_t rc_of_snprintf = 0;
uint8_t i;
Qcloud_IoT_Template* ptemplate = (Qcloud_IoT_Template *)handle;
POINTER_SANITY_CHECK(ptemplate, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(jsonBuffer, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(pClientToken, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(pAction, QCLOUD_ERR_INVAL);
int rc = _iot_action_json_init(ptemplate, jsonBuffer, sizeOfBuffer, pClientToken, pAction);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("event json init failed: %d", rc);
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, "\"code\":%d, \"status\":\"%s\", \"response\":{",\
replyPara->code, replyPara->status_msg);
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;
}
DeviceProperty *pJsonNode = pAction->pOutput;
for (i = 0; i < pAction->output_num; i++) {
if (pJsonNode != NULL && pJsonNode->key != NULL) {
rc = template_put_json_node(jsonBuffer, remain_size, pJsonNode->key, pJsonNode->data, pJsonNode->type);
if (rc != QCLOUD_RET_SUCCESS) {
return rc;
}
} else {
Log_e("%dth/%d null event property data", i, pAction->output_num);
return QCLOUD_ERR_INVAL;
}
pJsonNode++;
}
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) {
return rc;
}
//finish json
if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) < 1) {
return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL;
}
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "}");
return check_snprintf_return(rc_of_snprintf, remain_size);
}
static int _publish_action_to_cloud(void *c, char *pJsonDoc)
{
IOT_FUNC_ENTRY;
int rc = QCLOUD_RET_SUCCESS;
char topic[MAX_SIZE_OF_CLOUD_TOPIC] = {0};
Qcloud_IoT_Template *ptemplate = (Qcloud_IoT_Template *)c;
int size = HAL_Snprintf(topic, MAX_SIZE_OF_CLOUD_TOPIC, "$thing/up/action/%s/%s", iot_device_info_get()->product_id, iot_device_info_get()->device_name);
if (size < 0 || size > sizeof(topic) - 1)
{
Log_e("topic content length not enough! content size:%d buf size:%d", size, (int)sizeof(topic));
return QCLOUD_ERR_FAILURE;
}
PublishParams pubParams = DEFAULT_PUB_PARAMS;
pubParams.qos = QOS1;
pubParams.payload_len = strlen(pJsonDoc);
pubParams.payload = (char *) pJsonDoc;
rc = IOT_MQTT_Publish(ptemplate->mqtt, topic, &pubParams);
IOT_FUNC_EXIT_RC(rc);
}
int IOT_ACTION_REPLY(void *pClient, const char *pClientToken, char *pJsonDoc, size_t sizeOfBuffer, DeviceAction *pAction, sReplyPara *replyPara)
{
int rc;
rc = _iot_construct_action_json(pClient, pJsonDoc, sizeOfBuffer, pClientToken, pAction, replyPara);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("construct action json fail, %d",rc);
return rc;
}
rc = _publish_action_to_cloud(pClient, pJsonDoc);
if (rc < 0) {
Log_e("publish action to cloud fail, %d",rc);
}
return rc;
}
#endif

View File

@@ -0,0 +1,831 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "utils_param_check.h"
#include "data_template_client_json.h"
#include "data_template_client.h"
#include "data_template_action.h"
#include "data_template_client_common.h"
static void _init_request_params(RequestParams *pParams, Method method, OnReplyCallback callback, void *userContext, uint8_t timeout_sec) {
pParams->method = method;
pParams->user_context = userContext;
pParams->timeout_sec = timeout_sec;
pParams->request_callback = callback;
}
int IOT_Template_Publish(void *handle, char *topicName, PublishParams *pParams)
{
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
Qcloud_IoT_Template *template_client = (Qcloud_IoT_Template *)handle;
return qcloud_iot_mqtt_publish(template_client->mqtt, topicName, pParams);
}
int IOT_Template_Subscribe(void *handle, char *topicFilter, SubscribeParams *pParams)
{
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
Qcloud_IoT_Template *template_client = (Qcloud_IoT_Template *)handle;
return qcloud_iot_mqtt_subscribe(template_client->mqtt, topicFilter, pParams);
}
int IOT_Template_Unsubscribe(void *handle, char *topicFilter)
{
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
Qcloud_IoT_Template *template_client = (Qcloud_IoT_Template *)handle;
return qcloud_iot_mqtt_unsubscribe(template_client->mqtt, topicFilter);
}
bool IOT_Template_IsConnected(void *handle)
{
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
Qcloud_IoT_Template* template_client = (Qcloud_IoT_Template*)handle;
IOT_FUNC_EXIT_RC(IOT_MQTT_IsConnected(template_client->mqtt))
}
int IOT_Template_Register_Property(void *handle, DeviceProperty *pProperty, OnPropRegCallback callback)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
Qcloud_IoT_Template* ptemplate = (Qcloud_IoT_Template*)handle;
int rc;
if (IOT_MQTT_IsConnected(ptemplate->mqtt) == false) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
}
if (template_common_check_property_existence(ptemplate, pProperty))
IOT_FUNC_EXIT_RC(QCLOUD_ERR_PROPERTY_EXIST);
rc = template_common_register_property_on_delta(ptemplate, pProperty, callback);
IOT_FUNC_EXIT_RC(rc);
}
int IOT_Template_UnRegister_Property(void *handle, DeviceProperty *pProperty)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
Qcloud_IoT_Template* ptemplate = (Qcloud_IoT_Template*)handle;
if (IOT_MQTT_IsConnected(ptemplate->mqtt) == false) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
}
if (!template_common_check_property_existence(ptemplate, pProperty)) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_NOT_PROPERTY_EXIST);
}
int rc = template_common_remove_property(ptemplate, pProperty);
IOT_FUNC_EXIT_RC(rc);
}
#ifdef ACTION_ENABLED
int IOT_Template_Register_Action(void *handle, DeviceAction *pAction, OnActionHandleCallback callback)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
Qcloud_IoT_Template* ptemplate = (Qcloud_IoT_Template*)handle;
int rc;
if (IOT_MQTT_IsConnected(ptemplate->mqtt) == false) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
}
rc = IOT_Action_Register(ptemplate, pAction, callback);
IOT_FUNC_EXIT_RC(rc);
}
int IOT_Template_UnRegister_Action(void *handle, DeviceAction *pAction)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
Qcloud_IoT_Template* ptemplate = (Qcloud_IoT_Template*)handle;
if (IOT_MQTT_IsConnected(ptemplate->mqtt) == false) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
}
int rc = IOT_Action_Remove(ptemplate, pAction);
IOT_FUNC_EXIT_RC(rc);
}
#endif
static void _copy_template_init_params_to_mqtt(MQTTInitParams *pMqttInitParams, TemplateInitParams *templateInitParams)
{
pMqttInitParams->device_name = templateInitParams->device_name;
pMqttInitParams->product_id = templateInitParams->product_id;
#ifdef AUTH_MODE_CERT
pMqttInitParams->cert_file = templateInitParams->cert_file;
pMqttInitParams->key_file = templateInitParams->key_file;
#else
pMqttInitParams->device_secret = templateInitParams->device_secret;
#endif
pMqttInitParams->command_timeout = templateInitParams->command_timeout;
pMqttInitParams->keep_alive_interval_ms = templateInitParams->keep_alive_interval_ms;
pMqttInitParams->clean_session = templateInitParams->clean_session;
pMqttInitParams->auto_connect_enable = templateInitParams->auto_connect_enable;
}
static void _reply_ack_cb(void *pClient, Method method, ReplyAck replyAck, const char *pReceivedJsonDocument, void *pUserdata)
{
Request *request = (Request *)pUserdata;
Log_d("replyAck=%d", replyAck);
if (NULL != pReceivedJsonDocument) {
Log_d("Received Json Document=%s", pReceivedJsonDocument);
} else {
Log_d("Received Json Document is NULL");
}
*((ReplyAck *)(request->user_context))= replyAck;
}
/*control data may be for get status replay*/
static void _get_status_reply_ack_cb(void *pClient, Method method, ReplyAck replyAck, const char *pReceivedJsonDocument, void *pUserdata)
{
Request *request = (Request *)pUserdata;
Log_d("replyAck=%d", replyAck);
if (NULL == pReceivedJsonDocument) {
Log_d("Received Json Document is NULL");
}
if (*((ReplyAck *)request->user_context) == ACK_ACCEPTED){
Log_d("Received Json Document=%s", pReceivedJsonDocument);
IOT_Template_ClearControl(pClient, request->client_token, NULL, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
}else{
*((ReplyAck *)request->user_context)= replyAck;
}
}
static int _template_ConstructControlReply(char *jsonBuffer, size_t sizeOfBuffer, sReplyPara *replyPara)
{
POINTER_SANITY_CHECK(jsonBuffer, QCLOUD_ERR_INVAL);
int rc;
size_t remain_size = 0;
int32_t rc_of_snprintf;
if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) {
return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL;
}
rc_of_snprintf = HAL_Snprintf(jsonBuffer , remain_size, "{\"code\":%d, \"clientToken\":\"%s\",", replyPara->code, get_control_clientToken());
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(strlen(replyPara->status_msg) > 0){
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "\"status\":\"%s\"}", replyPara->status_msg);
}else{
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer) - 1, remain_size, "}");
}
rc = check_snprintf_return(rc_of_snprintf, remain_size);
return rc;
}
static void _template_mqtt_event_handler(void *pclient, void *context, MQTTEventMsg *msg)
{
uintptr_t packet_id = (uintptr_t)msg->msg;
Qcloud_IoT_Template *template_client = (Qcloud_IoT_Template *)context;
MQTTMessage* topic_info = (MQTTMessage*)msg->msg;
switch (msg->event_type) {
case MQTT_EVENT_SUBCRIBE_SUCCESS:
Log_d("template subscribe success, packet-id=%u", packet_id);
if (template_client->inner_data.sync_status > 0)
template_client->inner_data.sync_status = 0;
break;
case MQTT_EVENT_SUBCRIBE_TIMEOUT:
Log_d("template subscribe wait ack timeout, packet-id=%u", packet_id);
if (template_client->inner_data.sync_status > 0)
template_client->inner_data.sync_status = -1;
break;
case MQTT_EVENT_SUBCRIBE_NACK:
Log_d("template subscribe nack, packet-id=%u", packet_id);
if (template_client->inner_data.sync_status > 0)
template_client->inner_data.sync_status = -1;
break;
case MQTT_EVENT_PUBLISH_RECVEIVED:
Log_d("template 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 (template_client->event_handle.h_fp != NULL)
{
template_client->event_handle.h_fp(template_client, template_client->event_handle.context, msg);
}
}
int IOT_Template_JSON_ConstructReportArray(void *handle, char *jsonBuffer, size_t sizeOfBuffer, uint8_t count, DeviceProperty *pDeviceProperties[])
{
POINTER_SANITY_CHECK(jsonBuffer, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(pDeviceProperties, QCLOUD_ERR_INVAL);
Qcloud_IoT_Template* ptemplate = (Qcloud_IoT_Template*)handle;
POINTER_SANITY_CHECK(ptemplate, QCLOUD_ERR_INVAL);
size_t remain_size = 0;
int32_t rc_of_snprintf = 0;
int rc;
int8_t i;
build_empty_json(&(ptemplate->inner_data.token_num), jsonBuffer);
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, ", \"params\":{");
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("construct datatemplate report array failed: %d", rc);
return rc;
}
return rc;
}
int IOT_Template_ClearControl(void *handle, char *pClientToken, OnReplyCallback callback, uint32_t timeout_ms)
{
IOT_FUNC_ENTRY;
int rc;
char JsonDoc[MAX_CLEAE_DOC_LEN];
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(pClientToken, QCLOUD_ERR_INVAL);
Qcloud_IoT_Template* template_client = (Qcloud_IoT_Template*)handle;
if (IOT_MQTT_IsConnected(template_client->mqtt) == false) {
Log_e("template is disconnected");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
}
// if topic $thing/down/property subscribe not success before, subsrcibe again
if (template_client->inner_data.sync_status < 0) {
rc = subscribe_template_downstream_topic(template_client);
if (rc < 0)
{
Log_e("Subcribe $thing/down/property fail!");
}
}
memset(JsonDoc, 0, MAX_CLEAE_DOC_LEN);
int rc_of_snprintf = HAL_Snprintf(JsonDoc, MAX_CLEAE_DOC_LEN, "{\"clientToken\":\"%s\"}", pClientToken);
rc = check_snprintf_return(rc_of_snprintf, MAX_CLEAE_DOC_LEN);
if (rc != QCLOUD_RET_SUCCESS) {
return rc;
}
RequestParams request_params = DEFAULT_REQUEST_PARAMS;
_init_request_params(&request_params, CLEAR, callback, NULL, timeout_ms/1000);
rc = send_template_request(template_client, &request_params, JsonDoc, MAX_CLEAE_DOC_LEN);
IOT_FUNC_EXIT_RC(rc);
}
int IOT_Template_Report(void *handle, char *pJsonDoc, size_t sizeOfBuffer, OnReplyCallback 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_Template* template_client = (Qcloud_IoT_Template*)handle;
if (IOT_MQTT_IsConnected(template_client->mqtt) == false) {
Log_e("template is disconnected");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
}
// if topic $thing/down/property subscribe not success before, subsrcibe again
if (template_client->inner_data.sync_status < 0) {
rc = subscribe_template_downstream_topic(template_client);
if (rc < 0)
{
Log_e("Subcribe $thing/down/property fail!");
}
}
//Log_d("Report Document: %s", pJsonDoc);
RequestParams request_params = DEFAULT_REQUEST_PARAMS;
_init_request_params(&request_params, REPORT, callback, userContext, timeout_ms/1000);
rc = send_template_request(template_client, &request_params, pJsonDoc, sizeOfBuffer);
IOT_FUNC_EXIT_RC(rc);
}
int IOT_Template_Report_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_Template* template = (Qcloud_IoT_Template*)handle;
if (IOT_MQTT_IsConnected(template->mqtt) == false) {
Log_e("template is disconnected");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
}
ReplyAck ack_report = ACK_NONE;
rc = IOT_Template_Report(handle, pJsonDoc, sizeOfBuffer, _reply_ack_cb, &ack_report, timeout_ms);
if (rc != QCLOUD_RET_SUCCESS) IOT_FUNC_EXIT_RC(rc);
while (ACK_NONE == ack_report) {
IOT_Template_Yield(handle, 200);
}
if (ACK_ACCEPTED == ack_report) {
rc = QCLOUD_RET_SUCCESS;
} else if (ACK_TIMEOUT == ack_report) {
rc = QCLOUD_ERR_REPORT_TIMEOUT;
} else if (ACK_REJECTED == ack_report) {
rc = QCLOUD_ERR_REPORT_REJECTED;
}
IOT_FUNC_EXIT_RC(rc);
}
int IOT_Template_JSON_ConstructSysInfo(void *handle, char *jsonBuffer, size_t sizeOfBuffer, DeviceProperty *pPlatInfo, DeviceProperty *pSelfInfo)
{
POINTER_SANITY_CHECK(jsonBuffer, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(pPlatInfo, QCLOUD_ERR_INVAL);
Qcloud_IoT_Template* ptemplate = (Qcloud_IoT_Template*)handle;
POINTER_SANITY_CHECK(ptemplate, QCLOUD_ERR_INVAL);
size_t remain_size = 0;
int32_t rc_of_snprintf = 0;
int rc;
build_empty_json(&(ptemplate->inner_data.token_num), jsonBuffer);
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, ", \"params\":{");
rc = check_snprintf_return(rc_of_snprintf, remain_size);
if (rc != QCLOUD_RET_SUCCESS) {
return rc;
}
DeviceProperty *pJsonNode = pPlatInfo;
while((NULL != pJsonNode)&&(NULL != pJsonNode->key)) {
rc = put_json_node(jsonBuffer, remain_size, pJsonNode->key, pJsonNode->data, pJsonNode->type);
if (rc != QCLOUD_RET_SUCCESS) {
return rc;
}
pJsonNode++;
}
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) {
return rc;
}
if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) {
return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL;
}
pJsonNode = pSelfInfo;
if((NULL == pJsonNode)||(NULL == pJsonNode->key)){
Log_d("No self define info");
goto end;
}
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer) - 2, remain_size, ", \"device_label\":{");
rc = check_snprintf_return(rc_of_snprintf, remain_size);
if (rc != QCLOUD_RET_SUCCESS) {
return rc;
}
while((NULL != pJsonNode)&&(NULL != pJsonNode->key)) {
rc = put_json_node(jsonBuffer, remain_size, pJsonNode->key, pJsonNode->data, pJsonNode->type);
if (rc != QCLOUD_RET_SUCCESS) {
return rc;
}
pJsonNode++;
}
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) {
return rc;
}
end:
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);
return rc;
}
int IOT_Template_Report_SysInfo(void *handle, char *pJsonDoc, size_t sizeOfBuffer, OnReplyCallback 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_Template* template_client = (Qcloud_IoT_Template*)handle;
if (IOT_MQTT_IsConnected(template_client->mqtt) == false) {
Log_e("template is disconnected");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
}
// if topic $thing/down/property subscribe not success before, subsrcibe again
if (template_client->inner_data.sync_status < 0) {
rc = subscribe_template_downstream_topic(template_client);
if (rc < 0)
{
Log_e("Subcribe $thing/down/property fail!");
}
}
//Log_d("eLOG_INFO Document: %s", pJsonDoc);
RequestParams request_params = DEFAULT_REQUEST_PARAMS;
_init_request_params(&request_params, RINFO, callback, userContext, timeout_ms/1000);
rc = send_template_request(template_client, &request_params, pJsonDoc, sizeOfBuffer);
IOT_FUNC_EXIT_RC(rc);
}
int IOT_Template_Report_SysInfo_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_Template* template = (Qcloud_IoT_Template*)handle;
if (IOT_MQTT_IsConnected(template->mqtt) == false) {
Log_e("template is disconnected");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
}
ReplyAck ack_report = ACK_NONE;
rc = IOT_Template_Report_SysInfo(handle, pJsonDoc, sizeOfBuffer, _reply_ack_cb, &ack_report, timeout_ms);
if (rc != QCLOUD_RET_SUCCESS) IOT_FUNC_EXIT_RC(rc);
while (ACK_NONE == ack_report) {
IOT_Template_Yield(handle, 200);
}
if (ACK_ACCEPTED == ack_report) {
rc = QCLOUD_RET_SUCCESS;
} else if (ACK_TIMEOUT == ack_report) {
rc = QCLOUD_ERR_REPORT_TIMEOUT;
} else if (ACK_REJECTED == ack_report) {
rc = QCLOUD_ERR_REPORT_REJECTED;
}
IOT_FUNC_EXIT_RC(rc);
}
int IOT_Template_GetStatus(void *handle, OnReplyCallback 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_Template* template_client = (Qcloud_IoT_Template*)handle;
if (IOT_MQTT_IsConnected(template_client->mqtt) == false) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
}
// if topic $thing/down/property subscribe not success before, subsrcibe again
if (template_client->inner_data.sync_status < 0) {
rc = subscribe_template_downstream_topic(template_client);
if (rc < 0)
{
Log_e("Subcribe $thing/down/property fail!");
}
}
char getRequestJsonDoc[MAX_SIZE_OF_JSON_WITH_CLIENT_TOKEN];
build_empty_json(&(template_client->inner_data.token_num), getRequestJsonDoc);
//Log_d("GET Status Document: %s", getRequestJsonDoc);
RequestParams request_params = DEFAULT_REQUEST_PARAMS;
_init_request_params(&request_params, GET, callback, userContext, timeout_ms/1000);
rc = send_template_request(template_client, &request_params, getRequestJsonDoc, MAX_SIZE_OF_JSON_WITH_CLIENT_TOKEN);
IOT_FUNC_EXIT_RC(rc);
}
int IOT_Template_GetStatus_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_Template* pTemplate = (Qcloud_IoT_Template*)handle;
if (IOT_MQTT_IsConnected(pTemplate->mqtt) == false) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
}
ReplyAck ack_request = ACK_NONE;
rc = IOT_Template_GetStatus(handle, _get_status_reply_ack_cb, &ack_request, timeout_ms);
if (rc != QCLOUD_RET_SUCCESS) IOT_FUNC_EXIT_RC(rc);
while (ACK_NONE == ack_request) {
IOT_Template_Yield(handle, 200);
}
if (ACK_ACCEPTED == ack_request) {
rc = QCLOUD_RET_SUCCESS;
} else if (ACK_TIMEOUT == ack_request) {
rc = QCLOUD_ERR_GET_TIMEOUT;
} else if (ACK_REJECTED == ack_request) {
rc = QCLOUD_ERR_GET_REJECTED;
}
IOT_FUNC_EXIT_RC(rc);
}
int IOT_Template_ControlReply(void *handle, char *pJsonDoc, size_t sizeOfBuffer, sReplyPara *replyPara)
{
IOT_FUNC_ENTRY;
int rc;
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(pJsonDoc, QCLOUD_ERR_INVAL);
Qcloud_IoT_Template* template_client = (Qcloud_IoT_Template*)handle;
if (IOT_MQTT_IsConnected(template_client->mqtt) == false) {
Log_e("template is disconnected");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
}
// if topic $thing/down/property subscribe not success before, subsrcibe again
if (template_client->inner_data.sync_status < 0) {
rc = subscribe_template_downstream_topic(template_client);
if (rc < 0)
{
Log_e("Subcribe $thing/down/property fail!");
}
}
rc = _template_ConstructControlReply(pJsonDoc, sizeOfBuffer, replyPara);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("Construct ControlReply fail,rc=%d",rc);
return rc;
}
Log_d("Report Document: %s", pJsonDoc);
RequestParams request_params = DEFAULT_REQUEST_PARAMS;
_init_request_params(&request_params, REPLY, NULL, NULL, replyPara->timeout_ms/1000);
rc = send_template_request(template_client, &request_params, pJsonDoc, sizeOfBuffer);
IOT_FUNC_EXIT_RC(rc);
}
int IOT_Template_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_Template *ptemplate = (Qcloud_IoT_Template *)handle;
POINTER_SANITY_CHECK(ptemplate, QCLOUD_ERR_INVAL);
handle_template_expired_reply(ptemplate);
#ifdef EVENT_POST_ENABLED
handle_template_expired_event(ptemplate);
#endif
rc = IOT_MQTT_Yield(ptemplate->mqtt, timeout_ms);
IOT_FUNC_EXIT_RC(rc);
}
void* IOT_Template_Construct(TemplateInitParams *pParams)
{
POINTER_SANITY_CHECK(pParams, NULL);
int rc;
Qcloud_IoT_Template *template_client = NULL;
if ((template_client = (Qcloud_IoT_Template *)HAL_Malloc(sizeof(Qcloud_IoT_Template))) == NULL) {
Log_e("memory not enough to malloc TemplateClient");
}
MQTTInitParams mqtt_init_params;
_copy_template_init_params_to_mqtt(&mqtt_init_params, pParams);
mqtt_init_params.event_handle.h_fp = _template_mqtt_event_handler;
mqtt_init_params.event_handle.context = template_client;
void *mqtt_client = NULL;
if ((mqtt_client = IOT_MQTT_Construct(&mqtt_init_params)) == NULL) {
HAL_Free(template_client);
goto End;
}
template_client->mqtt = mqtt_client;
template_client->event_handle = pParams->event_handle;
template_client->inner_data.upstream_topic = NULL;
template_client->inner_data.downstream_topic = NULL;
template_client->inner_data.token_num = 0;
template_client->inner_data.eventflags = 0;
rc = qcloud_iot_template_init(template_client);
if (rc != QCLOUD_RET_SUCCESS) {
IOT_MQTT_Destroy(&(template_client->mqtt));
HAL_Free(template_client);
goto End;
}
rc = subscribe_template_downstream_topic(template_client);
if (rc < 0)
{
Log_e("Subcribe $thing/down/property fail!");
}
else {
template_client->inner_data.sync_status = rc;
while (rc == template_client->inner_data.sync_status) {
IOT_Template_Yield(template_client, 100);
}
if (0 == template_client->inner_data.sync_status) {
Log_i("Sync device data successfully");
} else {
Log_e("Sync device data failed");
}
}
#ifdef EVENT_POST_ENABLED
rc = IOT_Event_Init(template_client);
if (rc < 0)
{
Log_e("event init failed: %d", rc);
IOT_Template_Destroy(&(template_client->mqtt));
HAL_Free(template_client);
goto End;
}
#endif
#ifdef ACTION_ENABLED
rc = IOT_Action_Init(template_client);
if (rc < 0)
{
Log_e("action init failed: %d", rc);
IOT_Template_Destroy(&(template_client->mqtt));
HAL_Free(template_client);
goto End;
}
#endif
return template_client;
End:
return NULL;
}
int IOT_Template_Destroy(void *handle)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
Qcloud_IoT_Template* template_client = (Qcloud_IoT_Template*)handle;
qcloud_iot_template_reset(handle);
IOT_MQTT_Destroy(&template_client->mqtt);
if (NULL != template_client->mutex) {
HAL_MutexDestroy(template_client->mutex);
}
if (NULL != template_client->inner_data.downstream_topic) {
HAL_Free(template_client->inner_data.downstream_topic);
template_client->inner_data.downstream_topic = NULL;
}
HAL_Free(handle);
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS)
}
#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) 2016 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 "data_template_client_common.h"
#include "qcloud_iot_import.h"
/**
* @brief add registered propery's call back to data_template handle list
*/
static int _add_property_handle_to_template_list(Qcloud_IoT_Template *pTemplate, 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!");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
list_rpush(pTemplate->inner_data.property_handle_list, node);
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
int template_common_check_property_existence(Qcloud_IoT_Template *ptemplate, DeviceProperty *pProperty)
{
ListNode *node;
HAL_MutexLock(ptemplate->mutex);
node = list_find(ptemplate->inner_data.property_handle_list, pProperty);
HAL_MutexUnlock(ptemplate->mutex);
return (NULL != node);
}
int template_common_remove_property(Qcloud_IoT_Template *ptemplate, DeviceProperty *pProperty)
{
int rc = QCLOUD_RET_SUCCESS;
ListNode *node;
HAL_MutexLock(ptemplate->mutex);
node = list_find(ptemplate->inner_data.property_handle_list, pProperty);
if (NULL == node) {
rc = QCLOUD_ERR_NOT_PROPERTY_EXIST;
Log_e("Try to remove a non-existent property.");
} else {
list_remove(ptemplate->inner_data.property_handle_list, node);
}
HAL_MutexUnlock(ptemplate->mutex);
return rc;
}
int template_common_register_property_on_delta(Qcloud_IoT_Template *pTemplate, DeviceProperty *pProperty, OnPropRegCallback callback)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(pTemplate, 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(pTemplate->mutex);
rc = _add_property_handle_to_template_list(pTemplate, pProperty, callback);
HAL_MutexUnlock(pTemplate->mutex);
IOT_FUNC_EXIT_RC(rc);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,342 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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 <stdbool.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
#include "qcloud_iot_device.h"
#include "lite-utils.h"
#include "data_template_client_json.h"
#include "qcloud_iot_export_method.h"
int check_snprintf_return(int32_t returnCode, size_t maxSizeOfWrite) {
if (returnCode >= maxSizeOfWrite) {
return QCLOUD_ERR_JSON_BUFFER_TRUNCATED;
} else if (returnCode < 0) { // err
return QCLOUD_ERR_JSON;
}
return QCLOUD_RET_SUCCESS;
}
void insert_str(char *pDestStr, char *pSourceStr, int pos) {
int len = strlen(pDestStr);
int nlen = strlen(pSourceStr);
int i;
for (i = len - 1; i >= pos; --i) {
*(pDestStr + i + nlen) = *(pDestStr + i);
}
int n;
for (n = 0; n < nlen; n++)
*(pDestStr + pos + n) = *pSourceStr++;
*(pDestStr + len + nlen) = 0;
}
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){
rc = LITE_get_string(pProperty->data, value, pProperty->data_buff_len);
}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;
}
/**
* add field of client token into JSON
*
* @param pJsonDocument JSON string
* @param maxSizeOfJsonDocument max size of JSON string
* @return length after adding
*/
static int32_t _add_client_token(char *pJsonDocument, size_t maxSizeOfJsonDocument, uint32_t *tokenNumber) {
int32_t rc_of_snprintf = HAL_Snprintf(pJsonDocument, maxSizeOfJsonDocument, "%s-%u", iot_device_info_get()->product_id, (*tokenNumber)++);
return rc_of_snprintf;
}
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 template_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) {
return _add_client_token(pStrBuffer, sizeOfBuffer, tokenNumber);
}
void build_empty_json(uint32_t *tokenNumber, char *pJsonBuffer) {
HAL_Snprintf(pJsonBuffer, MAX_SIZE_OF_JSON_WITH_CLIENT_TOKEN, "{\"clientToken\":\"%s-%u\"}", iot_device_info_get()->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_action_id(char *pJsonDoc, char **pActionID) {
*pActionID = LITE_json_value_of(ACTION_ID_FIELD, pJsonDoc);
return *pActionID == NULL ? false : true;
}
bool parse_time_stamp(char *pJsonDoc, int32_t *pTimestamp) {
bool ret = false;
char *timestamp = LITE_json_value_of(TIME_STAMP_FIELD, pJsonDoc);
if (timestamp == NULL) return false;
if (sscanf(timestamp, "%" SCNu32, pTimestamp) != 1) {
Log_e("parse code failed, errCode: %d", QCLOUD_ERR_JSON_PARSE);
}
else {
ret = true;
}
HAL_Free(timestamp);
return ret;
}
bool parse_action_input(char *pJsonDoc, char **pActionInput)
{
*pActionInput = LITE_json_value_of(CMD_CONTROL_PARA, pJsonDoc);
return *pActionInput == 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 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;
}
bool parse_template_method_type(char *pJsonDoc, char **pMethod)
{
*pMethod = LITE_json_value_of(METHOD_FIELD, pJsonDoc);
return *pMethod == NULL ? false : true;
}
bool parse_template_get_control(char *pJsonDoc, char **control)
{
*control = LITE_json_value_of(GET_CONTROL_PARA, pJsonDoc);
return *control == NULL ? false : true;
}
bool parse_template_cmd_control(char *pJsonDoc, char **control)
{
*control = LITE_json_value_of(CMD_CONTROL_PARA, pJsonDoc);
return *control == NULL ? false : true;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,590 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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 <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include "qcloud_iot_import.h"
#include "utils_param_check.h"
#include "utils_list.h"
#include "data_template_client.h"
#include "data_template_client_json.h"
typedef void (*TraverseTemplateHandle)(Qcloud_IoT_Template *pTemplate, ListNode **node, List *list, const char *pClientToken, const char *pType);
static char sg_template_cloud_rcv_buf[CLOUD_IOT_JSON_RX_BUF_LEN];
static char sg_template_clientToken[MAX_SIZE_OF_CLIENT_TOKEN];
/**
* @brief unsubsribe topic: $thing/down/property/{ProductId}/{DeviceName}
*/
static int _unsubscribe_template_downstream_topic(void* pClient)
{
IOT_FUNC_ENTRY;
int rc = QCLOUD_RET_SUCCESS;
char downstream_topic[MAX_SIZE_OF_CLOUD_TOPIC] = {0};
int size = HAL_Snprintf(downstream_topic, MAX_SIZE_OF_CLOUD_TOPIC, "$thing/down/property/%s/%s", iot_device_info_get()->product_id, iot_device_info_get()->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);
}
IOT_MQTT_Unsubscribe(pClient, downstream_topic);
if (rc < 0) {
Log_e("unsubscribe topic: %s failed: %d.", downstream_topic, rc);
}
IOT_FUNC_EXIT_RC(rc);
}
/**
* @brief add request to data_template request wait for reply list
*/
static int _add_request_to_template_list(Qcloud_IoT_Template *pTemplate, const char *pClientToken, RequestParams *pParams)
{
IOT_FUNC_ENTRY;
HAL_MutexLock(pTemplate->mutex);
if (pTemplate->inner_data.reply_list->len >= MAX_APPENDING_REQUEST_AT_ANY_GIVEN_TIME)
{
HAL_MutexUnlock(pTemplate->mutex);
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MAX_APPENDING_REQUEST);
}
Request *request = (Request *)HAL_Malloc(sizeof(Request));
if (NULL == request) {
HAL_MutexUnlock(pTemplate->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(pTemplate->mutex);
Log_e("run list_node_new is error!");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
list_rpush(pTemplate->inner_data.reply_list, node);
HAL_MutexUnlock(pTemplate->mutex);
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
/**
* @brief publish operation to server
*
* @param pClient handle to data_template client
* @param method method type
* @param pJsonDoc JSON to publish
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
*/
int _publish_to_template_upstream_topic(Qcloud_IoT_Template *pTemplate, Method method, char *pJsonDoc)
{
IOT_FUNC_ENTRY;
int rc = QCLOUD_RET_SUCCESS;
char topic[MAX_SIZE_OF_CLOUD_TOPIC] = {0};
int size;
size = HAL_Snprintf(topic, MAX_SIZE_OF_CLOUD_TOPIC, "$thing/up/property/%s/%s", iot_device_info_get()->product_id, iot_device_info_get()->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(pTemplate->mqtt, topic, &pubParams);
IOT_FUNC_EXIT_RC(rc);
}
/**
* @brief fill method json filed with the value of RequestParams and Method
*/
static int _set_template_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 *method_str = NULL;
switch (method) {
case GET:
method_str = GET_STATUS;
break;
case REPORT:
method_str = REPORT_CMD;
break;
case RINFO:
method_str = INFO_CMD;
break;
case REPLY:
method_str = CONTROL_CMD_REPLY;
break;
case CLEAR:
method_str = CLEAR_CONTROL;
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, "\"method\":\"%s\", ", method_str);
size_t json_node_len = strlen(json_node_str);
if (json_node_len >= remain_size - 1) {
rc = QCLOUD_ERR_INVAL;
} else {
insert_str(pJsonDoc, json_node_str, 1);
}
IOT_FUNC_EXIT_RC(rc);
}
/**
* @brief iterator list and call traverseHandle for each node
*/
static void _traverse_template_list(Qcloud_IoT_Template *pTemplate, List *list, const char *pClientToken, const char *pType, TraverseTemplateHandle traverseHandle)
{
IOT_FUNC_ENTRY;
HAL_MutexLock(pTemplate->mutex);
if (list->len) {
ListIterator *iter;
ListNode *node = NULL;
if (NULL == (iter = list_iterator_new(list, LIST_TAIL))) {
HAL_MutexUnlock(pTemplate->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(pTemplate, &node, list, pClientToken, pType);
}
list_iterator_destroy(iter);
}
HAL_MutexUnlock(pTemplate->mutex);
IOT_FUNC_EXIT;
}
/**
* @brief handle the timeout request wait for reply
*/
static void _handle_template_expired_reply_callback(Qcloud_IoT_Template *pTemplate, 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(pTemplate, request->method, ACK_TIMEOUT, sg_template_cloud_rcv_buf, request);
}
list_remove(list, *node);
*node = NULL;
}
IOT_FUNC_EXIT;
}
static void _set_control_clientToken(const char *pClientToken)
{
memset(sg_template_clientToken, '\0', MAX_SIZE_OF_CLIENT_TOKEN);
strncpy(sg_template_clientToken, pClientToken, MAX_SIZE_OF_CLIENT_TOKEN);
}
char * get_control_clientToken(void)
{
return sg_template_clientToken;
}
void qcloud_iot_template_reset(void *pClient)
{
POINTER_SANITY_CHECK_RTN(pClient);
Qcloud_IoT_Template *template_client = (Qcloud_IoT_Template *)pClient;
if (template_client->inner_data.property_handle_list) {
list_destroy(template_client->inner_data.property_handle_list);
}
_unsubscribe_template_downstream_topic(template_client->mqtt);
if (template_client->inner_data.reply_list)
{
list_destroy(template_client->inner_data.reply_list);
}
if (template_client->inner_data.event_list)
{
list_destroy(template_client->inner_data.event_list);
}
}
int qcloud_iot_template_init(Qcloud_IoT_Template *pTemplate)
{
IOT_FUNC_ENTRY;
POINTER_SANITY_CHECK(pTemplate, QCLOUD_ERR_INVAL);
pTemplate->mutex = HAL_MutexCreate();
if (pTemplate->mutex == NULL)
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
pTemplate->inner_data.property_handle_list = list_new();
if (pTemplate->inner_data.property_handle_list)
{
pTemplate->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);
}
pTemplate->inner_data.reply_list = list_new();
if (pTemplate->inner_data.reply_list)
{
pTemplate->inner_data.reply_list->free = HAL_Free;
} else {
Log_e("no memory to allocate reply_list");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
pTemplate->inner_data.event_list = list_new();
if (pTemplate->inner_data.event_list)
{
pTemplate->inner_data.event_list->free = HAL_Free;
} else {
Log_e("no memory to allocate event_list");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
pTemplate->inner_data.action_handle_list = list_new();
if (pTemplate->inner_data.action_handle_list)
{
pTemplate->inner_data.action_handle_list->free = HAL_Free;
} else {
Log_e("no memory to allocate action_handle_list");
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
void handle_template_expired_reply(Qcloud_IoT_Template *pTemplate)
{
IOT_FUNC_ENTRY;
_traverse_template_list(pTemplate, pTemplate->inner_data.reply_list, NULL, NULL, _handle_template_expired_reply_callback);
IOT_FUNC_EXIT;
}
int send_template_request(Qcloud_IoT_Template *pTemplate, RequestParams *pParams, char *pJsonDoc, size_t sizeOfBuffer)
{
IOT_FUNC_ENTRY;
int rc = QCLOUD_RET_SUCCESS;
POINTER_SANITY_CHECK(pTemplate, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(pJsonDoc, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(pParams, QCLOUD_ERR_INVAL);
char* client_token = NULL;
// parse clientToken in pJsonDoc, return err if parse failed
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_template_json_type(pJsonDoc, sizeOfBuffer, pParams->method);
if (rc != QCLOUD_RET_SUCCESS)
IOT_FUNC_EXIT_RC(rc);
if (rc == QCLOUD_RET_SUCCESS) {
rc = _publish_to_template_upstream_topic(pTemplate, pParams->method, pJsonDoc);
}
if ((rc == QCLOUD_RET_SUCCESS) && (NULL != pParams->request_callback)) {
rc = _add_request_to_template_list(pTemplate, client_token, pParams);
}
HAL_Free(client_token);
IOT_FUNC_EXIT_RC(rc);
}
static void _handle_control(Qcloud_IoT_Template *pTemplate, char* control_str)
{
IOT_FUNC_ENTRY;
if (pTemplate->inner_data.property_handle_list->len) {
ListIterator *iter;
ListNode *node = NULL;
PropertyHandler *property_handle = NULL;
if (NULL == (iter = list_iterator_new(pTemplate->inner_data.property_handle_list, LIST_TAIL))) {
HAL_MutexUnlock(pTemplate->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(control_str, property_handle->property))
{
if (property_handle->callback != NULL)
{
property_handle->callback(pTemplate, control_str, strlen(control_str), property_handle->property);
}
node = NULL;
}
}
}
list_iterator_destroy(iter);
}
IOT_FUNC_EXIT;
}
static void _handle_template_reply_callback(Qcloud_IoT_Template *pTemplate, 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)
{
ReplyAck status = ACK_NONE;
// check operation success or not according to code field of reply message
int32_t reply_code = 0;
bool parse_success = parse_code_return(sg_template_cloud_rcv_buf, &reply_code);
if (parse_success) {
if (reply_code == 0) {
status = ACK_ACCEPTED;
} else {
status = ACK_REJECTED;
}
if (strcmp(pType, GET_STATUS_REPLY) == 0 && status == ACK_ACCEPTED)
{
char* control_str = NULL;
if (parse_template_get_control(sg_template_cloud_rcv_buf, &control_str)) {
Log_d("control data from get_status_reply");
_set_control_clientToken(pClientToken);
_handle_control(pTemplate, control_str);
HAL_Free(control_str);
*((ReplyAck *)request->user_context) = ACK_ACCEPTED; //prepare for clear_control
}
}
if (request->callback != NULL) {
request->callback(pTemplate, request->method, status, sg_template_cloud_rcv_buf, request);
}
}
else {
Log_e("parse template operation result code failed.");
}
list_remove(list, *node);
*node = NULL;
}
IOT_FUNC_EXIT;
}
static void _on_template_downstream_topic_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_Template *template_client = (Qcloud_IoT_Template*)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);
memset(sg_template_cloud_rcv_buf, 0, sizeof(sg_template_cloud_rcv_buf));
memcpy(sg_template_cloud_rcv_buf, message->payload, cloud_rcv_len + 1);
sg_template_cloud_rcv_buf[cloud_rcv_len] = '\0'; // jsmn_parse relies on a string
//Log_d("recv:%s", sg_template_cloud_rcv_buf);
//parse the message type from topic $thing/down/property
if (!parse_template_method_type(sg_template_cloud_rcv_buf, &type_str))
{
Log_e("Fail to parse method!");
goto End;
}
if (!parse_client_token(sg_template_cloud_rcv_buf, &client_token)) {
Log_e("Fail to parse client token! Json=%s", sg_template_cloud_rcv_buf);
goto End;
}
//handle control message
if (!strcmp(type_str, CONTROL_CMD)) {
HAL_MutexLock(template_client->mutex);
char* control_str = NULL;
if (parse_template_cmd_control(sg_template_cloud_rcv_buf, &control_str)) {
Log_d("control_str:%s", control_str);
_set_control_clientToken(client_token);
_handle_control(template_client, control_str);
HAL_Free(control_str);
}
HAL_MutexUnlock(template_client->mutex);
goto End;
}
if (template_client != NULL)
_traverse_template_list(template_client, template_client->inner_data.reply_list, client_token, type_str, _handle_template_reply_callback);
End:
HAL_Free(type_str);
HAL_Free(client_token);
IOT_FUNC_EXIT;
}
int subscribe_template_downstream_topic(Qcloud_IoT_Template *pTemplate)
{
IOT_FUNC_ENTRY;
int rc;
int size;
if (pTemplate->inner_data.downstream_topic == NULL) {
char *downstream_topic = (char *)HAL_Malloc(MAX_SIZE_OF_CLOUD_TOPIC * sizeof(char));
if (downstream_topic == NULL) IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
memset(downstream_topic, 0x0, MAX_SIZE_OF_CLOUD_TOPIC);
size = HAL_Snprintf(downstream_topic, MAX_SIZE_OF_CLOUD_TOPIC, "$thing/down/property/%s/%s", iot_device_info_get()->product_id, iot_device_info_get()->device_name);
if (size < 0 || size > MAX_SIZE_OF_CLOUD_TOPIC - 1)
{
Log_e("buf size < topic length!");
HAL_Free(downstream_topic);
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
pTemplate->inner_data.downstream_topic = downstream_topic;
}
SubscribeParams subscribe_params = DEFAULT_SUB_PARAMS;
subscribe_params.on_message_handler = _on_template_downstream_topic_handler;
subscribe_params.qos = QOS0;
rc = IOT_MQTT_Subscribe(pTemplate->mqtt, pTemplate->inner_data.downstream_topic, &subscribe_params);
if (rc < 0) {
Log_e("subscribe topic: %s failed: %d.", pTemplate->inner_data.downstream_topic, rc);
}
IOT_FUNC_EXIT_RC(rc);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,493 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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"
#if defined(EVENT_POST_ENABLED)
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "utils_param_check.h"
#include "lite-utils.h"
#include "data_template_client.h"
#include "data_template_event.h"
/**
* @brief iterator event list and call traverseHandle for each node
*/
static void _traverse_event_list(Qcloud_IoT_Template *pTemplate, List *list, const char *pClientToken, MQTTMessage *message, eEventDealType eDealType)
{
IOT_FUNC_ENTRY;
HAL_MutexLock(pTemplate->mutex);
if (list->len) {
ListIterator *iter;
ListNode *node = NULL;
if (NULL == (iter = list_iterator_new(list, LIST_TAIL))) {
HAL_MutexUnlock(pTemplate->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;
}
sEventReply *pReply = (sEventReply *)node->val;
/*timeout check*/
if(eDEAL_EXPIRED == eDealType){
if(expired(&pReply->timer)){
Log_e("eventToken[%s] timeout",pReply->client_token);
list_remove(list, node);
node = NULL;
}
}
/*match event wait for reply by clientToken*/
if((eDEAL_REPLY_CB == eDealType) && (0 == strcmp(pClientToken, pReply->client_token))){
if(NULL != pReply->callback){
pReply->callback(pTemplate, message);
Log_d("eventToken[%s] released",pReply->client_token);
list_remove(list, node);
node = NULL;
}
}
}
list_iterator_destroy(iter);
}
HAL_MutexUnlock(pTemplate->mutex);
IOT_FUNC_EXIT;
}
static void _on_event_reply_callback(void *pClient, MQTTMessage *message, void *userData)
{
POINTER_SANITY_CHECK_RTN(message);
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
Qcloud_IoT_Template *template_client = (Qcloud_IoT_Template*)mqtt_client->event_handle.context;
int32_t code;
char* client_token = NULL;
char* status = NULL;
Log_d("recv:%.*s",(int) message->payload_len, (char *) message->payload);
// parse clientToken from payload
if (!parse_client_token((char *) message->payload, &client_token)) {
Log_e("fail to parse client token!");
return;
}
// parse code from payload
if(!parse_code_return((char *) message->payload, &code)){
Log_e("fail to parse code");
return;
}
if(!parse_status_return((char *) message->payload, &status)){
// Log_d("no status return");
}
Log_d("eventToken:%s code:%d status:%s", client_token, code, status);
if (template_client != NULL)
_traverse_event_list(template_client, template_client->inner_data.event_list, client_token, message, eDEAL_REPLY_CB);
HAL_Free(client_token);
HAL_Free(status);
return;
}
/**
* @brief create event reply struct and add to event_list
*/
static sEventReply * _create_event_add_to_list(Qcloud_IoT_Template *pTemplate, OnEventReplyCallback replyCb, uint32_t reply_timeout_ms)
{
IOT_FUNC_ENTRY;
HAL_MutexLock(pTemplate->mutex);
if (pTemplate->inner_data.event_list->len >= MAX_EVENT_WAIT_REPLY)
{
HAL_MutexUnlock(pTemplate->mutex);
Log_e("Too many event wait for reply");
IOT_FUNC_EXIT_RC(NULL);
}
sEventReply *pReply = (sEventReply *)HAL_Malloc(sizeof(Request));
if (NULL == pReply) {
HAL_MutexUnlock(pTemplate->mutex);
Log_e("run memory malloc is error!");
IOT_FUNC_EXIT_RC(NULL);
}
pReply->callback = replyCb;
pReply->user_context = pTemplate;
InitTimer(&(pReply->timer));
countdown(&(pReply->timer), reply_timeout_ms);
HAL_Snprintf(pReply->client_token, EVENT_TOKEN_MAX_LEN, "%s-%u", iot_device_info_get()->product_id, pTemplate->inner_data.token_num++);
ListNode *node = list_node_new(pReply);
if (NULL == node) {
HAL_MutexUnlock(pTemplate->mutex);
Log_e("run list_node_new is error!");
HAL_Free(pReply);
IOT_FUNC_EXIT_RC(NULL);
}
list_rpush(pTemplate->inner_data.event_list, node);
HAL_MutexUnlock(pTemplate->mutex);
IOT_FUNC_EXIT_RC(pReply);
}
static int _iot_event_json_init(void *handle, char *jsonBuffer, size_t sizeOfBuffer, uint8_t event_count, OnEventReplyCallback replyCb, uint32_t reply_timeout_ms)
{
POINTER_SANITY_CHECK(jsonBuffer, QCLOUD_ERR_INVAL);
Qcloud_IoT_Template* ptemplate = (Qcloud_IoT_Template *)handle;
int32_t rc_of_snprintf;
sEventReply *pReply;
pReply = _create_event_add_to_list(ptemplate, replyCb, reply_timeout_ms);
if(!pReply){
Log_e("create event failed");
return QCLOUD_ERR_FAILURE;
}
memset(jsonBuffer, 0, sizeOfBuffer);
if(event_count > SIGLE_EVENT){
rc_of_snprintf = HAL_Snprintf(jsonBuffer, sizeOfBuffer, "{\"method\":\"%s\", \"clientToken\":\"%s\", ", \
POST_EVENTS, pReply->client_token);
}else{
rc_of_snprintf = HAL_Snprintf(jsonBuffer, sizeOfBuffer, "{\"method\":\"%s\", \"clientToken\":\"%s\", ", \
POST_EVENT, pReply->client_token);
}
return check_snprintf_return(rc_of_snprintf, sizeOfBuffer);
}
static int _iot_construct_event_json(void *handle, char *jsonBuffer, size_t sizeOfBuffer,
uint8_t event_count,
sEvent *pEventArry[],
OnEventReplyCallback replyCb,
uint32_t reply_timeout_ms)
{
size_t remain_size = 0;
int32_t rc_of_snprintf = 0;
uint8_t i,j;
Qcloud_IoT_Template* ptemplate = (Qcloud_IoT_Template *)handle;
POINTER_SANITY_CHECK(ptemplate, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(jsonBuffer, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(pEventArry, QCLOUD_ERR_INVAL);
int rc = _iot_event_json_init(ptemplate, jsonBuffer, sizeOfBuffer, event_count, replyCb, reply_timeout_ms);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("event json init failed: %d", rc);
return rc;
}
//Log_d("event_count:%d, Doc_init:%s",event_count, jsonBuffer);
if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) {
return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL;
}
if(event_count > SIGLE_EVENT){//mutlti event
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "\"events\":[");
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;
}
for(i = 0; i < event_count; i++){
sEvent *pEvent = pEventArry[i];
if(NULL == pEvent){
Log_e("%dth/%d null event", i, event_count);
return QCLOUD_ERR_INVAL;
}
if(0 == pEvent->timestamp){ //no accurate UTC time, set 0
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "{\"eventId\":\"%s\", \"type\":\"%s\", \"timestamp\":0, \"params\":{",\
pEvent->event_name, pEvent->type);
}else{ // accurate UTC time is second,change to ms
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "{\"eventId\":\"%s\", \"type\":\"%s\", \"timestamp\":%u000, \"params\":{",\
pEvent->event_name, pEvent->type, pEvent->timestamp);
}
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;
}
DeviceProperty *pJsonNode = pEvent->pEventData;
for (j = 0; j < pEvent->eventDataNum; j++) {
if (pJsonNode != NULL && pJsonNode->key != NULL) {
rc = template_put_json_node(jsonBuffer, remain_size, pJsonNode->key, pJsonNode->data, pJsonNode->type);
if (rc != QCLOUD_RET_SUCCESS) {
return rc;
}
} else {
Log_e("%dth/%d null event property data", i, pEvent->eventDataNum);
return QCLOUD_ERR_INVAL;
}
pJsonNode++;
}
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) {
return rc;
}
pEvent++;
}
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) {
return rc;
}
}else{ //single
sEvent *pEvent = pEventArry[0];
if(0 == pEvent->timestamp){ //no accurate UTC time, set 0
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "{\"eventId\":\"%s\", \"type\":\"%s\", \"timestamp\":0, \"params\":{",\
pEvent->event_name, pEvent->type);
}else{ // accurate UTC time is second,change to ms
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "\"eventId\":\"%s\", \"type\":\"%s\", \"timestamp\":%u000, \"params\":{",\
pEvent->event_name, pEvent->type, pEvent->timestamp);
}
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;
}
DeviceProperty *pJsonNode = pEvent->pEventData;
for (i = 0; i < pEvent->eventDataNum; i++) {
if (pJsonNode != NULL && pJsonNode->key != NULL) {
rc = template_put_json_node(jsonBuffer, remain_size, pJsonNode->key, pJsonNode->data, pJsonNode->type);
if (rc != QCLOUD_RET_SUCCESS) {
return rc;
}
} else {
Log_e("%dth/%d null event property data", i, pEvent->eventDataNum);
return QCLOUD_ERR_INVAL;
}
pJsonNode++;
}
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) {
return rc;
}
}
//finish json
if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) < 1) {
return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL;
}
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "}");
return check_snprintf_return(rc_of_snprintf, remain_size);
}
static int _publish_event_to_cloud(void *c, char *pJsonDoc)
{
IOT_FUNC_ENTRY;
int rc = QCLOUD_RET_SUCCESS;
char topic[MAX_SIZE_OF_CLOUD_TOPIC] = {0};
Qcloud_IoT_Template *ptemplate = (Qcloud_IoT_Template *)c;
int size = HAL_Snprintf(topic, MAX_SIZE_OF_CLOUD_TOPIC, "$thing/up/event/%s/%s", iot_device_info_get()->product_id, iot_device_info_get()->device_name);
if (size < 0 || size > sizeof(topic) - 1)
{
Log_e("topic content length not enough! content size:%d buf size:%d", size, (int)sizeof(topic));
return QCLOUD_ERR_FAILURE;
}
PublishParams pubParams = DEFAULT_PUB_PARAMS;
pubParams.qos = QOS0;
pubParams.payload_len = strlen(pJsonDoc);
pubParams.payload = (char *) pJsonDoc;
rc = IOT_MQTT_Publish(ptemplate->mqtt, topic, &pubParams);
IOT_FUNC_EXIT_RC(rc);
}
void handle_template_expired_event(void *client)
{
IOT_FUNC_ENTRY;
Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)client;
_traverse_event_list(pTemplate, pTemplate->inner_data.event_list, NULL, NULL, eDEAL_EXPIRED);
IOT_FUNC_EXIT;
}
void IOT_Event_setFlag(void *client, uint32_t flag)
{
Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)client;
pTemplate->inner_data.eventflags |= flag&0xffffffff;
}
void IOT_Event_clearFlag(void *client, uint32_t flag)
{
Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)client;
pTemplate->inner_data.eventflags &= (~flag)&0xffffffff;
}
uint32_t IOT_Event_getFlag(void *client)
{
Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)client;
return pTemplate->inner_data.eventflags;
}
int IOT_Event_Init(void *c)
{
static char topic_name[MAX_SIZE_OF_CLOUD_TOPIC] = {0};
Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)c;
int size = HAL_Snprintf(topic_name, MAX_SIZE_OF_CLOUD_TOPIC, "$thing/down/event/%s/%s", iot_device_info_get()->product_id, iot_device_info_get()->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 = _on_event_reply_callback;
return IOT_MQTT_Subscribe(pTemplate->mqtt, topic_name, &sub_params);
}
int IOT_Post_Event(void *pClient, char *pJsonDoc, size_t sizeOfBuffer, uint8_t event_count, sEvent *pEventArry[], OnEventReplyCallback replyCb)
{
int rc;
rc = _iot_construct_event_json(pClient, pJsonDoc, sizeOfBuffer, event_count, pEventArry, replyCb, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("construct event json fail, %d",rc);
return rc;
}
rc = _publish_event_to_cloud(pClient, pJsonDoc);
if (rc < 0) {
Log_e("publish event to cloud fail, %d",rc);
}
return rc;
}
int IOT_Post_Event_Raw(void *pClient, char *pJsonDoc, size_t sizeOfBuffer, char *pEventMsg, OnEventReplyCallback replyCb)
{
int rc;
size_t remain_size = 0;
int32_t rc_of_snprintf;
Qcloud_IoT_Template* ptemplate = (Qcloud_IoT_Template *)pClient;
POINTER_SANITY_CHECK(ptemplate, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(pJsonDoc, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(pEventMsg, QCLOUD_ERR_INVAL);
rc = _iot_event_json_init(ptemplate, pJsonDoc, sizeOfBuffer, MUTLTI_EVENTS, replyCb, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("event json init failed: %d", rc);
return rc;
}
if ((remain_size = sizeOfBuffer - strlen(pJsonDoc)) <= 1) {
return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL;
}
rc_of_snprintf = HAL_Snprintf(pJsonDoc + strlen(pJsonDoc), remain_size, "\"events\":[%s]}", pEventMsg);
rc = check_snprintf_return(rc_of_snprintf, remain_size);
if (rc != QCLOUD_RET_SUCCESS) {
return rc;
}
Log_d("JsonDoc:%s", pJsonDoc);
rc = _publish_event_to_cloud(pClient, pJsonDoc);
if (rc < 0 ) {
Log_e("publish event raw to cloud fail, %d",rc);
}
return rc;
}
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,657 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ota_client.h"
#include "qcloud_iot_export.h"
#include "utils_param_check.h"
#include "ota_lib.h"
#include "ota_fetch.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");
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;
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);
}
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_d("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,153 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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_export.h"
#include "qcloud_iot_import.h"
#include "qcloud_iot_ca.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;
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;
}
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;
if (is_begin_with(h_odc->url, "https"))
{
port = 443;
ca_crt = iot_https_ca_get();
}
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,324 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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 <string.h>
#include <stdio.h>
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "ota_client.h"
#include "utils_md5.h"
#include "lite-utils.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,189 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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 "ota_client.h"
#include <string.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;
} 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);
}
}
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.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;
}
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) {
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,213 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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>
#ifdef __cplusplus
extern "C" {
#endif
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#ifdef SYSTEM_COMM
#include "qcloud_iot_export_system.h"
#include "mqtt_client.h"
#include "lite-utils.h"
#include "device.h"
typedef struct _sys_mqtt_state {
bool topic_sub_ok;
bool result_recv_ok;
long time;
}SysMQTTState;
static SysMQTTState sg_state = {
.topic_sub_ok = false,
.result_recv_ok = false,
.time = 0};
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 = iot_device_info_get();
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);
DeviceInfo *dev_info = iot_device_info_get();
POINTER_SANITY_CHECK(dev_info, QCLOUD_ERR_INVAL);
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 *)&sg_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;
// subscribe sys topic: $sys/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 = _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((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 sys topic failed!");
return QCLOUD_ERR_FAILURE;
}
sg_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((Qcloud_IoT_Client *)pClient, 100);
cntRev++;
} while(!sg_state.result_recv_ok && cntRev < 20);
if (sg_state.result_recv_ok) {
*time = sg_state.time;
ret = QCLOUD_RET_SUCCESS;
} else {
*time = 0;
ret = QCLOUD_ERR_FAILURE;
}
return ret;
}
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,266 @@
/*
* Copyright (c) 2017-2019 Tencent Group. All rights reserved.
* License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
*
*/
/**
* Edit by shockcao@tencent.com 2018/3/15
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "json_parser.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,219 @@
/*
* Copyright (c) 2017-2019 Tencent Group. All rights reserved.
* License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
*
*/
/**
* Edit by shockcao@tencent.com 2018/3/15
*/
#include "json_parser.h"
#include "lite-utils.h"
#include "qcloud_iot_export_error.h"
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;
}
int LITE_get_string(int8_t *value, char *src, uint16_t max_len) {
int rc;
if(NULL != strncpy((char *)value, src, max_len)){
value[Min(strlen(src), max_len)] = '\0';
rc = QCLOUD_RET_SUCCESS;
}else{
rc = QCLOUD_ERR_FAILURE;
}
return rc;
}

View File

@@ -0,0 +1,124 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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>
#ifndef AUTH_WITH_NOTLS
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-----"
};
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
const char *iot_ca_get() {
#ifndef AUTH_WITH_NOTLS
return iot_ca_crt;
#else
return NULL;
#endif
}
const char *iot_https_ca_get() {
#ifndef AUTH_WITH_NOTLS
return iot_https_ca_crt;
#else
return NULL;
#endif
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,78 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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 <string.h>
#include "qcloud_iot_device.h"
#include "qcloud_iot_export.h"
static DeviceInfo sg_device_info;
static bool sg_devinfo_initialized;
int iot_device_info_init()
{
if (sg_devinfo_initialized) {
Log_e("device info has been initialized.");
return 0;
}
memset(&sg_device_info, 0x0, sizeof(DeviceInfo));
sg_devinfo_initialized = true;
return QCLOUD_RET_SUCCESS;
}
int iot_device_info_set(const char *product_id, const char *device_name)
{
memset(&sg_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(sg_device_info.product_id, product_id, MAX_SIZE_OF_PRODUCT_ID);
strncpy(sg_device_info.device_name, device_name, MAX_SIZE_OF_DEVICE_NAME);
/* construct device-id(@product_id+@device_name) */
memset(sg_device_info.client_id, 0x0, MAX_SIZE_OF_CLIENT_ID);
int ret = HAL_Snprintf(sg_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, product_id, device_name);
return QCLOUD_RET_SUCCESS;
}
DeviceInfo* iot_device_info_get(void)
{
return &sg_device_info;
}
#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) 2016 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_log.h"
#include <string.h>
#include "qcloud_iot_import.h"
#include "log_upload.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() {
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() {
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));
o += HAL_Snprintf(o, sizeof(sg_text_buf), "%s|%s|%s|%s(%d): ", level_str[level], HAL_Timer_current(), file_name, func, line);
va_list ap;
va_start(ap, fmt);
o += 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,172 @@
/*
* Copyright (c) 2017-2019 Tencent Group. All rights reserved.
* License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
*
*/
/**
* Edit by shockcao@tencent.com 2018/3/15
*/
#include "lite-utils.h"
#include "qcloud_iot_import.h"
#include "qcloud_iot_export_log.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) {
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,203 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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 "utils_base64.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,102 @@
/*
* Copyright (c) 2017-2019 Tencent Group. All rights reserved.
* License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 <stdio.h>
#include "qcloud_iot_import.h"
#include "utils_getopt.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,126 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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 "qcloud_iot_export_log.h"
#include "utils_md5.h"
#include "utils_sha1.h"
#include "utils_hmac.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,299 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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_import.h"
#include "qcloud_iot_export_log.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);
self = NULL;
}
/*
* 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,318 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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_import.h"
#include "qcloud_iot_export.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,106 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2019 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 <stdio.h>
#include <string.h>
#include "utils_ringbuff.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,337 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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 <stdlib.h>
#include <string.h>
#include "qcloud_iot_import.h"
#include "qcloud_iot_export_log.h"
#include "utils_sha1.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,44 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 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