diff --git a/include/mqtt5_client.h b/include/mqtt5_client.h index 25b27c8..780e492 100644 --- a/include/mqtt5_client.h +++ b/include/mqtt5_client.h @@ -8,6 +8,7 @@ #define _MQTT5_CLIENT_H_ #include "mqtt_client.h" +#include "mqtt_common.h" #ifdef __cplusplus extern "C" { @@ -77,11 +78,6 @@ typedef enum mqtt5_reason_code_t { */ typedef __attribute__((deprecated)) esp_mqtt5_reason_code_t esp_mqtt5_error_reason_code_t; -/** - * MQTT5 user property handle - */ -typedef struct mqtt5_user_property_list_t *mqtt5_user_property_handle_t; - /** * MQTT5 protocol connect properties and will properties configuration, more details refer to MQTT5 protocol document section 3.1.2.11 and 3.3.2.3 */ @@ -106,58 +102,6 @@ typedef struct { will_user_property; /*!< The handle for will message user property, call function esp_mqtt5_client_set_user_property to set it */ } esp_mqtt5_connection_property_config_t; -/** - * MQTT5 protocol publish properties configuration, more details refer to MQTT5 protocol document section 3.3.2.3 - */ -typedef struct { - bool payload_format_indicator; /*!< This value is to indicator publish message payload format */ - uint32_t message_expiry_interval; /*!< The time interval that message expiry */ - uint16_t topic_alias; /*!< An integer value to identify the topic instead of using topic name string */ - const char *response_topic; /*!< Topic name for a response message */ - const char *correlation_data; /*!< Binary data for receiver to match the response message */ - uint16_t correlation_data_len; /*!< The length of correlation data */ - const char - *content_type; /*!< This value is to indicator publish message content type, use a MIME content type string */ - mqtt5_user_property_handle_t - user_property; /*!< The handle for user property, call function esp_mqtt5_client_set_user_property to set it */ -} esp_mqtt5_publish_property_config_t; - -/** - * MQTT5 protocol subscribe properties configuration, more details refer to MQTT5 protocol document section 3.8.2.1 - */ -typedef struct { - uint16_t subscribe_id; /*!< A variable byte represents the identifier of the subscription */ - bool no_local_flag; /*!< Subscription Option to allow that server publish message that client sent */ - bool retain_as_published_flag; /*!< Subscription Option to keep the retain flag as published option */ - uint8_t retain_handle; /*!< Subscription Option to handle retain option */ - bool is_share_subscribe; /*!< Whether subscribe is a shared subscription */ - const char - *share_name; /*!< The name of shared subscription which is a part of $share/{share_name}/{topic} */ - mqtt5_user_property_handle_t - user_property; /*!< The handle for user property, call function esp_mqtt5_client_set_user_property to set it */ -} esp_mqtt5_subscribe_property_config_t; - -/** - * MQTT5 protocol unsubscribe properties configuration, more details refer to MQTT5 protocol document section 3.10.2.1 - */ -typedef struct { - bool is_share_subscribe; /*!< Whether subscribe is a shared subscription */ - const char - *share_name; /*!< The name of shared subscription which is a part of $share/{share_name}/{topic} */ - mqtt5_user_property_handle_t - user_property; /*!< The handle for user property, call function esp_mqtt5_client_set_user_property to set it */ -} esp_mqtt5_unsubscribe_property_config_t; - -/** - * MQTT5 protocol disconnect properties configuration, more details refer to MQTT5 protocol document section 3.14.2.2 - */ -typedef struct { - uint32_t session_expiry_interval; /*!< The interval time of session expiry */ - uint8_t disconnect_reason; /*!< The reason that connection disconnect, refer to mqtt5_error_reason_code */ - mqtt5_user_property_handle_t - user_property; /*!< The handle for user property, call function esp_mqtt5_client_set_user_property to set it */ -} esp_mqtt5_disconnect_property_config_t; - /** * MQTT5 server response properties from CONNACK (section 3.2.2.3) * @@ -194,14 +138,6 @@ typedef struct { esp_mqtt5_server_resp_property_t server; /*!< Server response properties from CONNACK (valid only in MQTT_EVENT_CONNECTED) */ } esp_mqtt5_event_property_t; -/** - * MQTT5 protocol for user property - */ -typedef struct { - const char *key; /*!< Item key name */ - const char *value; /*!< Item value string */ -} esp_mqtt5_user_property_item_t; - /** * @brief Set MQTT5 client connect property configuration * diff --git a/include/mqtt_client.h b/include/mqtt_client.h index 4f740ba..0fc1c45 100644 --- a/include/mqtt_client.h +++ b/include/mqtt_client.h @@ -18,6 +18,7 @@ #include "esp_err.h" #include "esp_event.h" #include "esp_transport.h" +#include "mqtt_common.h" #ifdef CONFIG_MQTT_PROTOCOL_5 #include "mqtt5_client.h" #endif @@ -28,11 +29,6 @@ extern "C" { typedef struct esp_mqtt_client *esp_mqtt_client_handle_t; -#define MQTT_OVER_TCP_SCHEME "mqtt" -#define MQTT_OVER_SSL_SCHEME "mqtts" -#define MQTT_OVER_WS_SCHEME "ws" -#define MQTT_OVER_WSS_SCHEME "wss" - /** * @brief *MQTT* event types. * @@ -152,16 +148,6 @@ typedef enum esp_mqtt_transport_t { ``wss`` */ } esp_mqtt_transport_t; -/** - * *MQTT* protocol version used for connection - */ -typedef enum esp_mqtt_protocol_ver_t { - MQTT_PROTOCOL_UNDEFINED = 0, - MQTT_PROTOCOL_V_3_1, - MQTT_PROTOCOL_V_3_1_1, - MQTT_PROTOCOL_V_5, -} esp_mqtt_protocol_ver_t; - /** * States of MQTT client connection */ @@ -408,14 +394,6 @@ typedef struct esp_mqtt_client_config_t { } outbox; /*!< Outbox configuration. */ } esp_mqtt_client_config_t; -/** - * Topic definition struct - */ -typedef struct topic_t { - const char *filter; /*!< Topic filter to subscribe */ - int qos; /*!< Max QoS level of the subscription */ -} esp_mqtt_topic_t; - /** * @brief Creates *MQTT* client handle based on the configuration * diff --git a/include/mqtt_common.h b/include/mqtt_common.h new file mode 100644 index 0000000..aa2c0c7 --- /dev/null +++ b/include/mqtt_common.h @@ -0,0 +1,99 @@ +/* + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MQTT_OVER_TCP_SCHEME "mqtt" +#define MQTT_OVER_SSL_SCHEME "mqtts" +#define MQTT_OVER_WS_SCHEME "ws" +#define MQTT_OVER_WSS_SCHEME "wss" + +/** + * *MQTT* protocol version used for connection + */ +typedef enum esp_mqtt_protocol_ver_t { + MQTT_PROTOCOL_UNDEFINED = 0, + MQTT_PROTOCOL_V_3_1, + MQTT_PROTOCOL_V_3_1_1, + MQTT_PROTOCOL_V_5, +} esp_mqtt_protocol_ver_t; + +/** + * Topic definition struct + */ +typedef struct topic_t { + const char *filter; /*!< Topic filter to subscribe */ + int qos; /*!< Max QoS level of the subscription */ +} esp_mqtt_topic_t; + +/** + * MQTT5 user property handle + */ +typedef struct mqtt5_user_property_list_t *mqtt5_user_property_handle_t; + +/** + * MQTT5 protocol for user property + */ +typedef struct { + const char *key; /*!< Item key name */ + const char *value; /*!< Item value string */ +} esp_mqtt5_user_property_item_t; + +/** + * MQTT5 protocol publish properties configuration, more details refer to MQTT5 protocol document section 3.3.2.3 + */ +typedef struct { + bool payload_format_indicator; /*!< This value is to indicator publish message payload format */ + uint32_t message_expiry_interval; /*!< The time interval that message expiry */ + uint16_t topic_alias; /*!< An integer value to identify the topic instead of using topic name string */ + const char *response_topic; /*!< Topic name for a response message */ + const char *correlation_data; /*!< Binary data for receiver to match the response message */ + uint16_t correlation_data_len; /*!< The length of correlation data */ + const char *content_type; /*!< This value is to indicator publish message content type, use a MIME content type string */ + mqtt5_user_property_handle_t user_property; /*!< The handle for user property, call function esp_mqtt5_client_set_user_property to set it */ +} esp_mqtt5_publish_property_config_t; + +/** + * MQTT5 protocol subscribe properties configuration, more details refer to MQTT5 protocol document section 3.8.2.1 + */ +typedef struct { + uint16_t subscribe_id; /*!< A variable byte represents the identifier of the subscription */ + bool no_local_flag; /*!< Subscription Option to allow that server publish message that client sent */ + bool retain_as_published_flag; /*!< Subscription Option to keep the retain flag as published option */ + uint8_t retain_handle; /*!< Subscription Option to handle retain option */ + bool is_share_subscribe; /*!< Whether subscribe is a shared subscription */ + const char *share_name; /*!< The name of shared subscription which is a part of $share/{share_name}/{topic} */ + mqtt5_user_property_handle_t user_property; /*!< The handle for user property, call function esp_mqtt5_client_set_user_property to set it */ +} esp_mqtt5_subscribe_property_config_t; + +/** + * MQTT5 protocol disconnect properties configuration, more details refer to MQTT5 protocol document section 3.14.2.2 + */ +typedef struct { + uint32_t session_expiry_interval; /*!< The interval time of session expiry */ + uint8_t disconnect_reason; /*!< The reason that connection disconnect, refer to mqtt5_error_reason_code */ + mqtt5_user_property_handle_t user_property; /*!< The handle for user property, call function esp_mqtt5_client_set_user_property to set it */ +} esp_mqtt5_disconnect_property_config_t; + +/** + * MQTT5 protocol unsubscribe properties configuration, more details refer to MQTT5 protocol document section 3.10.2.1 + */ +typedef struct { + bool is_share_subscribe; /*!< Whether subscribe is a shared subscription */ + const char *share_name; /*!< The name of shared subscription which is a part of $share/{share_name}/{topic} */ + mqtt5_user_property_handle_t user_property; /*!< The handle for user property, call function esp_mqtt5_client_set_user_property to set it */ +} esp_mqtt5_unsubscribe_property_config_t; + +#ifdef __cplusplus +} +#endif diff --git a/lib/include/mqtt5_client_priv.h b/lib/include/mqtt5_client_priv.h index c8bcc2a..6cd805f 100644 --- a/lib/include/mqtt5_client_priv.h +++ b/lib/include/mqtt5_client_priv.h @@ -16,13 +16,6 @@ extern "C" { #endif -typedef struct mqtt5_topic_alias { - char *topic; - uint16_t topic_len; - uint16_t topic_alias; - STAILQ_ENTRY(mqtt5_topic_alias) next; -} mqtt5_topic_alias_t; -STAILQ_HEAD(mqtt5_topic_alias_list_t, mqtt5_topic_alias); typedef struct mqtt5_topic_alias_list_t *mqtt5_topic_alias_handle_t; typedef struct mqtt5_topic_alias *mqtt5_topic_alias_item_t; diff --git a/lib/include/mqtt5_msg.h b/lib/include/mqtt5_msg.h index 75bc599..1a03d55 100644 --- a/lib/include/mqtt5_msg.h +++ b/lib/include/mqtt5_msg.h @@ -7,10 +7,8 @@ #define MQTT5_MSG_H #include #include -#include "sys/queue.h" -#include "mqtt_config.h" #include "mqtt_msg.h" -#include "mqtt_client.h" +#include "mqtt_common.h" #ifdef __cplusplus extern "C" { #endif @@ -45,12 +43,6 @@ enum mqtt_properties_type { MQTT5_PROPERTY_SHARED_SUBSCR_AVAILABLE = 0x2A, }; -typedef struct mqtt5_user_property { - char *key; - char *value; - STAILQ_ENTRY(mqtt5_user_property) next; -} mqtt5_user_property_t; -STAILQ_HEAD(mqtt5_user_property_list_t, mqtt5_user_property); typedef struct mqtt5_user_property *mqtt5_user_property_item_t; typedef struct { @@ -141,6 +133,16 @@ mqtt_message_t *mqtt5_msg_pubrel(mqtt_message_t *message, uint16_t message_id); mqtt_message_t *mqtt5_msg_pubrec(mqtt_message_t *message, uint16_t message_id); mqtt_message_t *mqtt5_msg_puback(mqtt_message_t *message, uint16_t message_id); +mqtt5_user_property_handle_t mqtt5_msg_create_user_property_list(void); +esp_err_t mqtt5_msg_set_user_property(mqtt5_user_property_handle_t *user_property_list, const char *key, size_t key_len, + const char *value, size_t value_len); +void mqtt5_msg_delete_user_property(mqtt5_user_property_handle_t user_property_list); +esp_err_t mqtt5_msg_get_user_property(mqtt5_user_property_handle_t user_property_list, + esp_mqtt5_user_property_item_t *item, uint8_t *item_num); +uint8_t mqtt5_msg_get_user_property_count(mqtt5_user_property_handle_t user_property_list); +esp_err_t mqtt5_msg_copy_user_property(mqtt5_user_property_handle_t user_property_new, + const struct mqtt5_user_property_list_t *user_property_old); + #ifdef __cplusplus } #endif diff --git a/lib/include/mqtt_client_priv.h b/lib/include/mqtt_client_priv.h index 72420ac..1f0e6e9 100644 --- a/lib/include/mqtt_client_priv.h +++ b/lib/include/mqtt_client_priv.h @@ -15,6 +15,7 @@ #include "platform.h" #include "esp_event.h" +#include "mqtt_config.h" #include "mqtt_client.h" #include "mqtt_msg.h" #ifdef MQTT_PROTOCOL_5 diff --git a/lib/include/mqtt_msg.h b/lib/include/mqtt_msg.h index b4ce7e6..065c07d 100644 --- a/lib/include/mqtt_msg.h +++ b/lib/include/mqtt_msg.h @@ -8,9 +8,10 @@ #define MQTT_MSG_H #include #include +#include +#include "esp_err.h" +#include "mqtt_common.h" -#include "mqtt_config.h" -#include "mqtt_client.h" #ifdef __cplusplus extern "C" { #endif diff --git a/lib/mqtt5_msg.c b/lib/mqtt5_msg.c index 53b5d88..1262b84 100644 --- a/lib/mqtt5_msg.c +++ b/lib/mqtt5_msg.c @@ -5,11 +5,11 @@ */ #include #include "mqtt5_msg.h" -#include "mqtt_client.h" -#include "mqtt_config.h" +#include "esp_err.h" +#include "mqtt_common.h" #include "platform.h" #include "esp_log.h" -#include "mqtt_client_priv.h" +#include "sys/queue.h" #define MQTT5_MAX_FIXED_HEADER_SIZE 5 #define MQTT5_MAX_PROPERTY_STRING_LEN (16 * 1024) @@ -32,6 +32,13 @@ static const char *TAG = "mqtt5_msg"; #define MQTT5_CONVERT_TWO_BYTE(i, a) i = (a >> 8) & 0xff; \ i = a & 0xff; +typedef struct mqtt5_user_property { + char *key; + char *value; + STAILQ_ENTRY(mqtt5_user_property) next; +} mqtt5_user_property_t; +STAILQ_HEAD(mqtt5_user_property_list_t, mqtt5_user_property); + enum mqtt5_connect_flag { MQTT5_CONNECT_FLAG_USERNAME = 1 << 7, MQTT5_CONNECT_FLAG_PASSWORD = 1 << 6, @@ -234,13 +241,12 @@ static mqtt_message_t *fini_message(mqtt_message_t *message, int type, int dup, return message; } -static esp_err_t mqtt5_msg_set_user_property(mqtt5_user_property_handle_t *user_property, char *key, size_t key_len, - char *value, size_t value_len) +esp_err_t mqtt5_msg_set_user_property(mqtt5_user_property_handle_t *user_property_list, const char *key, size_t key_len, + const char *value, size_t value_len) { - if (!*user_property) { - *user_property = calloc(1, sizeof(struct mqtt5_user_property_list_t)); - ESP_MEM_CHECK(TAG, *user_property, return ESP_FAIL); - STAILQ_INIT(*user_property); + if (!*user_property_list) { + *user_property_list = mqtt5_msg_create_user_property_list(); + ESP_MEM_CHECK(TAG, *user_property_list, return ESP_FAIL); } mqtt5_user_property_item_t user_property_item = calloc(1, sizeof(mqtt5_user_property_t)); @@ -260,13 +266,13 @@ static esp_err_t mqtt5_msg_set_user_property(mqtt5_user_property_handle_t *user_ }); memcpy(user_property_item->value, value, value_len); user_property_item->value[value_len] = '\0'; - STAILQ_INSERT_TAIL(*user_property, user_property_item, next); + STAILQ_INSERT_TAIL(*user_property_list, user_property_item, next); return ESP_OK; } -static mqtt5_user_property_handle_t mqtt5_msg_get_user_property(uint8_t *buffer, size_t buffer_length) +static mqtt5_user_property_handle_t mqtt5_msg_parse_user_property(uint8_t *buffer, size_t buffer_length) { - mqtt5_user_property_handle_t user_porperty = NULL; + mqtt5_user_property_handle_t user_property = NULL; uint8_t *property = buffer; uint16_t property_offset = 0, len = 0; @@ -327,8 +333,7 @@ static mqtt5_user_property_handle_t mqtt5_msg_get_user_property(uint8_t *buffer, #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" - if (mqtt5_msg_set_user_property(&user_porperty, (char *)key, key_len, (char *)value, value_len) != ESP_OK) { -#pragma GCC diagnostic pop + if (mqtt5_msg_set_user_property(&user_property, (char *)key, key_len, (char *)value, value_len) != ESP_OK) { ESP_LOGE(TAG, "mqtt5_msg_set_user_property fail"); goto err; } @@ -342,9 +347,9 @@ static mqtt5_user_property_handle_t mqtt5_msg_get_user_property(uint8_t *buffer, } } - return user_porperty; + return user_property; err: - esp_mqtt5_client_delete_user_property(user_porperty); + mqtt5_msg_delete_user_property(user_property); return NULL; } @@ -562,7 +567,7 @@ char *mqtt5_get_publish_property_payload(uint8_t *buffer, size_t buffer_length, property_offset += len; if (mqtt5_msg_set_user_property(user_property, (char *)key, key_len, (char *)value, value_len) != ESP_OK) { - esp_mqtt5_client_delete_user_property(*user_property); + mqtt5_msg_delete_user_property(*user_property); *user_property = NULL; ESP_LOGE(TAG, "mqtt5_msg_set_user_property fail"); return NULL; @@ -613,7 +618,7 @@ char *mqtt5_get_suback_data(uint8_t *buffer, size_t *length, mqtt5_user_property if (*user_property) { ESP_LOGE(TAG, "user_property not freed before mqtt5_get_suback_data"); - esp_mqtt5_client_delete_user_property(*user_property); + mqtt5_msg_delete_user_property(*user_property); *user_property = NULL; } @@ -637,16 +642,11 @@ char *mqtt5_get_suback_data(uint8_t *buffer, size_t *length, mqtt5_user_property return NULL; } - /* False positive: the previous *user_property value is freed above if non-NULL. - * The analyzer cannot track the deallocation across the TU boundary. */ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" - *user_property = mqtt5_msg_get_user_property(buffer + offset, property_len); -#pragma GCC diagnostic pop + *user_property = mqtt5_msg_parse_user_property(buffer + offset, property_len); offset += property_len; if (offset >= totlen) { - esp_mqtt5_client_delete_user_property(*user_property); + mqtt5_msg_delete_user_property(*user_property); *user_property = NULL; *length = 0; return NULL; @@ -667,7 +667,7 @@ char *mqtt5_get_puback_data(uint8_t *buffer, size_t *length, mqtt5_user_property if (*user_property) { ESP_LOGE(TAG, "user_property not freed before mqtt5_get_puback_data"); - esp_mqtt5_client_delete_user_property(*user_property); + mqtt5_msg_delete_user_property(*user_property); *user_property = NULL; } @@ -689,12 +689,7 @@ char *mqtt5_get_puback_data(uint8_t *buffer, size_t *length, mqtt5_user_property return NULL; } - /* False positive: the previous *user_property value is freed above if non-NULL. - * The analyzer cannot track the deallocation across the TU boundary. */ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" - *user_property = mqtt5_msg_get_user_property(buffer + offset, property_len); -#pragma GCC diagnostic pop + *user_property = mqtt5_msg_parse_user_property(buffer + offset, property_len); } return data; @@ -1006,7 +1001,7 @@ esp_err_t mqtt5_msg_parse_connack_property(uint8_t *buffer, size_t buffer_len, m property_offset += len; if (mqtt5_msg_set_user_property(user_property, (char *)key, key_len, (char *)value, value_len) != ESP_OK) { - esp_mqtt5_client_delete_user_property(*user_property); + mqtt5_msg_delete_user_property(*user_property); *user_property = NULL; ESP_LOGE(TAG, "mqtt5_msg_set_user_property fail"); return ESP_FAIL; @@ -1543,3 +1538,112 @@ mqtt_message_t *mqtt5_msg_pubcomp(mqtt_message_t *message, uint16_t message_id) properties_offset), fail_message(message)); return fini_message(message, MQTT_MSG_TYPE_PUBCOMP, 0, 0, 0); } + +void mqtt5_msg_delete_user_property(mqtt5_user_property_handle_t user_property_list) +{ + if (user_property_list) { + mqtt5_user_property_item_t item; + mqtt5_user_property_item_t tmp; + STAILQ_FOREACH_SAFE(item, user_property_list, next, tmp) { + STAILQ_REMOVE(user_property_list, item, mqtt5_user_property, next); + free(item->key); + free(item->value); + free(item); + } + } + + free(user_property_list); +} + +mqtt5_user_property_handle_t mqtt5_msg_create_user_property_list(void) +{ + mqtt5_user_property_handle_t user_property = calloc(1, sizeof(struct mqtt5_user_property_list_t)); + ESP_MEM_CHECK(TAG, user_property, return NULL); + STAILQ_INIT(user_property); + return user_property; +} + +uint8_t mqtt5_msg_get_user_property_count(mqtt5_user_property_handle_t user_property_list) +{ + uint8_t count = 0; + mqtt5_user_property_item_t item; + STAILQ_FOREACH(item, user_property_list, next) { + count ++; + } + return count; +} + +static void mqtt5_msg_free_user_property_result(esp_mqtt5_user_property_item_t *item) +{ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" + free((void *)item->key); + free((void *)item->value); +#pragma GCC diagnostic pop + item->key = NULL; + item->value = NULL; +} + +esp_err_t mqtt5_msg_get_user_property(mqtt5_user_property_handle_t user_property_list, + esp_mqtt5_user_property_item_t *item, uint8_t *item_num) +{ + int property_item_idx = 0; + int j = 0; + mqtt5_user_property_item_t user_property_item; + uint8_t num = *item_num; + STAILQ_FOREACH(user_property_item, user_property_list, next) { + if (property_item_idx < num) { + size_t item_key_len = strlen(user_property_item->key); + size_t item_value_len = strlen(user_property_item->value); + char *key = calloc(1, item_key_len + 1); + ESP_MEM_CHECK(TAG, key, goto err); + memcpy(key, user_property_item->key, item_key_len); + key[item_key_len] = '\0'; + char *value = calloc(1, item_value_len + 1); + ESP_MEM_CHECK(TAG, value, { + free(key); + goto err; + }); + memcpy(value, user_property_item->value, item_value_len); + value[item_value_len] = '\0'; + item[property_item_idx].key = key; + item[property_item_idx].value = value; + property_item_idx ++; + } else { + break; + } + } + *item_num = property_item_idx; + return ESP_OK; +err: + + for (j = 0; j < property_item_idx; j ++) { + mqtt5_msg_free_user_property_result(&item[j]); + } + + return ESP_ERR_NO_MEM; +} + +esp_err_t mqtt5_msg_copy_user_property(mqtt5_user_property_handle_t user_property_new, + const struct mqtt5_user_property_list_t *user_property_old) +{ + mqtt5_user_property_item_t old_item; + mqtt5_user_property_item_t new_item; + STAILQ_FOREACH(old_item, user_property_old, next) { + new_item = calloc(1, sizeof(mqtt5_user_property_t)); + ESP_MEM_CHECK(TAG, new_item, return ESP_FAIL); + new_item->key = strdup(old_item->key); + ESP_MEM_CHECK(TAG, new_item->key, { + free(new_item); + return ESP_FAIL; + }); + new_item->value = strdup(old_item->value); + ESP_MEM_CHECK(TAG, new_item->value, { + free(new_item->key); + free(new_item); + return ESP_FAIL; + }); + STAILQ_INSERT_TAIL(user_property_new, new_item, next); + } + return ESP_OK; +} diff --git a/lib/mqtt_msg.c b/lib/mqtt_msg.c index 8a8560d..199e928 100644 --- a/lib/mqtt_msg.c +++ b/lib/mqtt_msg.c @@ -5,7 +5,6 @@ */ #include #include "esp_heap_caps.h" -#include "mqtt_client.h" #include "mqtt_msg.h" #include "mqtt_config.h" #include "platform.h" diff --git a/mqtt5_client.c b/mqtt5_client.c index 59a0d39..6334748 100644 --- a/mqtt5_client.c +++ b/mqtt5_client.c @@ -4,15 +4,29 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "esp_err.h" +#include "mqtt_config.h" +#include "mqtt_client.h" #include "mqtt_client_priv.h" +#include "mqtt5_client.h" +#include "mqtt5_msg.h" #include "esp_log.h" #include +#include static const char *TAG = "mqtt5_client"; // Receive Maximum is optional in CONNACK; when absent the limit is 65535 #define MQTT5_DEFAULT_RECEIVE_MAXIMUM 65535 +typedef struct mqtt5_topic_alias { + char *topic; + uint16_t topic_len; + uint16_t topic_alias; + STAILQ_ENTRY(mqtt5_topic_alias) next; +} mqtt5_topic_alias_t; +STAILQ_HEAD(mqtt5_topic_alias_list_t, mqtt5_topic_alias); + static void esp_mqtt5_print_error_code(esp_mqtt5_client_handle_t client, int code); static esp_err_t esp_mqtt5_client_update_topic_alias(mqtt5_topic_alias_handle_t topic_alias_handle, uint16_t topic_alias, char *topic, size_t topic_len); @@ -505,25 +519,7 @@ static esp_err_t esp_mqtt5_user_property_copy(mqtt5_user_property_handle_t user_ ESP_LOGE(TAG, "Input is NULL"); return ESP_FAIL; } - - mqtt5_user_property_item_t old_item, new_item; - STAILQ_FOREACH(old_item, user_property_old, next) { - new_item = calloc(1, sizeof(mqtt5_user_property_t)); - ESP_MEM_CHECK(TAG, new_item, return ESP_FAIL); - new_item->key = strdup(old_item->key); - ESP_MEM_CHECK(TAG, new_item->key, { - free(new_item); - return ESP_FAIL; - }); - new_item->value = strdup(old_item->value); - ESP_MEM_CHECK(TAG, new_item->value, { - free(new_item->key); - free(new_item); - return ESP_FAIL; - }); - STAILQ_INSERT_TAIL(user_property_new, new_item, next); - } - return ESP_OK; + return mqtt5_msg_copy_user_property(user_property_new, user_property_old); } esp_err_t esp_mqtt5_client_set_publish_property(esp_mqtt5_client_handle_t client, @@ -688,17 +684,11 @@ esp_err_t esp_mqtt5_client_set_disconnect_property(esp_mqtt5_client_handle_t cli if (property->user_property) { esp_mqtt5_client_delete_user_property(client->mqtt5_config->disconnect_property_info.user_property); - /* False positive: the allocation remains owned by disconnect_property_info - * until it is replaced or the MQTT 5 configuration is destroyed. */ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" - client->mqtt5_config->disconnect_property_info.user_property = calloc(1, sizeof(struct mqtt5_user_property_list_t)); + client->mqtt5_config->disconnect_property_info.user_property = mqtt5_msg_create_user_property_list(); ESP_MEM_CHECK(TAG, client->mqtt5_config->disconnect_property_info.user_property, { MQTT_API_UNLOCK(client); return ESP_ERR_NO_MEM; }); -#pragma GCC diagnostic pop - STAILQ_INIT(client->mqtt5_config->disconnect_property_info.user_property); if (esp_mqtt5_user_property_copy(client->mqtt5_config->disconnect_property_info.user_property, property->user_property) != ESP_OK) { @@ -772,9 +762,8 @@ esp_err_t esp_mqtt5_client_set_connect_property(esp_mqtt5_client_handle_t client if (connect_property->user_property) { esp_mqtt5_client_delete_user_property(client->mqtt5_config->connect_property_info.user_property); - client->mqtt5_config->connect_property_info.user_property = calloc(1, sizeof(struct mqtt5_user_property_list_t)); + client->mqtt5_config->connect_property_info.user_property = mqtt5_msg_create_user_property_list(); ESP_MEM_CHECK(TAG, client->mqtt5_config->connect_property_info.user_property, goto _mqtt_set_config_failed); - STAILQ_INIT(client->mqtt5_config->connect_property_info.user_property); if (esp_mqtt5_user_property_copy(client->mqtt5_config->connect_property_info.user_property, connect_property->user_property) != ESP_OK) { @@ -817,14 +806,8 @@ esp_err_t esp_mqtt5_client_set_connect_property(esp_mqtt5_client_handle_t client if (connect_property->will_user_property) { esp_mqtt5_client_delete_user_property(client->mqtt5_config->will_property_info.user_property); - /* False positive: esp_mqtt_destroy_config() releases this allocation on failure, - * but the analyzer cannot follow that cleanup across the translation-unit boundary. */ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" - client->mqtt5_config->will_property_info.user_property = calloc(1, sizeof(struct mqtt5_user_property_list_t)); + client->mqtt5_config->will_property_info.user_property = mqtt5_msg_create_user_property_list(); ESP_MEM_CHECK(TAG, client->mqtt5_config->will_property_info.user_property, goto _mqtt_set_config_failed); -#pragma GCC diagnostic pop - STAILQ_INIT(client->mqtt5_config->will_property_info.user_property); if (esp_mqtt5_user_property_copy(client->mqtt5_config->will_property_info.user_property, connect_property->will_user_property) != ESP_OK) { @@ -842,7 +825,7 @@ _mqtt_set_config_failed: return ESP_ERR_NO_MEM; } -esp_err_t esp_mqtt5_client_set_user_property(mqtt5_user_property_handle_t *user_property, +esp_err_t esp_mqtt5_client_set_user_property(mqtt5_user_property_handle_t *user_property_list, esp_mqtt5_user_property_item_t item[], uint8_t item_num) { if (!item_num || !item) { @@ -850,124 +833,46 @@ esp_err_t esp_mqtt5_client_set_user_property(mqtt5_user_property_handle_t *user_ return ESP_FAIL; } - if (!*user_property) { - *user_property = calloc(1, sizeof(struct mqtt5_user_property_list_t)); - ESP_MEM_CHECK(TAG, *user_property, return ESP_ERR_NO_MEM); - STAILQ_INIT(*user_property); - } - for (int i = 0; i < item_num; i ++) { if (item[i].key && item[i].value) { - mqtt5_user_property_item_t user_property_item = calloc(1, sizeof(mqtt5_user_property_t)); - ESP_MEM_CHECK(TAG, user_property_item, goto err); size_t key_len = strlen(item[i].key); size_t value_len = strlen(item[i].value); - user_property_item->key = calloc(1, key_len + 1); - ESP_MEM_CHECK(TAG, user_property_item->key, { - free(user_property_item); - goto err; - }); - memcpy(user_property_item->key, item[i].key, key_len); - user_property_item->key[key_len] = '\0'; - user_property_item->value = calloc(1, value_len + 1); - ESP_MEM_CHECK(TAG, user_property_item->value, { - free(user_property_item->key); - free(user_property_item); - goto err; - }); - memcpy(user_property_item->value, item[i].value, value_len); - user_property_item->value[value_len] = '\0'; - STAILQ_INSERT_TAIL(*user_property, user_property_item, next); + esp_err_t ret = mqtt5_msg_set_user_property(user_property_list, item[i].key, key_len, item[i].value, + value_len); + + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to set user property"); + esp_mqtt5_client_delete_user_property(*user_property_list); + *user_property_list = NULL; + return ret; + } } } return ESP_OK; -err: - esp_mqtt5_client_delete_user_property(*user_property); - *user_property = NULL; - return ESP_ERR_NO_MEM; } esp_err_t esp_mqtt5_client_get_user_property(mqtt5_user_property_handle_t user_property, esp_mqtt5_user_property_item_t *item, uint8_t *item_num) { - int i = 0, j = 0; - - if (user_property && item && *item_num) { - mqtt5_user_property_item_t user_property_item; - uint8_t num = *item_num; - STAILQ_FOREACH(user_property_item, user_property, next) { - if (i < num) { - size_t item_key_len = strlen(user_property_item->key); - size_t item_value_len = strlen(user_property_item->value); - char *key = calloc(1, item_key_len + 1); - ESP_MEM_CHECK(TAG, key, goto err); - memcpy(key, user_property_item->key, item_key_len); - key[item_key_len] = '\0'; - char *value = calloc(1, item_value_len + 1); - ESP_MEM_CHECK(TAG, value, { - free(key); - goto err; - }); - memcpy(value, user_property_item->value, item_value_len); - value[item_value_len] = '\0'; - item[i].key = key; - item[i].value = value; - i ++; - } else { - break; - } - } - *item_num = i; - return ESP_OK; - } else { + if (!user_property || !item || !item_num || !*item_num) { ESP_LOGE(TAG, "Input value is NULL or item_num is 0"); return ESP_FAIL; } -err: -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" - - for (j = 0; j < i; j ++) { - if (item[j].key) { - free((char *)item[j].key); - } - - if (item[j].value) { - free((char *)item[j].value); - } - } - -#pragma GCC diagnostic pop - return ESP_ERR_NO_MEM; + return mqtt5_msg_get_user_property(user_property, item, item_num); } uint8_t esp_mqtt5_client_get_user_property_count(mqtt5_user_property_handle_t user_property) { - uint8_t count = 0; - - if (user_property) { - mqtt5_user_property_item_t item; - STAILQ_FOREACH(item, user_property, next) { - count ++; - } + if (!user_property) { + return 0; } - return count; + return mqtt5_msg_get_user_property_count(user_property); } -void esp_mqtt5_client_delete_user_property(mqtt5_user_property_handle_t user_property) +void esp_mqtt5_client_delete_user_property(mqtt5_user_property_handle_t user_property_list) { - if (user_property) { - mqtt5_user_property_item_t item, tmp; - STAILQ_FOREACH_SAFE(item, user_property, next, tmp) { - STAILQ_REMOVE(user_property, item, mqtt5_user_property, next); - free(item->key); - free(item->value); - free(item); - } - } - - free(user_property); + mqtt5_msg_delete_user_property(user_property_list); } diff --git a/mqtt_client.c b/mqtt_client.c index 657cc17..1e6d503 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -10,6 +10,7 @@ #include "esp_log.h" #include "esp_heap_caps.h" #include "esp_transport.h" +#include "mqtt_config.h" #include "mqtt_client.h" #include "mqtt_client_priv.h" #include "mqtt_msg.h"