From 67042a1315c63cf0415f2eb19dca16df1372a6e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Cabral?= Date: Fri, 1 Mar 2019 18:20:53 +0000 Subject: [PATCH 1/2] ADD: Get the response code from a failing connection. This commit adds an event information "connect_return_code" that is written when the client state is MQTT_STATE_INIT, and the connection fails. This event info can then be written by the user app to find out the reason of the fail connection. Merges https://github.com/espressif/esp-mqtt/pull/100 --- include/mqtt_client.h | 16 +++++++++++++++- lib/include/mqtt_msg.h | 9 --------- mqtt_client.c | 30 ++++++++++++++++++------------ 3 files changed, 33 insertions(+), 22 deletions(-) diff --git a/include/mqtt_client.h b/include/mqtt_client.h index b29255e..d08c555 100644 --- a/include/mqtt_client.h +++ b/include/mqtt_client.h @@ -37,7 +37,7 @@ typedef struct esp_mqtt_client *esp_mqtt_client_handle_t; * */ typedef enum { - MQTT_EVENT_ERROR = 0, + MQTT_EVENT_ERROR = 0, /*!< on error event, additional context: error handle from esp_tls (if supported) */ MQTT_EVENT_CONNECTED, /*!< connected event, additional context: session_present flag */ MQTT_EVENT_DISCONNECTED, /*!< disconnected event */ MQTT_EVENT_SUBSCRIBED, /*!< subscribed event, additional context: msg_id */ @@ -57,8 +57,21 @@ typedef enum { and current data offset updating. */ MQTT_EVENT_BEFORE_CONNECT, /*!< The event occurs before connecting */ + MQTT_EVENT_CONNECTION_REFUSED, /*!< The event occurs if connection is refused by the broker, additional context: connect_return_code */ } esp_mqtt_event_id_t; +/** + * MQTT connection error codes propagated via ERROR event + */ +typedef enum { + MQTT_CONNECTION_ACCEPTED = 0, /*!< Connection accepted */ + MQTT_CONNECTION_REFUSE_PROTOCOL, /*!< MQTT connection refused reason: Wrong protocol */ + MQTT_CONNECTION_REFUSE_ID_REJECTED, /*!< MQTT connection refused reason: ID rejected */ + MQTT_CONNECTION_REFUSE_SERVER_UNAVAILABLE, /*!< MQTT connection refused reason: Server unavailable */ + MQTT_CONNECTION_REFUSE_BAD_USERNAME, /*!< MQTT connection refused reason: Wrong user */ + MQTT_CONNECTION_REFUSE_NOT_AUTHORIZED /*!< MQTT connection refused reason: Wrong username or password */ +} esp_mqtt_connect_return_code_t; + typedef enum { MQTT_TRANSPORT_UNKNOWN = 0x0, MQTT_TRANSPORT_OVER_TCP, /*!< MQTT over TCP, using scheme: ``mqtt`` */ @@ -83,6 +96,7 @@ typedef struct { int msg_id; /*!< MQTT messaged id of message */ int session_present; /*!< MQTT session_present flag for connection event */ void* error_handle; /*!< esp-tls error handle referencing last error/flags captured in transports */ + esp_mqtt_connect_return_code_t connect_return_code; /*!< MQTT connection return code. Only written on a connection */ } esp_mqtt_event_t; typedef esp_mqtt_event_t *esp_mqtt_event_handle_t; diff --git a/lib/include/mqtt_msg.h b/lib/include/mqtt_msg.h index 80ab72f..470f4c4 100644 --- a/lib/include/mqtt_msg.h +++ b/lib/include/mqtt_msg.h @@ -57,15 +57,6 @@ enum mqtt_message_type { MQTT_MSG_TYPE_DISCONNECT = 14 }; -enum mqtt_connect_return_code { - CONNECTION_ACCEPTED = 0, - CONNECTION_REFUSE_PROTOCOL, - CONNECTION_REFUSE_ID_REJECTED, - CONNECTION_REFUSE_SERVER_UNAVAILABLE, - CONNECTION_REFUSE_BAD_USERNAME, - CONNECTION_REFUSE_NOT_AUTHORIZED -}; - typedef struct mqtt_message { uint8_t *data; uint32_t length; diff --git a/mqtt_client.c b/mqtt_client.c index f359766..e7ccc2c 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -317,27 +317,33 @@ static esp_err_t esp_mqtt_connect(esp_mqtt_client_handle_t client, int timeout_m } client->mqtt_state.in_buffer_read_len = 0; connect_rsp_code = mqtt_get_connect_return_code(client->mqtt_state.in_buffer); - switch (connect_rsp_code) { - case CONNECTION_ACCEPTED: + if (connect_rsp_code == MQTT_CONNECTION_ACCEPTED) { ESP_LOGD(TAG, "Connected"); return ESP_OK; - case CONNECTION_REFUSE_PROTOCOL: + } + switch (connect_rsp_code) { + case MQTT_CONNECTION_REFUSE_PROTOCOL: ESP_LOGW(TAG, "Connection refused, bad protocol"); - return ESP_FAIL; - case CONNECTION_REFUSE_SERVER_UNAVAILABLE: + break; + case MQTT_CONNECTION_REFUSE_SERVER_UNAVAILABLE: ESP_LOGW(TAG, "Connection refused, server unavailable"); - return ESP_FAIL; - case CONNECTION_REFUSE_BAD_USERNAME: + break; + case MQTT_CONNECTION_REFUSE_BAD_USERNAME: ESP_LOGW(TAG, "Connection refused, bad username or password"); - return ESP_FAIL; - case CONNECTION_REFUSE_NOT_AUTHORIZED: + break; + case MQTT_CONNECTION_REFUSE_NOT_AUTHORIZED: ESP_LOGW(TAG, "Connection refused, not authorized"); - return ESP_FAIL; + break; default: ESP_LOGW(TAG, "Connection refused, Unknow reason"); - return ESP_FAIL; + break; } - return ESP_OK; + /* propagate event with connection refused error */ + client->event.event_id = MQTT_EVENT_CONNECTION_REFUSED; + client->event.connect_return_code = connect_rsp_code; + esp_mqtt_dispatch_event_with_msgid(client); + + return ESP_FAIL; } static esp_err_t esp_mqtt_abort_connection(esp_mqtt_client_handle_t client) From e3b013e2db58124ea68cf7c8f44a8cba6e1572b7 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Mon, 30 Sep 2019 14:19:43 +0200 Subject: [PATCH 2/2] Extended error structure to be used in mqtt library and include mqtt specific errors. Corrected typos in comments and log messages --- include/mqtt_client.h | 53 +++++++++++++++++++++++++++++++++---------- mqtt_client.c | 36 +++++++++++++++++++++-------- 2 files changed, 68 insertions(+), 21 deletions(-) diff --git a/include/mqtt_client.h b/include/mqtt_client.h index d08c555..8ca3293 100644 --- a/include/mqtt_client.h +++ b/include/mqtt_client.h @@ -37,7 +37,7 @@ typedef struct esp_mqtt_client *esp_mqtt_client_handle_t; * */ typedef enum { - MQTT_EVENT_ERROR = 0, /*!< on error event, additional context: error handle from esp_tls (if supported) */ + MQTT_EVENT_ERROR = 0, /*!< on error event, additional context: connection return code, error handle from esp_tls (if supported) */ MQTT_EVENT_CONNECTED, /*!< connected event, additional context: session_present flag */ MQTT_EVENT_DISCONNECTED, /*!< disconnected event */ MQTT_EVENT_SUBSCRIBED, /*!< subscribed event, additional context: msg_id */ @@ -57,7 +57,6 @@ typedef enum { and current data offset updating. */ MQTT_EVENT_BEFORE_CONNECT, /*!< The event occurs before connecting */ - MQTT_EVENT_CONNECTION_REFUSED, /*!< The event occurs if connection is refused by the broker, additional context: connect_return_code */ } esp_mqtt_event_id_t; /** @@ -72,6 +71,15 @@ typedef enum { MQTT_CONNECTION_REFUSE_NOT_AUTHORIZED /*!< MQTT connection refused reason: Wrong username or password */ } esp_mqtt_connect_return_code_t; +/** + * MQTT connection error codes propagated via ERROR event + */ +typedef enum { + MQTT_ERROR_TYPE_NONE = 0, + MQTT_ERROR_TYPE_ESP_TLS, + MQTT_ERROR_TYPE_CONNECTION_REFUSED, +} esp_mqtt_error_type_t; + typedef enum { MQTT_TRANSPORT_UNKNOWN = 0x0, MQTT_TRANSPORT_OVER_TCP, /*!< MQTT over TCP, using scheme: ``mqtt`` */ @@ -80,6 +88,28 @@ typedef enum { MQTT_TRANSPORT_OVER_WSS /*!< MQTT over Websocket Secure, using scheme: ``wss`` */ } esp_mqtt_transport_t; +/** + * @brief MQTT error code structure to be passed as a contextual information into ERROR event + * + * Important: This structure extends `esp_tls_last_error` error structure and is backward compatible with it + * (so might be down-casted and treated as `esp_tls_last_error` error, but recommended to update applications if used this way previously) + * + * Use this structure directly checking error_type first and then appropriate error code depending on the source of the error: + * + * | error_type | related member variables | note | + * | MQTT_ERROR_TYPE_ESP_TLS | esp_tls_last_esp_err, esp_tls_stack_err, esp_tls_cert_verify_flags | Error reported from esp-tls | + * | MQTT_ERROR_TYPE_CONNECTION_REFUSED | connect_return_code | Internal error reported from MQTT broker on connection | + */ +typedef struct esp_mqtt_error_codes { + /* compatible portion of the struct corresponding to struct esp_tls_last_error */ + esp_err_t esp_tls_last_esp_err; /*!< last esp_err code reported from esp-tls component */ + int esp_tls_stack_err; /*!< tls specific error code reported from underlying tls stack */ + int esp_tls_cert_verify_flags; /*!< tls flags reported from underlying tls stack during certificate verification */ + /* esp-mqtt specific structure extension */ + esp_mqtt_error_type_t error_type; /*!< error type referring to the source of the error */ + esp_mqtt_connect_return_code_t connect_return_code; /*!< connection refused error code reported from MQTT broker on connection */ +} esp_mqtt_error_codes_t; + /** * MQTT event configuration structure */ @@ -87,16 +117,15 @@ typedef struct { esp_mqtt_event_id_t event_id; /*!< MQTT event type */ esp_mqtt_client_handle_t client; /*!< MQTT client handle for this event */ void *user_context; /*!< User context passed from MQTT client config */ - char *data; /*!< Data asociated with this event */ - int data_len; /*!< Lenght of the data for this event */ + char *data; /*!< Data associated with this event */ + int data_len; /*!< Length of the data for this event */ int total_data_len; /*!< Total length of the data (longer data are supplied with multiple events) */ - int current_data_offset; /*!< Actual offset for the data asociated with this event */ - char *topic; /*!< Topic asociated with this event */ - int topic_len; /*!< Length of the topic for this event asociated with this event */ + int current_data_offset; /*!< Actual offset for the data associated with this event */ + char *topic; /*!< Topic associated with this event */ + int topic_len; /*!< Length of the topic for this event associated with this event */ int msg_id; /*!< MQTT messaged id of message */ int session_present; /*!< MQTT session_present flag for connection event */ - void* error_handle; /*!< esp-tls error handle referencing last error/flags captured in transports */ - esp_mqtt_connect_return_code_t connect_return_code; /*!< MQTT connection return code. Only written on a connection */ + esp_mqtt_error_codes_t *error_handle; /*!< esp-mqtt error handle including esp-tls errors as well as internal mqtt errors */ } esp_mqtt_event_t; typedef esp_mqtt_event_t *esp_mqtt_event_handle_t; @@ -152,7 +181,7 @@ esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *co * @brief Sets mqtt connection URI. This API is usually used to overrides the URI * configured in esp_mqtt_client_init * - * @param client mqtt client hanlde + * @param client mqtt client handle * @param uri * * @return ESP_FAIL if URI parse error, ESP_OK on success @@ -237,7 +266,7 @@ int esp_mqtt_client_unsubscribe(esp_mqtt_client_handle_t client, const char *top * @param data payload string (set to NULL, sending empty payload message) * @param len data length, if set to 0, length is calculated from payload string * @param qos qos of publish message - * @param retain ratain flag + * @param retain retain flag * * @return message_id of the publish message (for QoS 0 message_id will always be zero) on success. * -1 on failure. @@ -270,7 +299,7 @@ esp_err_t esp_mqtt_set_config(esp_mqtt_client_handle_t client, const esp_mqtt_cl * * @param client mqtt client handle * @param event event type - * @param event_handler hanlder callback + * @param event_handler handler callback * @param event_handler_arg handlers context * * @return ESP_ERR_NO_MEM if failed to allocate diff --git a/mqtt_client.c b/mqtt_client.c index e7ccc2c..19458f7 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -339,8 +339,12 @@ static esp_err_t esp_mqtt_connect(esp_mqtt_client_handle_t client, int timeout_m break; } /* propagate event with connection refused error */ - client->event.event_id = MQTT_EVENT_CONNECTION_REFUSED; - client->event.connect_return_code = connect_rsp_code; + client->event.event_id = MQTT_EVENT_ERROR; + client->event.error_handle->error_type = MQTT_ERROR_TYPE_CONNECTION_REFUSED; + client->event.error_handle->connect_return_code = connect_rsp_code; + client->event.error_handle->esp_tls_stack_err = 0; + client->event.error_handle->esp_tls_last_esp_err = 0; + client->event.error_handle->esp_tls_cert_verify_flags = 0; esp_mqtt_dispatch_event_with_msgid(client); return ESP_FAIL; @@ -363,6 +367,11 @@ esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *co { esp_mqtt_client_handle_t client = calloc(1, sizeof(struct esp_mqtt_client)); ESP_MEM_CHECK(TAG, client, return NULL); + client->event.error_handle = calloc(1, sizeof(esp_mqtt_error_codes_t)); + if (!client->event.error_handle) { + free(client); + return NULL; + } client->api_lock = xSemaphoreCreateMutex(); if (!client->api_lock) { free(client); @@ -502,6 +511,7 @@ esp_err_t esp_mqtt_client_destroy(esp_mqtt_client_handle_t client) free(client->mqtt_state.in_buffer); free(client->mqtt_state.out_buffer); vSemaphoreDelete(client->api_lock); + free(client->event.error_handle); free(client); return ESP_OK; } @@ -580,8 +590,12 @@ static esp_err_t mqtt_write_data(esp_mqtt_client_handle_t client) // client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data); if (write_len <= 0) { client->event.event_id = MQTT_EVENT_ERROR; + client->event.error_handle->error_type = MQTT_ERROR_TYPE_ESP_TLS; + client->event.error_handle->connect_return_code = 0; #ifdef MQTT_SUPPORTED_FEATURE_TRANSPORT_ERR_REPORTING - client->event.error_handle = esp_transport_get_error_handle(client->transport); + client->event.error_handle->esp_tls_last_esp_err = esp_tls_get_and_clear_last_error(esp_transport_get_error_handle(client->transport), + &client->event.error_handle->esp_tls_stack_err, + &client->event.error_handle->esp_tls_cert_verify_flags); #endif esp_mqtt_dispatch_event_with_msgid(client); ESP_LOGE(TAG, "Error write data or timeout, written len = %d, errno=%d", write_len, errno); @@ -976,7 +990,7 @@ static esp_err_t mqtt_resend_queued(esp_mqtt_client_handle_t client, outbox_item // try to resend the data if (mqtt_write_data(client) != ESP_OK) { - ESP_LOGE(TAG, "Error to public data "); + ESP_LOGE(TAG, "Error to resend data "); esp_mqtt_abort_connection(client); return ESP_FAIL; } @@ -1013,7 +1027,7 @@ static void esp_mqtt_task(void *pv) esp_mqtt_dispatch_event_with_msgid(client); if (client->transport == NULL) { - ESP_LOGE(TAG, "There are no transport"); + ESP_LOGE(TAG, "There is no transport"); client->run = false; } @@ -1023,8 +1037,12 @@ static void esp_mqtt_task(void *pv) client->config->network_timeout_ms) < 0) { ESP_LOGE(TAG, "Error transport connect"); client->event.event_id = MQTT_EVENT_ERROR; + client->event.error_handle->error_type = MQTT_ERROR_TYPE_ESP_TLS; + client->event.error_handle->connect_return_code = 0; #ifdef MQTT_SUPPORTED_FEATURE_TRANSPORT_ERR_REPORTING - client->event.error_handle = esp_transport_get_error_handle(client->transport); + client->event.error_handle->esp_tls_last_esp_err = esp_tls_get_and_clear_last_error(esp_transport_get_error_handle(client->transport), + &client->event.error_handle->esp_tls_stack_err, + &client->event.error_handle->esp_tls_cert_verify_flags); #endif esp_mqtt_dispatch_event_with_msgid(client); esp_mqtt_abort_connection(client); @@ -1090,7 +1108,7 @@ static void esp_mqtt_task(void *pv) client->state = MQTT_STATE_INIT; } - //Delete mesaage after 30 senconds + //Delete message after 30 seconds int deleted = outbox_delete_expired(client->outbox, platform_tick_get_ms(), OUTBOX_EXPIRED_TIMEOUT_MS); client->mqtt_state.pending_msg_count -= deleted; if (client->mqtt_state.pending_msg_count < 0) { @@ -1115,7 +1133,7 @@ static void esp_mqtt_task(void *pv) MQTT_API_UNLOCK(client); xEventGroupWaitBits(client->status_bits, RECONNECT_BIT, false, true, client->wait_timeout_ms / 2 / portTICK_RATE_MS); - // continue the while loop insted of break, as the mutex is unlocked + // continue the while loop instead of break, as the mutex is unlocked continue; } MQTT_API_UNLOCK(client); @@ -1371,7 +1389,7 @@ int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, cannot_publish: if (qos == 0) { - ESP_LOGW(TAG, "Publish: Loosing qos0 data when client not connected"); + ESP_LOGW(TAG, "Publish: Losing qos0 data when client not connected"); } MQTT_API_UNLOCK_FROM_OTHER_TASK(client); return 0;