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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,41 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 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 "coap_client_net.h"
#include "network_interface.h"
int qcloud_iot_coap_network_init(Network *pNetwork)
{
int rc;
/* first choice: TLS */
pNetwork->type = NETWORK_DTLS;
#ifdef AUTH_WITH_NOTLS
pNetwork->type = NETWORK_UDP;
#endif
rc = network_init(pNetwork);
return rc;
}
#ifdef __cplusplus
}
#endif

View File

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