123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498 |
- /*
- * Tencent is pleased to support the open source community by making IoT Hub
- available.
- * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights
- reserved.
- * Licensed under the MIT License (the "License"); you may not use this file
- except in
- * compliance with the License. You may obtain a copy of the License at
- * http://opensource.org/licenses/MIT
- * Unless required by applicable law or agreed to in writing, software
- distributed under the License is
- * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND,
- * either express or implied. See the License for the specific language
- governing permissions and
- * limitations under the License.
- *
- */
- #include <ctype.h>
- #include <stdbool.h>
- #include <stdint.h>
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
- #ifdef __cplusplus
- extern "C" {
- #endif
- #include "lite-utils.h"
- #include "log_upload.h"
- #include "mqtt_client.h"
- #include "qcloud_iot_ca.h"
- #include "qcloud_iot_common.h"
- #include "qcloud_iot_device.h"
- #include "qcloud_iot_export.h"
- #include "qcloud_iot_import.h"
- #include "utils_base64.h"
- #include "utils_list.h"
- static uint16_t _get_random_start_packet_id(void)
- {
- srand((unsigned)HAL_GetTimeMs());
- return rand() % 65536 + 1;
- }
- // currently return a constant value
- int IOT_MQTT_GetErrCode(void)
- {
- return QCLOUD_ERR_FAILURE;
- }
- void *IOT_MQTT_Construct(MQTTInitParams *pParams)
- {
- POINTER_SANITY_CHECK(pParams, NULL);
- STRING_PTR_SANITY_CHECK(pParams->product_id, NULL);
- STRING_PTR_SANITY_CHECK(pParams->device_name, NULL);
- Qcloud_IoT_Client *mqtt_client = NULL;
- char *client_id = NULL;
- // create and init MQTTClient
- if ((mqtt_client = (Qcloud_IoT_Client *)HAL_Malloc(sizeof(Qcloud_IoT_Client))) == NULL) {
- Log_e("malloc MQTTClient failed");
- return NULL;
- }
- int rc = qcloud_iot_mqtt_init(mqtt_client, pParams);
- if (rc != QCLOUD_RET_SUCCESS) {
- Log_e("mqtt init failed: %d", rc);
- HAL_Free(mqtt_client);
- return NULL;
- }
- MQTTConnectParams connect_params = DEFAULT_MQTTCONNECT_PARAMS;
- client_id = HAL_Malloc(MAX_SIZE_OF_CLIENT_ID + 1);
- if (client_id == NULL) {
- Log_e("malloc client_id failed");
- HAL_Free(mqtt_client);
- return NULL;
- }
- memset(client_id, 0, MAX_SIZE_OF_CLIENT_ID + 1);
- HAL_Snprintf(client_id, MAX_SIZE_OF_CLIENT_ID, "%s%s", pParams->product_id, pParams->device_name);
- connect_params.client_id = client_id;
- // Upper limit of keep alive interval is (11.5 * 60) seconds
- connect_params.keep_alive_interval = Min(pParams->keep_alive_interval_ms / 1000, 690);
- connect_params.clean_session = pParams->clean_session;
- connect_params.auto_connect_enable = pParams->auto_connect_enable;
- #if defined(AUTH_WITH_NOTLS) && defined(AUTH_MODE_KEY)
- if (pParams->device_secret == NULL) {
- Log_e("Device secret is null!");
- qcloud_iot_mqtt_fini(mqtt_client);
- HAL_Free(mqtt_client);
- HAL_Free(client_id);
- return NULL;
- }
- size_t src_len = strlen(pParams->device_secret);
- size_t len;
- memset(mqtt_client->psk_decode, 0x00, DECODE_PSK_LENGTH);
- rc = qcloud_iot_utils_base64decode(mqtt_client->psk_decode, DECODE_PSK_LENGTH, &len,\
- (unsigned char *)pParams->device_secret, src_len);
- connect_params.device_secret = (char *)mqtt_client->psk_decode;
- connect_params.device_secret_len = len;
- if (rc != QCLOUD_RET_SUCCESS) {
- Log_e("Device secret decode err, secret:%s", pParams->device_secret);
- qcloud_iot_mqtt_fini(mqtt_client);
- HAL_Free(mqtt_client);
- HAL_Free(client_id);
- return NULL;
- }
- #endif
- rc = qcloud_iot_mqtt_connect(mqtt_client, &connect_params);
- if (rc != QCLOUD_RET_SUCCESS) {
- Log_e("mqtt connect with id: %s failed: %d", mqtt_client->options.conn_id, rc);
- qcloud_iot_mqtt_fini(mqtt_client);
- HAL_Free(mqtt_client);
- HAL_Free(client_id);
- return NULL;
- } else {
- Log_i("mqtt connect with id: %s success", mqtt_client->options.conn_id);
- }
- #ifdef LOG_UPLOAD
- // log subscribe topics
- if (is_log_uploader_init()) {
- set_log_mqtt_client((void *)mqtt_client);
- int log_level;
- rc = qcloud_get_log_level(&log_level);
- if (rc < 0) {
- Log_e("client get log topic failed: %d", rc);
- }
- IOT_Log_Upload(true);
- }
- #endif
- return mqtt_client;
- }
- int IOT_MQTT_Destroy(void **pClient)
- {
- POINTER_SANITY_CHECK(*pClient, QCLOUD_ERR_INVAL);
- Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)(*pClient);
- int rc = qcloud_iot_mqtt_disconnect(mqtt_client);
- // disconnect network stack by force
- if (rc != QCLOUD_RET_SUCCESS) {
- mqtt_client->network_stack.disconnect(&(mqtt_client->network_stack));
- set_client_conn_state(mqtt_client, NOTCONNECTED);
- }
- int i = 0;
- for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
- /* notify this event to topic subscriber */
- if (NULL != mqtt_client->sub_handles[i].topic_filter && NULL != mqtt_client->sub_handles[i].sub_event_handler)
- mqtt_client->sub_handles[i].sub_event_handler(mqtt_client, MQTT_EVENT_CLIENT_DESTROY,
- mqtt_client->sub_handles[i].handler_user_data);
- if (NULL != mqtt_client->sub_handles[i].topic_filter) {
- HAL_Free((void *)mqtt_client->sub_handles[i].topic_filter);
- mqtt_client->sub_handles[i].topic_filter = NULL;
- }
- }
- #ifdef MQTT_RMDUP_MSG_ENABLED
- reset_repeat_packet_id_buffer(mqtt_client);
- #endif
- HAL_MutexDestroy(mqtt_client->lock_generic);
- HAL_MutexDestroy(mqtt_client->lock_write_buf);
- HAL_MutexDestroy(mqtt_client->lock_list_sub);
- HAL_MutexDestroy(mqtt_client->lock_list_pub);
- list_destroy(mqtt_client->list_pub_wait_ack);
- list_destroy(mqtt_client->list_sub_wait_ack);
- HAL_Free(mqtt_client->options.client_id);
- HAL_Free(*pClient);
- *pClient = NULL;
- #ifdef LOG_UPLOAD
- set_log_mqtt_client(NULL);
- #endif
- Log_i("mqtt release!");
- return rc;
- }
- int IOT_MQTT_Yield(void *pClient, uint32_t timeout_ms)
- {
- Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
- int rc = qcloud_iot_mqtt_yield(mqtt_client, timeout_ms);
- #ifdef LOG_UPLOAD
- /* do instant log uploading if MQTT communication error */
- if (rc == QCLOUD_RET_SUCCESS)
- IOT_Log_Upload(false);
- else
- IOT_Log_Upload(true);
- #endif
- return rc;
- }
- int IOT_MQTT_Yield_MT(void *pClient, uint32_t timeout_ms)
- {
- Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
- int rc = qcloud_iot_mqtt_yield_mt(mqtt_client, timeout_ms);
- #ifdef LOG_UPLOAD
- /* do instant log uploading if MQTT communication error */
- if (rc == QCLOUD_RET_SUCCESS)
- IOT_Log_Upload(false);
- else
- IOT_Log_Upload(true);
- #endif
- return rc;
- }
- #ifdef MULTITHREAD_ENABLED
- void IOT_MQTT_Set_Yield_Thread_State(void *pClient, bool state)
- {
- Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
- mqtt_client->yield_thread_running = state;
- }
- #endif
- int IOT_MQTT_Publish(void *pClient, char *topicName, PublishParams *pParams)
- {
- Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
- return qcloud_iot_mqtt_publish(mqtt_client, topicName, pParams);
- }
- int IOT_MQTT_Subscribe(void *pClient, char *topicFilter, SubscribeParams *pParams)
- {
- Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
- return qcloud_iot_mqtt_subscribe(mqtt_client, topicFilter, pParams);
- }
- int IOT_MQTT_Unsubscribe(void *pClient, char *topicFilter)
- {
- Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
- return qcloud_iot_mqtt_unsubscribe(mqtt_client, topicFilter);
- }
- bool IOT_MQTT_IsSubReady(void *pClient, char *topicFilter)
- {
- Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
- return qcloud_iot_mqtt_is_sub_ready(mqtt_client, topicFilter);
- }
- bool IOT_MQTT_IsConnected(void *pClient)
- {
- IOT_FUNC_ENTRY;
- POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
- Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
- IOT_FUNC_EXIT_RC(get_client_conn_state(mqtt_client) == 1)
- }
- int qcloud_iot_mqtt_init(Qcloud_IoT_Client *pClient, MQTTInitParams *pParams)
- {
- IOT_FUNC_ENTRY;
- POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
- POINTER_SANITY_CHECK(pParams, QCLOUD_ERR_INVAL);
- memset(pClient, 0x0, sizeof(Qcloud_IoT_Client));
- int size = HAL_Snprintf(pClient->host_addr, HOST_STR_LENGTH, "%s.%s", pParams->product_id,
- iot_get_mqtt_domain(pParams->region));
- if (size < 0 || size > HOST_STR_LENGTH - 1) {
- IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
- }
- int i = 0;
- for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
- pClient->sub_handles[i].topic_filter = NULL;
- pClient->sub_handles[i].message_handler = NULL;
- pClient->sub_handles[i].sub_event_handler = NULL;
- pClient->sub_handles[i].qos = QOS0;
- pClient->sub_handles[i].handler_user_data = NULL;
- }
- if (pParams->command_timeout < MIN_COMMAND_TIMEOUT)
- pParams->command_timeout = MIN_COMMAND_TIMEOUT;
- if (pParams->command_timeout > MAX_COMMAND_TIMEOUT)
- pParams->command_timeout = MAX_COMMAND_TIMEOUT;
- pClient->command_timeout_ms = pParams->command_timeout;
- // packet id, random from [1 - 65536]
- pClient->next_packet_id = _get_random_start_packet_id();
- pClient->write_buf_size = QCLOUD_IOT_MQTT_TX_BUF_LEN;
- pClient->read_buf_size = QCLOUD_IOT_MQTT_RX_BUF_LEN;
- pClient->is_ping_outstanding = 0;
- pClient->was_manually_disconnected = 0;
- pClient->counter_network_disconnected = 0;
- #ifdef MULTITHREAD_ENABLED
- pClient->yield_thread_running = false;
- #endif
- pClient->event_handle = pParams->event_handle;
- pClient->lock_generic = HAL_MutexCreate();
- if (NULL == pClient->lock_generic) {
- IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
- }
- set_client_conn_state(pClient, NOTCONNECTED);
- if ((pClient->lock_write_buf = HAL_MutexCreate()) == NULL) {
- Log_e("create write buf lock failed.");
- goto error;
- }
- if ((pClient->lock_list_sub = HAL_MutexCreate()) == NULL) {
- Log_e("create sub list lock failed.");
- goto error;
- }
- if ((pClient->lock_list_pub = HAL_MutexCreate()) == NULL) {
- Log_e("create pub list lock failed.");
- goto error;
- }
- if ((pClient->list_pub_wait_ack = list_new()) == NULL) {
- Log_e("create pub wait list failed.");
- goto error;
- }
- pClient->list_pub_wait_ack->free = HAL_Free;
- if ((pClient->list_sub_wait_ack = list_new()) == NULL) {
- Log_e("create sub wait list failed.");
- goto error;
- }
- pClient->list_sub_wait_ack->free = HAL_Free;
- #ifndef AUTH_WITH_NOTLS// device param for TLS connection
- #ifdef AUTH_MODE_CERT
- strncpy(pClient->cert_file_path, pParams->cert_file, FILE_PATH_MAX_LEN - 1);
- strncpy(pClient->key_file_path, pParams->key_file, FILE_PATH_MAX_LEN - 1);
- pClient->network_stack.ssl_connect_params.cert_file = pClient->cert_file_path;
- pClient->network_stack.ssl_connect_params.key_file = pClient->key_file_path;
- pClient->network_stack.ssl_connect_params.ca_crt = iot_ca_get();
- pClient->network_stack.ssl_connect_params.ca_crt_len = strlen(pClient->network_stack.ssl_connect_params.ca_crt);
- #else
- if (pParams->device_secret != NULL) {
- size_t src_len = strlen(pParams->device_secret);
- size_t len;
- memset(pClient->psk_decode, 0x00, DECODE_PSK_LENGTH);
- qcloud_iot_utils_base64decode(pClient->psk_decode, DECODE_PSK_LENGTH, &len,
- (unsigned char *)pParams->device_secret, src_len);
- pClient->network_stack.ssl_connect_params.psk = (char *)pClient->psk_decode;
- pClient->network_stack.ssl_connect_params.psk_length = len;
- } else {
- Log_e("psk is empty!");
- IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
- }
- memset( pClient->network_stack.ssl_connect_params.psk_id, 0, MAX_SIZE_OF_CLIENT_ID);
- HAL_Snprintf( pClient->network_stack.ssl_connect_params.psk_id, MAX_SIZE_OF_CLIENT_ID, \
- "%s%s", pParams->product_id, pParams->device_name);
- pClient->network_stack.ssl_connect_params.ca_crt = NULL;
- pClient->network_stack.ssl_connect_params.ca_crt_len = 0;
- #endif
- pClient->network_stack.host = pClient->host_addr;
- pClient->network_stack.port = MQTT_SERVER_PORT_TLS;
- pClient->network_stack.ssl_connect_params.timeout_ms =
- (pClient->command_timeout_ms > QCLOUD_IOT_TLS_HANDSHAKE_TIMEOUT) ? pClient->command_timeout_ms
- : QCLOUD_IOT_TLS_HANDSHAKE_TIMEOUT;
- #else
- pClient->network_stack.host = pClient->host_addr;
- pClient->network_stack.port = MQTT_SERVER_PORT_NOTLS;
- #endif
- // init network stack
- qcloud_iot_mqtt_network_init(pParams->profile_idx, &(pClient->network_stack));
- // ping timer and reconnect delay timer
- InitTimer(&(pClient->ping_timer));
- InitTimer(&(pClient->reconnect_delay_timer));
- IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
- error:
- if (pClient->list_pub_wait_ack) {
- pClient->list_pub_wait_ack->free(pClient->list_pub_wait_ack);
- pClient->list_pub_wait_ack = NULL;
- }
- if (pClient->list_sub_wait_ack) {
- pClient->list_sub_wait_ack->free(pClient->list_sub_wait_ack);
- pClient->list_sub_wait_ack = NULL;
- }
- if (pClient->lock_generic) {
- HAL_MutexDestroy(pClient->lock_generic);
- pClient->lock_generic = NULL;
- }
- if (pClient->lock_list_sub) {
- HAL_MutexDestroy(pClient->lock_list_sub);
- pClient->lock_list_sub = NULL;
- }
- if (pClient->lock_list_pub) {
- HAL_MutexDestroy(pClient->lock_list_pub);
- pClient->lock_list_pub = NULL;
- }
- if (pClient->lock_write_buf) {
- HAL_MutexDestroy(pClient->lock_write_buf);
- pClient->lock_write_buf = NULL;
- }
- IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE)
- }
- int qcloud_iot_mqtt_fini(Qcloud_IoT_Client *mqtt_client)
- {
- IOT_FUNC_ENTRY;
- POINTER_SANITY_CHECK(mqtt_client, QCLOUD_ERR_INVAL);
- HAL_MutexDestroy(mqtt_client->lock_generic);
- HAL_MutexDestroy(mqtt_client->lock_write_buf);
- HAL_MutexDestroy(mqtt_client->lock_list_sub);
- HAL_MutexDestroy(mqtt_client->lock_list_pub);
- list_destroy(mqtt_client->list_pub_wait_ack);
- list_destroy(mqtt_client->list_sub_wait_ack);
- Log_i("release mqtt client resources");
- IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
- }
- int qcloud_iot_mqtt_set_autoreconnect(Qcloud_IoT_Client *pClient, bool value)
- {
- IOT_FUNC_ENTRY;
- POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
- pClient->options.auto_connect_enable = (uint8_t)value;
- IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
- }
- bool qcloud_iot_mqtt_is_autoreconnect_enabled(Qcloud_IoT_Client *pClient)
- {
- IOT_FUNC_ENTRY;
- POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
- bool is_enabled = false;
- if (pClient->options.auto_connect_enable == 1) {
- is_enabled = true;
- }
- IOT_FUNC_EXIT_RC(is_enabled);
- }
- int qcloud_iot_mqtt_get_network_disconnected_count(Qcloud_IoT_Client *pClient)
- {
- IOT_FUNC_ENTRY;
- POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
- IOT_FUNC_EXIT_RC(pClient->counter_network_disconnected);
- }
- int qcloud_iot_mqtt_reset_network_disconnected_count(Qcloud_IoT_Client *pClient)
- {
- IOT_FUNC_ENTRY;
- POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
- pClient->counter_network_disconnected = 0;
- IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
- }
- #ifdef __cplusplus
- }
- #endif
|