first commit for opensource

first commit for opensource
This commit is contained in:
supowang
2019-09-16 13:19:50 +08:00
parent 08ab013b8e
commit edb2879617
6303 changed files with 5472815 additions and 23 deletions

View File

@@ -0,0 +1,106 @@
/*
* 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.h"
__QCLOUD_STATIC__ void coap_auth_callback(void *message, void *context)
{
QCLOUD_FUNC_ENTRY
QCLOUD_POINTER_SANITY_CHECK_RTN(message);
QCLOUD_POINTER_SANITY_CHECK_RTN(context);
coap_message_t *msg = NULL;
qcloud_coap_client_t *client = NULL;
msg = (coap_message_t *)message;
client = (qcloud_coap_client_t *)context;
if (msg->code_class != COAP_CODE_CLASS_SUCCESS ||
msg->code_detail != COAP_CODE_DETAIL_205_CONTENT) {
client->auth_state = QCLOUD_COAP_AUTH_STATE_FAIL;
QCLOUD_LOG_E("auth token failed, code_class: %d code_detail: %d", msg->code_class, msg->code_detail);
return;
}
QCLOUD_LOG_I("auth token success, code_class: %d code_detail: %d", msg->code_class, msg->code_detail);
if (msg->payload_len == 0 ||
msg->payload == NULL ||
strlen(msg->payload) == 0) {
client->auth_state = QCLOUD_COAP_AUTH_STATE_FAIL;
QCLOUD_LOG_E("auth token response empty");
} else {
client->auth_token_len = msg->payload_len;
client->auth_token = osal_malloc(client->auth_token_len);
strncpy(client->auth_token, msg->payload,client->auth_token_len);
client->auth_state = QCLOUD_COAP_AUTH_STATE_SUCCESS;
QCLOUD_LOG_D("auth_token_len = %d, auth_token = %.*s", client->auth_token_len, client->auth_token_len, client->auth_token);
}
QCLOUD_FUNC_EXIT
}
__QCLOUD_INTERNAL__ qcloud_err_t coap_auth(qcloud_coap_client_t *client, char *connection_id)
{
QCLOUD_FUNC_ENTRY
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_COAP_NULL);
int len;
qcloud_err_t rc;
char message_token[8] = {0};
coap_message_t connect_msg = COAP_MESSAGE_INITIALIZER;
coap_message_init(&connect_msg);
coap_message_type_set(&connect_msg, COAP_MSG_TYPE_CON);
coap_message_code_set(&connect_msg, COAP_CODE_CLASS_REQ, COAP_REQUEST_METHOD_POST);
coap_message_id_set(&connect_msg, coap_glue_packet_id_generate(client));
len = coap_message_token_get(client, message_token);
coap_message_token_set(&connect_msg, message_token, len);
coap_message_option_add(&connect_msg, COAP_MSG_OPTION_CODE_URI_PATH, strlen(client->auth_uri), client->auth_uri);
coap_message_option_add(&connect_msg, COAP_MSG_OPTION_CODE_NEED_RESP, 1, "0");
coap_message_callback_set(&connect_msg, coap_auth_callback);
coap_message_context_set(&connect_msg, client);
connect_msg.payload_len = sizeof(client->auth_id);
connect_msg.payload = (char *)osal_malloc(connect_msg.payload_len);
if (!connect_msg.payload) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
}
coap_message_payload_set(&connect_msg, client->auth_id, connect_msg.payload_len);
rc = coap_glue_msg_send(client, &connect_msg);
osal_free(connect_msg.payload);
QCLOUD_FUNC_EXIT_RC(rc)
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,306 @@
/*
* 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.h"
__QCLOUD_STATIC__ qcloud_err_t coap_client_network_host_construct(qcloud_network_t *network, qcloud_device_t *device)
{
int server_len;
char coap_server[QCLOUD_SERVER_DOMAIN_MAX];
memset(network->host, 0, sizeof(network->host));
server_len = osal_snprintf(coap_server, sizeof(coap_server), "%s.%s", device->product_id, qcloud_coap_server);
if (server_len < 0 || server_len > QCLOUD_SERVER_DOMAIN_MAX - 1) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
memcpy(network->host, coap_server, sizeof(network->host));
network->port = qcloud_coap_port;
return QCLOUD_ERR_SUCCESS;
}
__QCLOUD_STATIC__ qcloud_err_t coap_client_network_init(qcloud_network_t *network, qcloud_device_t *device)
{
#if (QCLOUD_CFG_TLS_EN > 0u)
QCLOUD_FUNC_EXIT_RC_IF_NOT(qcloud_tls_init(&network->tls_opt, device), QCLOUD_ERR_SUCCESS, QCLOUD_ERR_FAILURE);
QCLOUD_FUNC_EXIT_RC_IF_NOT(qcloud_network_dtls_init(network), QCLOUD_ERR_SUCCESS, QCLOUD_ERR_FAILURE);
#else
QCLOUD_FUNC_EXIT_RC_IF_NOT(qcloud_network_udp_init(network), QCLOUD_ERR_SUCCESS, QCLOUD_ERR_FAILURE);
#endif
QCLOUD_FUNC_EXIT_RC_IF_NOT(coap_client_network_host_construct(network, device), QCLOUD_ERR_SUCCESS, QCLOUD_ERR_FAILURE);
return QCLOUD_ERR_SUCCESS;
}
__QCLOUD_STATIC__ uint16_t coap_client_random_packet_id_generate(void)
{
#define PACKET_ID_MAX (65535)
srand((unsigned)osal_timer_current_sec());
return rand() % (PACKET_ID_MAX + 1) + 1;
}
__QCLOUD_STATIC__ qcloud_err_t coap_client_construct(qcloud_coap_client_t *client,
qcloud_device_t *device,
coap_event_handler_fn_t handler)
{
int len = 0;
client->auth_state = QCLOUD_COAP_AUTH_STATE_NONE;
client->command_timeout = QCLOUD_COAP_COMMAND_TIMEOUT;
client->message_token = 0;
client->event_handler.handler = handler;
// packet id 取随机数 1- 65536
client->packet_id = coap_client_random_packet_id_generate();
client->auth_token = NULL;
client->auth_token_len = 0;
client->retransmit_max = 1;
len = osal_snprintf(client->auth_uri, sizeof(client->auth_uri), "%s/%s/%s", device->product_id, device->device_name, QCLOUD_COAP_AUTH_URI);
if (len < 0 || len >= QCLOUD_COAP_AUTH_URI_MAX) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
}
qcloud_list_init(&client->message_list);
if ((client->message_list_lock = osal_mutex_create()) == NULL) {
goto errout;
}
if ((client->tx_lock = osal_mutex_create()) == NULL) {
goto errout;
}
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS);
errout:
if (client->message_list_lock) {
osal_mutex_destroy(client->message_list_lock);
}
if (client->tx_lock) {
osal_mutex_destroy(client->tx_lock);
}
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE)
}
__QCLOUD_API__ qcloud_err_t qcloud_coap_client_create(qcloud_coap_client_t *client,
qcloud_device_t *device,
coap_event_handler_fn_t handler)
{
QCLOUD_FUNC_ENTRY;
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
QCLOUD_POINTER_SANITY_CHECK(device, QCLOUD_ERR_INVAL);
memset(client, 0, sizeof(qcloud_coap_client_t));
QCLOUD_FUNC_EXIT_RC_IF_NOT(coap_client_network_init(&client->network, device), QCLOUD_ERR_SUCCESS, QCLOUD_ERR_FAILURE);
QCLOUD_FUNC_EXIT_RC_IF_NOT(coap_client_construct(client, device, handler), QCLOUD_ERR_SUCCESS, QCLOUD_ERR_FAILURE);
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS);
}
__QCLOUD_API__ qcloud_err_t qcloud_coap_client_connect(qcloud_coap_client_t *client)
{
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
int len;
qcloud_err_t rc;
char connection_id[QCLOUD_COAP_CONNECT_ID_MAX + 1];
QCLOUD_FUNC_EXIT_RC_IF_NOT(rc = client->network.connect(&client->network), QCLOUD_ERR_SUCCESS, rc);
coap_glue_connect_id_generate(connection_id);
len = osal_snprintf(client->auth_id, sizeof(client->auth_id), "%s;%s", QCLOUD_APPID, connection_id);
if (len < 0 || len >= QCLOUD_COAP_AUTH_ID_MAX) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
}
coap_auth(client, connection_id);
while (client->auth_state == QCLOUD_COAP_AUTH_STATE_NONE) {
qcloud_coap_client_yield(client, 200);
}
if (client->auth_state != QCLOUD_COAP_AUTH_STATE_SUCCESS) {
QCLOUD_LOG_I("auth failed");
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS);
}
__QCLOUD_API__ qcloud_err_t qcloud_coap_client_yield(qcloud_coap_client_t *client, uint32_t timeout_ms)
{
QCLOUD_FUNC_ENTRY;
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
return coap_glue_spin(client, timeout_ms);
}
__QCLOUD_API__ qcloud_err_t qcloud_coap_client_destroy(qcloud_coap_client_t *client)
{
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
if (client->network.is_connected && client->network.is_connected(&client->network)) {
client->network.disconnect(&client->network);
}
coap_glue_message_list_destroy(client);
osal_mutex_destroy(client->tx_lock);
osal_mutex_destroy(client->message_list_lock);
if (client->auth_token) {
osal_free(client->auth_token);
client->auth_token = NULL;
}
client->auth_token_len = 0;
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS);
}
__QCLOUD_API__ qcloud_err_t qcloud_coap_client_msg_send(qcloud_coap_client_t *client,
char *topic,
coap_send_opt_t *send_opt)
{
QCLOUD_FUNC_ENTRY
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
QCLOUD_POINTER_SANITY_CHECK(topic, QCLOUD_ERR_INVAL);
QCLOUD_POINTER_SANITY_CHECK(send_opt, QCLOUD_ERR_INVAL);
int len;
qcloud_err_t rc;
char message_token[8] = {0};
coap_message_t send_msg = COAP_MESSAGE_INITIALIZER;
if (strlen(topic) > QCLOUD_COAP_URI_MAX) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_MAX_TOPIC_LENGTH);
}
coap_message_init(&send_msg);
coap_message_type_set(&send_msg, COAP_MSG_TYPE_CON);
coap_message_code_set(&send_msg, COAP_CODE_CLASS_REQ, COAP_REQUEST_METHOD_POST);
coap_message_id_set(&send_msg, coap_glue_packet_id_generate(client));
len = coap_message_token_get(client, message_token);
coap_message_token_set(&send_msg, message_token, len);
send_msg.payload = (char *)osal_malloc(send_opt->payload_len);
if (!send_msg.payload) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
}
coap_message_payload_set(&send_msg, send_opt->payload, send_opt->payload_len);
coap_message_option_add(&send_msg, COAP_MSG_OPTION_CODE_URI_PATH, strlen(topic), topic);
coap_message_option_add(&send_msg, COAP_MSG_OPTION_CODE_AUTH_TOKEN, client->auth_token_len, client->auth_token);
if (send_opt->resp_cb) {
coap_message_option_add(&send_msg, COAP_MSG_OPTION_CODE_NEED_RESP, 1, "1");
coap_message_callback_set(&send_msg, send_opt->resp_cb);
} else {
coap_message_option_add(&send_msg, COAP_MSG_OPTION_CODE_NEED_RESP, 1, "0");
}
coap_message_context_set(&send_msg, send_opt->context);
rc = coap_glue_msg_send(client, &send_msg);
osal_free(send_msg.payload);
QCLOUD_FUNC_EXIT_RC(rc)
}
__QCLOUD_API__ uint16_t qcloud_coap_msg_id_get(coap_message_t *message)
{
QCLOUD_FUNC_ENTRY
if (!message) {
return COAP_MSG_ID_MAX;
}
return message->id;
}
__QCLOUD_API__ qcloud_err_t qcloud_coap_msg_payload_get(coap_message_t *message, char **payload, int *payload_len)
{
QCLOUD_FUNC_ENTRY
QCLOUD_POINTER_SANITY_CHECK(message, QCLOUD_ERR_INVAL);
QCLOUD_POINTER_SANITY_CHECK(payload, QCLOUD_ERR_INVAL);
QCLOUD_POINTER_SANITY_CHECK(payload_len, QCLOUD_ERR_INVAL);
if (message->code_class != COAP_CODE_CLASS_SUCCESS ||
message->code_detail != COAP_CODE_DETAIL_205_CONTENT) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE)
}
*payload = message->payload;
*payload_len = message->payload_len;
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS)
}
__QCLOUD_API__ coap_event_type_t qcloud_coap_event_type_get(coap_message_t *message)
{
QCLOUD_FUNC_ENTRY
QCLOUD_POINTER_SANITY_CHECK(message, COAP_EVENT_TYPE_UNAUTHORIZED);
switch (message->code_class) {
case COAP_CODE_CLASS_SUCCESS:
return COAP_EVENT_TYPE_RECEIVE_RESPCONTENT;
case COAP_CODE_CLASS_SERVER_ERR:
return COAP_EVENT_TYPE_INTERNAL_SERVER_ERROR;
case COAP_CODE_CLASS_INTERNAL_ERR:
return COAP_EVENT_TYPE_SEPRESP_TIMEOUT;
case COAP_CODE_CLASS_CLIENT_ERR:
if (message->code_detail == COAP_CODE_DETAIL_401_UNAUTHORIZED) {
return COAP_EVENT_TYPE_UNAUTHORIZED;
} else {
return COAP_EVENT_TYPE_FORBIDDEN;
}
default:
QCLOUD_LOG_E("not supported code class: %d", message->code_class);
return COAP_EVENT_TYPE_ACK_TIMEOUT;
}
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,276 @@
/*
* 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.h"
/**
* @brief Free an option structure that was allocated by coap_msg_op_new
*
* @param[in,out] op Pointer to the option structure
*/
__QCLOUD_STATIC__ void coap_message_option_destroy(coap_msg_option_t *option)
{
QCLOUD_FUNC_ENTRY
if (option->val) {
osal_free(option->val);
}
osal_free(option);
QCLOUD_FUNC_EXIT
}
/**
* @brief Deinitialise an option linked-list structure
*
* @param[in,out] list Pointer to an option linked-list structure
*/
__QCLOUD_STATIC__ void coap_message_option_list_destroy(coap_message_t *message)
{
QCLOUD_FUNC_ENTRY
QCLOUD_POINTER_SANITY_CHECK_RTN(message);
qcloud_list_t *curr, *next;
coap_msg_option_t *option;
if (qcloud_list_empty(&message->option_list)) {
QCLOUD_FUNC_EXIT;
}
QCLOUD_LIST_FOR_EACH_SAFE(curr, next, &message->option_list) {
option = QCLOUD_LIST_ENTRY(curr, coap_msg_option_t, list);
coap_message_option_destroy(option);
}
QCLOUD_FUNC_EXIT;
}
__QCLOUD_INTERNAL__ void coap_message_init(coap_message_t *message)
{
message->version = COAP_VERSION;
qcloud_list_init(&message->option_list);
}
__QCLOUD_INTERNAL__ int coap_message_token_get(qcloud_coap_client_t *client, char *buf)
{
uint32_t token;
token = client->message_token;
buf[0] = ((token & 0x00FF) >> 0);
buf[1] = ((token & 0xFF00) >> 8);
buf[2] = ((token & 0xFF0000) >> 16);
buf[3] = ((token & 0xFF000000) >> 24);
++client->message_token;
return sizeof(uint32_t);
}
__QCLOUD_INTERNAL__ qcloud_err_t coap_message_type_set(coap_message_t *message, uint8_t type)
{
QCLOUD_FUNC_ENTRY
message->type = type;
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS)
}
__QCLOUD_INTERNAL__ qcloud_err_t coap_message_code_set(coap_message_t *message, uint32_t code_class, uint32_t code_detail)
{
QCLOUD_FUNC_ENTRY
if (code_class > COAP_MSG_CODE_CLASS_MAX) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_INVAL)
}
if (code_detail > COAP_MSG_CODE_DETAIL_MAX) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_INVAL)
}
message->code_class = code_class;
message->code_detail = code_detail;
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS)
}
__QCLOUD_INTERNAL__ qcloud_err_t coap_message_id_set(coap_message_t *message, uint16_t id)
{
QCLOUD_FUNC_ENTRY
if (id > COAP_MSG_ID_MAX) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_INVAL)
}
message->id = id;
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS)
}
__QCLOUD_INTERNAL__ qcloud_err_t coap_message_token_set(coap_message_t *message, char *buf, uint8_t len)
{
QCLOUD_FUNC_ENTRY
if (len > COAP_MSG_TOKEN_MAX) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_INVAL)
}
memcpy(message->token, buf, len);
message->token_len = len;
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS)
}
__QCLOUD_INTERNAL__ qcloud_err_t coap_message_payload_set(coap_message_t *message, char *buf, size_t len)
{
QCLOUD_FUNC_ENTRY
if (len > 0 && !message->payload) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE)
}
message->payload_len = 0;
if (len > 0) {
memcpy(message->payload, buf, len);
message->payload_len = len;
}
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS)
}
__QCLOUD_INTERNAL__ coap_msg_option_t *coap_message_option_construct(uint16_t option_code, uint32_t len, const char *val)
{
QCLOUD_FUNC_ENTRY
char *this_val = NULL;
coap_msg_option_t *option = NULL;
option = (coap_msg_option_t *)osal_malloc(sizeof(coap_msg_option_t));
if (!option) {
QCLOUD_LOG_E("memory alloc failed");
return NULL;
}
this_val = (char *)osal_malloc(len);
if (!this_val) {
osal_free(option);
QCLOUD_LOG_E("memory alloc failed");
return NULL;
}
option->option_code = option_code;
option->val_len = len;
option->val = this_val;
memcpy(option->val, val, len);
qcloud_list_init(&option->list);
return option;
}
__QCLOUD_STATIC__ void coap_message_option_do_add(coap_message_t *message, coap_msg_option_t *option)
{
coap_msg_option_t *iter;
qcloud_list_t *curr, *option_list;
option_list = &message->option_list;
/* keep option_code in ascending order */
QCLOUD_LIST_FOR_EACH(curr, option_list) {
iter = QCLOUD_LIST_ENTRY(curr, coap_msg_option_t, list);
if (option->option_code <= iter->option_code) {
break;
}
}
qcloud_list_add_tail(&option->list, curr);
}
__QCLOUD_INTERNAL__ qcloud_err_t coap_message_option_add(coap_message_t *message, coap_msg_opt_code_t option_code, uint32_t len, const char *val)
{
QCLOUD_FUNC_ENTRY
QCLOUD_POINTER_SANITY_CHECK(message, QCLOUD_ERR_INVAL);
coap_msg_option_t *option = NULL;
option = coap_message_option_construct(option_code, len, val);
if (!option) {
QCLOUD_LOG_E("option alloc failed.");
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE)
}
coap_message_option_do_add(message, option);
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS)
}
__QCLOUD_INTERNAL__ qcloud_err_t coap_message_callback_set(coap_message_t *message, coap_resp_callback_t callback)
{
QCLOUD_FUNC_ENTRY
message->resp_cb = callback;
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS)
}
__QCLOUD_INTERNAL__ qcloud_err_t coap_message_context_set(coap_message_t *message, void *context)
{
QCLOUD_FUNC_ENTRY
message->context = context;
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS)
}
__QCLOUD_INTERNAL__ void coap_message_destroy(coap_message_t *message)
{
QCLOUD_FUNC_ENTRY
coap_message_option_list_destroy(message);
if (message->payload) {
osal_free(message->payload);
}
memset(message, 0, sizeof(coap_message_t));
QCLOUD_FUNC_EXIT
}
__QCLOUD_INTERNAL__ void coap_message_dump(coap_message_t* message)
{
QCLOUD_LOG_I("version = %u", message->version);
QCLOUD_LOG_I("type = %d", message->type);
QCLOUD_LOG_I("code_class = %u", message->code_class);
QCLOUD_LOG_I("code_detail = %u", message->code_detail);
QCLOUD_LOG_I("id = %d", message->id);
QCLOUD_LOG_I("payload_len = %d", message->payload_len);
QCLOUD_LOG_I("payload: %s", message->payload);
QCLOUD_LOG_I("token_len = %u", message->token_len);
QCLOUD_LOG_I("token: %s", message->token);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,368 @@
/*
* 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.h"
#define COAP_SWAP_UINT16(n) ((((uint16_t)(n) & 0xff00) >> 8) | (((uint16_t)(n) & 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
*/
__QCLOUD_STATIC__ qcloud_err_t coap_message_verify(coap_message_t *message)
{
QCLOUD_FUNC_ENTRY
if (COAP_MSG_IS_EMPTY(message)) {
/* empty message */
if (message->type == COAP_MSG_TYPE_NON ||
message->token_len != 0 ||
!qcloud_list_empty(&message->option_list) ||
message->payload_len != 0) {
QCLOUD_LOG_E("message option not empty");
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
}
/* non-empty message */
if (message->type == COAP_MSG_TYPE_RST) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_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
*/
__QCLOUD_STATIC__ qcloud_err_t coap_message_option_list_add(coap_message_t *message, uint16_t option_code, uint32_t len, const char *val)
{
QCLOUD_FUNC_ENTRY
coap_msg_option_t *option = NULL;
option = coap_message_option_construct(option_code, len, val);
if (!option) {
QCLOUD_LOG_E("allocate new option failed.");
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE)
}
qcloud_list_add_tail(&option->list, &message->option_list);
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_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
*/
__QCLOUD_STATIC__ int coap_message_deserialize_header(coap_message_t *message, char *buf, size_t len)
{
QCLOUD_FUNC_ENTRY
char *p = buf;
if (len < 4) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE);
}
message->version = (p[0] >> 6) & 0x03;
if (message->version != COAP_VERSION) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
}
message->type = (p[0] >> 4) & 0x03;
message->token_len = p[0] & 0x0f;
if (message->token_len > sizeof(message->token)) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
message->code_detail = p[1] & 0x1f;
message->code_class = (p[1] >> 5) & 0x07;
if (message->code_class != COAP_CODE_CLASS_REQ &&
message->code_class != COAP_CODE_CLASS_SUCCESS &&
message->code_class != COAP_CODE_CLASS_CLIENT_ERR &&
message->code_class != COAP_CODE_CLASS_SERVER_ERR) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_COAP_BADMSG)
}
message->id = COAP_SWAP_UINT16(*((uint16_t *)(&p[2])));
p += 4;
len -= 4;
QCLOUD_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
*/
__QCLOUD_STATIC__ int coap_message_deserialize_token(coap_message_t *message, char *buf, size_t len)
{
QCLOUD_FUNC_ENTRY
if (len < message->token_len) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
memcpy(message->token, buf, message->token_len);
QCLOUD_FUNC_EXIT_RC(message->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
*/
__QCLOUD_STATIC__ int coap_message_deserialize_option(coap_message_t *message, char *buf, size_t len)
{
QCLOUD_FUNC_ENTRY
char *p = buf;
qcloud_err_t rc;
uint16_t option_code_delta = 0, option_len = 0, option_code = 0;
if (len < 1) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
option_code_delta = (p[0] >> 4) & 0x0f;
option_len = p[0] & 0x0f;
if ((option_code_delta == 15) || (option_len == 15)) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
p++;
len--;
if (option_code_delta == 13) {
if (len < 1) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
option_code_delta += p[0];
p++;
len--;
} else if (option_code_delta == 14) {
if (len < 2) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
option_code_delta = 269 + COAP_SWAP_UINT16(*((uint16_t *)(&p[0])));
p += 2;
len -= 2;
}
if (option_len == 13) {
if (len < 1) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
option_len += p[0];
p++;
len--;
} else if (option_len == 14) {
if (len < 2) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
option_len = 269 + COAP_SWAP_UINT16(*((uint16_t *)(&p[0])));
p += 2;
len -= 2;
}
if (len < option_len) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
option_code += option_code_delta;
rc = coap_message_option_list_add(message, option_code, option_len, p);
QCLOUD_FUNC_EXIT_RC_IF_NOT(rc, QCLOUD_ERR_SUCCESS, -1);
p += option_len;
QCLOUD_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
*/
__QCLOUD_STATIC__ int coap_message_deserialize_options(coap_message_t *message, char *buf, size_t buf_len)
{
QCLOUD_FUNC_ENTRY
int len = 0;
char *p = buf;
while ((p[0] & 0xff) != 0xff && buf_len != 0) {
len = coap_message_deserialize_option(message, p, buf_len);
if (len < 0) {
return len;
}
p += len;
buf_len -= len;
}
QCLOUD_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
*/
__QCLOUD_STATIC__ int coap_message_deserialize_payload(coap_message_t *message, char *buf, size_t len)
{
QCLOUD_FUNC_ENTRY
char *p = buf;
if (len == 0) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS)
}
if ((p[0] & 0xff) != 0xff) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
p++;
len--;
if (len == 0) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_COAP_DATA_SIZE)
}
message->payload = (char *)osal_malloc(len);
if (!message->payload){
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_INVAL)
}
memcpy(message->payload, p, len);
message->payload_len = len;
p += len;
QCLOUD_FUNC_EXIT_RC(p - buf)
}
__QCLOUD_INTERNAL__ qcloud_err_t coap_message_deserialize(coap_message_t *message, char *buf, size_t buf_len)
{
QCLOUD_FUNC_ENTRY
int len = 0;
char *p = buf;
len = coap_message_deserialize_header(message, p, buf_len);
if (len < 0) {
QCLOUD_LOG_E("coap_message_deserialize_header failed, num:%lu", len);
goto errout;
}
p += len;
buf_len -= len;
len = coap_message_deserialize_token(message, p, buf_len);
if (len < 0) {
QCLOUD_LOG_E("coap_message_deserialize_token failed, num:%lu", len);
goto errout;
}
p += len;
buf_len -= len;
len = coap_message_deserialize_options(message, p, buf_len);
if (len < 0) {
QCLOUD_LOG_E("coap_message_deserialize_options failed, num:%lu", len);
goto errout;
}
p += len;
buf_len -= len;
len = coap_message_deserialize_payload(message, p, buf_len);
if (len < 0) {
QCLOUD_LOG_E("coap_message_deserialize_payload failed, num:%lu", len);
goto errout;
}
QCLOUD_FUNC_EXIT_RC(coap_message_verify(message))
errout:
coap_message_destroy(message);
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_COAP_INTERNAL)
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,489 @@
/*
* 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.h"
__QCLOUD_INTERNAL__ void coap_glue_connect_id_generate(char *conn_id)
{
int i = 0, flag;
srand((unsigned)osal_timer_current_sec());
for (i = 0; i < QCLOUD_COAP_CONNECT_ID_MAX - 1; ++i) {
flag = rand() % 3;
switch (flag) {
case 0:
conn_id[i] = (rand() % 26) + 'a';
break;
case 1:
conn_id[i] = (rand() % 26) + 'A';
break;
case 2:
conn_id[i] = (rand() % 10) + '0';
break;
}
}
conn_id[QCLOUD_COAP_CONNECT_ID_MAX - 1] = '\0';
}
__QCLOUD_INTERNAL__ uint16_t coap_glue_packet_id_generate(qcloud_coap_client_t *client)
{
#define PACKET_ID_MAX (65535)
uint16_t packet_id = client->packet_id;
client->packet_id = (packet_id == PACKET_ID_MAX ? 1 : (packet_id + 1));
return client->packet_id;
}
__QCLOUD_STATIC__ coap_event_type_t coap_glue_event_type_get(coap_message_t *message, coap_incoming_msg_type_t msg_type)
{
if (message->code_class == COAP_CODE_CLASS_SUCCESS &&
message->code_detail == COAP_CODE_DETAIL_205_CONTENT) {
if (msg_type == COAP_INCOMING_MSG_TYPE_RESP) {
return COAP_EVENT_TYPE_RECEIVE_RESPCONTENT;
} else {
return COAP_EVENT_TYPE_RECEIVE_ACK;
}
} else if (message->code_class == COAP_CODE_CLASS_CLIENT_ERR &&
message->code_detail == COAP_CODE_DETAIL_401_UNAUTHORIZED) {
return COAP_EVENT_TYPE_UNAUTHORIZED;
} else if (message->code_class == COAP_CODE_CLASS_CLIENT_ERR &&
message->code_detail == COAP_CODE_DETAIL_403_FORBIDDEN) {
return COAP_EVENT_TYPE_FORBIDDEN;
} else {
return COAP_EVENT_TYPE_INTERNAL_SERVER_ERROR;
}
}
__QCLOUD_STATIC__ void coap_glue_msg_sent_info_destroy(coap_msg_sent_info_t *msg_sent_info)
{
qcloud_list_del(&msg_sent_info->list);
osal_free(msg_sent_info->message);
osal_free(msg_sent_info);
}
__QCLOUD_INTERNAL__ qcloud_err_t coap_glue_message_list_destroy(qcloud_coap_client_t *client)
{
QCLOUD_FUNC_ENTRY;
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
qcloud_list_t *curr, *next;
coap_msg_sent_info_t *msg_sent_info = NULL;
if (qcloud_list_empty(&client->message_list)) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS);
}
osal_mutex_lock(client->message_list_lock);
QCLOUD_LIST_FOR_EACH_SAFE(curr, next, &client->message_list) {
msg_sent_info = QCLOUD_LIST_ENTRY(curr, coap_msg_sent_info_t, list);
coap_glue_msg_sent_info_destroy(msg_sent_info);
}
osal_mutex_unlock(client->message_list_lock);
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS);
}
__QCLOUD_STATIC__ qcloud_err_t coap_glue_message_list_scan(qcloud_coap_client_t *client)
{
QCLOUD_FUNC_ENTRY;
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
int ret;
size_t write_len;
qcloud_list_t *curr, *next;
coap_event_t event;
coap_message_t message = {0};
coap_msg_sent_info_t *msg_sent_info = NULL;
if (qcloud_list_empty(&client->message_list)) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS);
}
osal_mutex_lock(client->message_list_lock);
QCLOUD_LIST_FOR_EACH_SAFE(curr, next, &client->message_list) {
msg_sent_info = QCLOUD_LIST_ENTRY(curr, coap_msg_sent_info_t, list);
if (!osal_timer_is_expired(&msg_sent_info->timer)) {
continue;
}
if (msg_sent_info->transmit_count < client->retransmit_max &&
!msg_sent_info->is_acked) {
osal_timer_init(&msg_sent_info->timer);
osal_timer_countdown_ms(&msg_sent_info->timer, client->command_timeout);
++msg_sent_info->transmit_count;
ret = client->network.write(&client->network, msg_sent_info->message, msg_sent_info->message_len,
osal_timer_remain(&msg_sent_info->timer), &write_len);
if (ret == QCLOUD_ERR_SUCCESS) {
continue;
}
QCLOUD_LOG_E("retansmit the message id %d failed.", msg_sent_info->message_id);
} else if (msg_sent_info->resp_cb) {
message.type = COAP_MSG_TYPE_ACK;
message.context = msg_sent_info->context;
message.code_class = COAP_CODE_CLASS_INTERNAL_ERR;
message.code_detail = COAP_CODE_DETAIL_600_TIMEOUT;
message.id = msg_sent_info->message_id;
msg_sent_info->resp_cb(&message, msg_sent_info->context);
} else if (client->event_handler.handler) {
if (msg_sent_info->is_acked) {
event.type = COAP_EVENT_TYPE_SEPRESP_TIMEOUT;
} else {
event.type = COAP_EVENT_TYPE_ACK_TIMEOUT;
}
event.message = (void *)(&msg_sent_info->message_id);
client->event_handler.handler(client->event_handler.context, &event);
} else {
QCLOUD_LOG_E("response and event callback both null");
}
coap_glue_msg_sent_info_destroy(msg_sent_info);
}
osal_mutex_unlock(client->message_list_lock);
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS);
}
__QCLOUD_STATIC__ qcloud_err_t coap_glue_message_list_unrecord(qcloud_coap_client_t *client, coap_message_t *message, coap_incoming_msg_type_t msg_type)
{
QCLOUD_FUNC_ENTRY;
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
coap_event_t event;
coap_event_type_t event_type;
qcloud_list_t *curr, *next;
coap_msg_sent_info_t *msg_sent_info = NULL;
if (qcloud_list_empty(&client->message_list)) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
osal_mutex_lock(client->message_list_lock);
QCLOUD_LIST_FOR_EACH_SAFE(curr, next, &client->message_list) {
msg_sent_info = QCLOUD_LIST_ENTRY(curr, coap_msg_sent_info_t, list);
if (msg_type == COAP_INCOMING_MSG_TYPE_ACK &&
msg_sent_info->message_id == message->id) {
msg_sent_info->is_acked = QCLOUD_TRUE;
osal_timer_init(&msg_sent_info->timer);
osal_timer_countdown_ms(&msg_sent_info->timer, client->command_timeout);
}
if (msg_type == COAP_INCOMING_MSG_TYPE_RESP) {
if (msg_sent_info->token_len != 0 &&
msg_sent_info->token_len == message->token_len &&
memcmp(msg_sent_info->token, message->token, message->token_len) == 0) {
message->context = msg_sent_info->context;
if (msg_sent_info->resp_cb) {
msg_sent_info->resp_cb(message, msg_sent_info->context);
} else if (client->event_handler.handler) { // event handle process
event_type = coap_glue_event_type_get(message, COAP_INCOMING_MSG_TYPE_RESP);
event.type = event_type;
event.message = message;
message->id = msg_sent_info->message_id;
client->event_handler.handler(client->event_handler.context, &event);
} else {
QCLOUD_LOG_E("response and event callback both null");
}
coap_glue_msg_sent_info_destroy(msg_sent_info);
}
}
if (msg_type == COAP_INCOMING_MSG_TYPE_PIGGY) {
if (msg_sent_info->message_id == message->id) {
message->context = msg_sent_info->context;
if (msg_sent_info->resp_cb) {
msg_sent_info->resp_cb(message, msg_sent_info->context);
} else if (client->event_handler.handler) { // event handle process
event_type = coap_glue_event_type_get(message, COAP_INCOMING_MSG_TYPE_PIGGY);
event.type = event_type;
event.message = (void *)(&message->id);
client->event_handler.handler(client->event_handler.context, &event);
} else {
QCLOUD_LOG_E("response and event callback both null");
}
coap_glue_msg_sent_info_destroy(msg_sent_info);
}
}
}
osal_mutex_unlock(client->message_list_lock);
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS);
}
/**
* @brief 向服务器发送确认消息
*
* @param[in,out] client 指向客户端结构的指针
* @param[in] msg 指向消息结构的指针
*
* @returns Operation status
* @retval 0 Success
* @retval <0 Error
*/
__QCLOUD_STATIC__ qcloud_err_t coap_glue_resp_ack_send(qcloud_coap_client_t *client, uint16_t id)
{
QCLOUD_FUNC_ENTRY
qcloud_err_t rc;
coap_message_t ack_msg = COAP_MESSAGE_INITIALIZER;
coap_message_init(&ack_msg);
rc = coap_message_type_set(&ack_msg, COAP_MSG_TYPE_ACK);
if (rc != QCLOUD_ERR_SUCCESS) {
goto out;
}
rc = coap_message_id_set(&ack_msg, id);
if (rc != QCLOUD_ERR_SUCCESS) {
goto out;
}
rc = coap_glue_msg_send(client, &ack_msg);
out:
coap_message_destroy(&ack_msg);
QCLOUD_FUNC_EXIT_RC(rc)
}
__QCLOUD_STATIC__ qcloud_err_t coap_glue_piggy_message_handle(qcloud_coap_client_t *client, coap_message_t *message)
{
QCLOUD_FUNC_ENTRY
QCLOUD_FUNC_EXIT_RC(coap_glue_message_list_unrecord(client, message, COAP_INCOMING_MSG_TYPE_PIGGY));
}
__QCLOUD_STATIC__ qcloud_err_t coap_glue_ack_message_handle(qcloud_coap_client_t *client, coap_message_t *message)
{
QCLOUD_FUNC_ENTRY
QCLOUD_FUNC_EXIT_RC(coap_glue_message_list_unrecord(client, message, COAP_INCOMING_MSG_TYPE_ACK));
}
__QCLOUD_STATIC__ qcloud_err_t coap_glue_resp_message_handle(qcloud_coap_client_t *client, coap_message_t *message)
{
QCLOUD_FUNC_ENTRY
qcloud_err_t rc;
if (message->type == COAP_MSG_TYPE_CON) {
rc = coap_glue_resp_ack_send(client, message->id);
QCLOUD_LOG_D("send ack message for id: %d, rc: %d", message->id, rc);
}
QCLOUD_FUNC_EXIT_RC(coap_glue_message_list_unrecord(client, message, COAP_INCOMING_MSG_TYPE_RESP));
}
__QCLOUD_STATIC__ qcloud_err_t coap_glue_incoming_message_handle(qcloud_coap_client_t *client, uint8_t *buf, size_t buf_len)
{
QCLOUD_FUNC_ENTRY
qcloud_err_t rc = QCLOUD_ERR_SUCCESS;
coap_message_t incoming_msg;
memset(&incoming_msg, 0x00, sizeof(coap_message_t));
rc = coap_message_deserialize(&incoming_msg, (char *)buf, buf_len);
if (rc != QCLOUD_ERR_SUCCESS) {
QCLOUD_LOG_E("deserialize msg failed: %d", rc);
QCLOUD_FUNC_EXIT_RC(rc);
}
if (incoming_msg.type == COAP_MSG_TYPE_ACK && COAP_MSG_IS_EMPTY_ACK(&incoming_msg)) { // empty ACK
QCLOUD_LOG_D("receive ACK msg, id %d", incoming_msg.id);
coap_glue_ack_message_handle(client, &incoming_msg);
} else if (incoming_msg.type == COAP_MSG_TYPE_ACK && !COAP_MSG_IS_EMPTY(&incoming_msg)) { // piggy Response
QCLOUD_LOG_D("receive piggy ACK msg, id %d", incoming_msg.id);
coap_glue_piggy_message_handle(client, &incoming_msg);
} else if (incoming_msg.type == COAP_MSG_TYPE_CON && COAP_MSG_IS_EMPTY_RSP(&incoming_msg)) { // payload Response
QCLOUD_LOG_D("receive response msg, id: %d", incoming_msg.id);
coap_glue_resp_message_handle(client, &incoming_msg);
} else if (incoming_msg.type == COAP_MSG_TYPE_NON && COAP_MSG_IS_EMPTY_RSP(&incoming_msg)) { // payload Response
QCLOUD_LOG_D("receive response msg, id: %d", incoming_msg.id);
coap_glue_resp_message_handle(client, &incoming_msg);
} else {
QCLOUD_LOG_E("msg type not recgonized");
}
if (incoming_msg.payload) {
osal_free(incoming_msg.payload);
incoming_msg.payload_len = 0;
}
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS);
}
__QCLOUD_STATIC__ coap_msg_sent_info_t *coap_glue_message_sent_info_construct(qcloud_coap_client_t *client, coap_message_t *message, int len)
{
coap_msg_sent_info_t *msg_sent_info = NULL;
msg_sent_info = (coap_msg_sent_info_t *)osal_malloc(sizeof(coap_msg_sent_info_t));
if (!msg_sent_info) {
QCLOUD_LOG_E("memory alloc failed");
return NULL;
}
msg_sent_info->message = osal_malloc(len);
if (!msg_sent_info->message) {
QCLOUD_LOG_E("memory alloc failed");
osal_free(msg_sent_info);
return NULL;
}
msg_sent_info->is_acked = QCLOUD_FALSE;
msg_sent_info->context = message->context;
msg_sent_info->message_id = message->id;
msg_sent_info->resp_cb = message->resp_cb;
msg_sent_info->message_len = len;
msg_sent_info->token_len = message->token_len;
memcpy(msg_sent_info->token, message->token, message->token_len);
memcpy(msg_sent_info->message, client->tx_buffer, len);
if (message->type == COAP_MSG_TYPE_CON) {
msg_sent_info->transmit_count = 0;
osal_timer_init(&msg_sent_info->timer);
osal_timer_countdown_ms(&msg_sent_info->timer, client->command_timeout);
}
return msg_sent_info;
}
__QCLOUD_STATIC__ qcloud_err_t coap_glue_message_list_record(qcloud_coap_client_t *client, coap_message_t *message, int len)
{
QCLOUD_FUNC_ENTRY
coap_msg_sent_info_t *msg_sent_info = NULL;
msg_sent_info = coap_glue_message_sent_info_construct(client, message, len);
if (!msg_sent_info) {
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS)
}
osal_mutex_lock(client->message_list_lock);
qcloud_list_add(&msg_sent_info->list, &client->message_list);
osal_mutex_unlock(client->message_list_lock);
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS)
}
__QCLOUD_STATIC__ qcloud_err_t coap_glue_recv(qcloud_coap_client_t *client, uint32_t timeout_ms)
{
QCLOUD_FUNC_ENTRY
size_t read_len = 0;
qcloud_err_t rc;
rc = client->network.read(&client->network, client->rx_buffer, sizeof(client->rx_buffer), timeout_ms, &read_len);
switch (rc) {
case QCLOUD_ERR_SUCCESS:
rc = coap_glue_incoming_message_handle(client, client->rx_buffer, read_len);
break;
case QCLOUD_ERR_SSL_READ_TIMEOUT:
break;
default:
break;
}
QCLOUD_FUNC_EXIT_RC(rc)
}
__QCLOUD_INTERNAL__ qcloud_err_t coap_glue_spin(qcloud_coap_client_t *client, uint32_t timeout_ms)
{
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
qcloud_err_t rc;
rc = coap_glue_recv(client, timeout_ms);
if (rc != QCLOUD_ERR_SUCCESS && rc != QCLOUD_ERR_SSL_READ_TIMEOUT) {
QCLOUD_FUNC_EXIT_RC(rc)
}
QCLOUD_FUNC_EXIT_RC(coap_glue_message_list_scan(client));
}
__QCLOUD_INTERNAL__ qcloud_err_t coap_glue_msg_send(qcloud_coap_client_t *client, coap_message_t *message)
{
QCLOUD_FUNC_ENTRY
int len = 0;
qcloud_err_t rc;
size_t write_len = 0;
osal_mutex_lock(client->tx_lock);
len = coap_message_serialize(message, (char*)client->tx_buffer, sizeof(client->tx_buffer));
if (len < 0) {
QCLOUD_LOG_E("failed to serialize coap message");
osal_mutex_unlock(client->tx_lock);
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE)
}
rc = client->network.write(&client->network, client->tx_buffer, len, 0, &write_len);
if (rc != QCLOUD_ERR_SUCCESS) {
QCLOUD_LOG_E("coap net fail to write rc: %d", rc);
osal_mutex_unlock(client->tx_lock);
QCLOUD_FUNC_EXIT_RC(rc)
}
if (message->type == COAP_MSG_TYPE_CON &&
message->code_class == COAP_CODE_CLASS_REQ) {
rc = coap_glue_message_list_record(client, message, write_len);
QCLOUD_LOG_I("add message id: %d, rc: %d", message->id, rc);
} else {
QCLOUD_LOG_I("message donot need retransmit");
}
osal_mutex_unlock(client->tx_lock);
QCLOUD_FUNC_EXIT_RC(rc)
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,292 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 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.h"
/**
* @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
*/
__QCLOUD_STATIC__ int coap_message_serialize_header(coap_message_t *message, char *buf, size_t len)
{
QCLOUD_FUNC_ENTRY
if (len < 4) {
return -1;
}
buf[0] = (char)((COAP_VERSION << 6)
| ((message->type & 0x03) << 4)
| (message->token_len & 0x0f));
buf[1] = (char)(((message->code_class & 0x07) << 5)
| (message->code_detail & 0x1f));
buf[2] = (message->id & 0xFF00) >> 8;
buf[3] = (message->id & 0x00FF);
QCLOUD_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
*/
__QCLOUD_STATIC__ int coap_message_serialize_token(coap_message_t *message, char *buf, size_t len)
{
QCLOUD_FUNC_ENTRY
if (len < message->token_len) {
return -1;
}
memcpy(buf, message->token, message->token_len);
return 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
*/
__QCLOUD_STATIC__ int coap_message_option_format(coap_msg_option_t *option, uint16_t prev_option_code, char *buf, size_t buf_len)
{
QCLOUD_FUNC_ENTRY
char *p = NULL;
uint32_t len = 0;
uint16_t option_code_delta = 0;
p = buf;
option_code_delta = option->option_code - prev_option_code;
len++;
/* option delta */
if (option_code_delta >= 269) {
len += 2;
} else if (option_code_delta >= 13) {
len += 1;
}
/* option length */
if (option->val_len >= 269) {
len += 2;
} else if (option->option_code >= 13) {
len += 1;
}
/* option value */
len += option->val_len;
if (len > buf_len) {
return QCLOUD_ERR_COAP_DATA_SIZE;
}
/* option delta */
if (option_code_delta >= 269) {
p[0] = 14 << 4;
} else if (option_code_delta >= 13) {
p[0] = 13 << 4;
} else {
p[0] = option_code_delta << 4;
}
/* option length */
if (option->val_len >= 269) {
p[0] |= 14;
} else if (option->val_len >= 13) {
p[0] |= 13;
} else {
p[0] |= option->val_len;
}
p++;
buf_len--;
/* option delta extended */
if (option_code_delta >= 269) {
*p = (uint8_t)(((option_code_delta - 269) & 0xFF00) >> 8);
*(p + 1) = (uint8_t)(((option_code_delta - 269) & 0x00FF));
p += 2;
buf_len -= 2;
} else if (option_code_delta >= 13) {
p[0] = option_code_delta - 13;
p++;
buf_len--;
}
/* option length extended */
if (option->val_len >= 269) {
*p = (unsigned char)(((option->val_len - 269) & 0xFF00) >> 8);
*(p + 1) = (unsigned char)(((option->val_len - 269) & 0x00FF));
p += 2;
buf_len -= 2;
} else if (option->val_len >= 13) {
p[0] = option->val_len - 13;
p++;
buf_len--;
}
/* option value */
memcpy(p, option->val, option->val_len);
p += option->val_len;
return 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
*/
__QCLOUD_STATIC__ int coap_message_serialize_options(coap_message_t *message, char *buf, size_t buf_len)
{
QCLOUD_FUNC_ENTRY;
int len;
char *p = NULL;
uint16_t prev_option_code = 0;
qcloud_list_t *curr;
coap_msg_option_t *option;
p = buf;
QCLOUD_LIST_FOR_EACH(curr, &message->option_list) {
option = QCLOUD_LIST_ENTRY(curr, coap_msg_option_t, list);
// coap_message_option_destroy(option);
len = coap_message_option_format(option, prev_option_code, p, buf_len);
if (len < 0) {
return len;
}
p += len;
buf_len -= len;
prev_option_code = option->option_code;
}
return 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
*/
__QCLOUD_STATIC__ int coap_message_serialize_payload(coap_message_t *message, char *buf, size_t buf_len)
{
QCLOUD_FUNC_ENTRY;
if (message->payload_len == 0) {
return 0;
}
if (message->payload_len + 1 > buf_len) {
return -1;
}
buf[0] = 0xff;
memcpy(&buf[1], message->payload, message->payload_len);
return message->payload_len + 1;
}
__QCLOUD_INTERNAL__ int coap_message_serialize(coap_message_t *message, char *buf, size_t buf_len)
{
QCLOUD_FUNC_ENTRY;
int len = 0;
char *p = buf;
if (!message || !buf) {
return -1;
}
len = coap_message_serialize_header(message, p, buf_len);
if (len < 0) {
QCLOUD_LOG_E("serialize header fail len: %lu", len);
return -1;
}
p += len;
buf_len -= len;
len = coap_message_serialize_token(message, p, buf_len);
if (len < 0) {
QCLOUD_LOG_E("erialize token fail len: %lu", len);
return -1;
}
p += len;
buf_len -= len;
len = coap_message_serialize_options(message, p, buf_len);
if (len < 0) {
QCLOUD_LOG_E("serialize options fail len: %lu", len);
return -1;
}
p += len;
buf_len -= len;
len = coap_message_serialize_payload(message, p, buf_len);
if (len < 0) {
QCLOUD_LOG_E("coap_message_serialize_payload fail num=%lu", len);
return -1;
}
p += len;
return p - buf;
}
#ifdef __cplusplus
}
#endif