From fa7ade77b146b6c77395782a619f634249b93224 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 25 Jul 2018 16:15:07 +0200 Subject: [PATCH 01/56] IDF integration: Refactored to common tcp transport component, fixed warnings --- examples/mqtt_tcp/main/Kconfig.projbuild | 6 + examples/mqtt_tcp/main/app_main.c | 43 +++- examples/mqtt_ws/main/app_main.c | 9 +- lib/transport.c | 218 ------------------- lib/transport_ssl.c | 259 ----------------------- lib/transport_tcp.c | 152 ------------- lib/transport_ws.c | 2 +- mqtt_client.c | 5 + 8 files changed, 51 insertions(+), 643 deletions(-) delete mode 100644 lib/transport.c delete mode 100644 lib/transport_ssl.c delete mode 100644 lib/transport_tcp.c diff --git a/examples/mqtt_tcp/main/Kconfig.projbuild b/examples/mqtt_tcp/main/Kconfig.projbuild index 1c9c2e6..0310c2c 100644 --- a/examples/mqtt_tcp/main/Kconfig.projbuild +++ b/examples/mqtt_tcp/main/Kconfig.projbuild @@ -12,4 +12,10 @@ config WIFI_PASSWORD help WiFi password (WPA or WPA2) for the example to use. +config BROKER_URL + string "Broker URL" + default "mqtt://iot.eclipse.org" + help + URL of the broker to connect to + endmenu diff --git a/examples/mqtt_tcp/main/app_main.c b/examples/mqtt_tcp/main/app_main.c index 05ee57a..d690b1c 100755 --- a/examples/mqtt_tcp/main/app_main.c +++ b/examples/mqtt_tcp/main/app_main.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -34,14 +35,17 @@ static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event) switch (event->event_id) { case MQTT_EVENT_CONNECTED: ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); - msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0); - ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); + msg_id = esp_mqtt_client_publish(client, "/topic/qos1", "data_3", 0, 1, 0); + ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); - msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1); - ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); + // msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0); + // ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); - msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1"); - ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id); + // msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1); + // ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); + + // msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1"); + // ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id); break; case MQTT_EVENT_DISCONNECTED: ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); @@ -49,8 +53,8 @@ static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event) case MQTT_EVENT_SUBSCRIBED: ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); - msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0); - ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); + // msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0); + // ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); break; case MQTT_EVENT_UNSUBSCRIBED: ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); @@ -114,12 +118,31 @@ static void wifi_init(void) static void mqtt_app_start(void) { - const esp_mqtt_client_config_t mqtt_cfg = { - .uri = "mqtt://iot.eclipse.org", + char line[128]; + esp_mqtt_client_config_t mqtt_cfg = { + .uri = CONFIG_BROKER_URL, .event_handle = mqtt_event_handler, // .user_context = (void *)your_context }; + if (strcmp(mqtt_cfg.uri, "FROM_STDIN") == 0) { + int count = 0; + printf("Please enter url of mqtt broker\n"); + while (count < 128) { + int c = fgetc(stdin); + if (c == '\n') { + line[count] = '\0'; + break; + } else if (c > 0 && c < 127) { + line[count] = c; + ++count; + } + vTaskDelay(10 / portTICK_PERIOD_MS); + } + mqtt_cfg.uri = line; + printf("Broker url: %s\n", line); + } + esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg); esp_mqtt_client_start(client); } diff --git a/examples/mqtt_ws/main/app_main.c b/examples/mqtt_ws/main/app_main.c index c9c65a5..2ebc65e 100755 --- a/examples/mqtt_ws/main/app_main.c +++ b/examples/mqtt_ws/main/app_main.c @@ -40,8 +40,8 @@ static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event) msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1); ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); - msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1"); - ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id); + // msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1"); + // ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id); break; case MQTT_EVENT_DISCONNECTED: ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); @@ -49,7 +49,10 @@ static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event) case MQTT_EVENT_SUBSCRIBED: ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); - msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0); + msg_id = esp_mqtt_client_publish(client, "/topic/qos1", "data_1", 0, 1, 0); + printf("sending msgid=%d\n", msg_id); + msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data_0", 0, 0, 0); + printf("sending msgid=%d\n", msg_id); ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); break; case MQTT_EVENT_UNSUBSCRIBED: diff --git a/lib/transport.c b/lib/transport.c deleted file mode 100644 index 04f3939..0000000 --- a/lib/transport.c +++ /dev/null @@ -1,218 +0,0 @@ -#include -#include - -#include "rom/queue.h" -#include "esp_log.h" - -#include "transport.h" -#include "platform.h" - - -static const char *TAG = "TRANSPORT"; - -/** - * Transport layer structure, which will provide functions, basic properties for transport types - */ -struct transport_item_t { - int port; - int socket; /*!< Socket to use in this transport */ - char *scheme; /*!< Tag name */ - void *context; /*!< Context data */ - void *data; /*!< Additional transport data */ - connect_func _connect; /*!< Connect function of this transport */ - io_read_func _read; /*!< Read */ - io_func _write; /*!< Write */ - trans_func _close; /*!< Close */ - poll_func _poll_read; /*!< Poll and read */ - poll_func _poll_write; /*!< Poll and write */ - trans_func _destroy; /*!< Destroy and free transport */ - STAILQ_ENTRY(transport_item_t) next; -}; - - -/** - * This list will hold all transport available - */ -STAILQ_HEAD(transport_list_t, transport_item_t); - - -transport_list_handle_t transport_list_init() -{ - transport_list_handle_t list = calloc(1, sizeof(struct transport_list_t)); - ESP_MEM_CHECK(TAG, list, return NULL); - STAILQ_INIT(list); - return list; -} - -esp_err_t transport_list_add(transport_list_handle_t list, transport_handle_t t, const char *scheme) -{ - if (list == NULL || t == NULL) { - return ESP_ERR_INVALID_ARG; - } - t->scheme = calloc(1, strlen(scheme) + 1); - ESP_MEM_CHECK(TAG, t->scheme, return ESP_ERR_NO_MEM); - strcpy(t->scheme, scheme); - STAILQ_INSERT_TAIL(list, t, next); - return ESP_OK; -} - -transport_handle_t transport_list_get_transport(transport_list_handle_t list, const char *scheme) -{ - if (!list) { - return NULL; - } - if (scheme == NULL) { - return STAILQ_FIRST(list); - } - transport_handle_t item; - STAILQ_FOREACH(item, list, next) { - if (strcasecmp(item->scheme, scheme) == 0) { - return item; - } - } - return NULL; -} - -esp_err_t transport_list_destroy(transport_list_handle_t list) -{ - transport_list_clean(list); - free(list); - return ESP_OK; -} - -esp_err_t transport_list_clean(transport_list_handle_t list) -{ - transport_handle_t item = STAILQ_FIRST(list); - transport_handle_t tmp; - while (item != NULL) { - tmp = STAILQ_NEXT(item, next); - if (item->_destroy) { - item->_destroy(item); - } - transport_destroy(item); - item = tmp; - } - STAILQ_INIT(list); - return ESP_OK; -} - -transport_handle_t transport_init() -{ - transport_handle_t t = calloc(1, sizeof(struct transport_item_t)); - ESP_MEM_CHECK(TAG, t, return NULL); - return t; -} - -esp_err_t transport_destroy(transport_handle_t t) -{ - if (t->scheme) { - free(t->scheme); - } - free(t); - return ESP_OK; -} - -int transport_connect(transport_handle_t t, const char *host, int port, int timeout_ms) -{ - int ret = -1; - if (t && t->_connect) { - return t->_connect(t, host, port, timeout_ms); - } - return ret; -} - -int transport_read(transport_handle_t t, char *buffer, int len, int timeout_ms) -{ - if (t && t->_read) { - return t->_read(t, buffer, len, timeout_ms); - } - return -1; -} - -int transport_write(transport_handle_t t, const char *buffer, int len, int timeout_ms) -{ - if (t && t->_write) { - return t->_write(t, buffer, len, timeout_ms); - } - return -1; -} - -int transport_poll_read(transport_handle_t t, int timeout_ms) -{ - if (t && t->_poll_read) { - return t->_poll_read(t, timeout_ms); - } - return -1; -} - -int transport_poll_write(transport_handle_t t, int timeout_ms) -{ - if (t && t->_poll_write) { - return t->_poll_write(t, timeout_ms); - } - return -1; -} - -int transport_close(transport_handle_t t) -{ - if (t && t->_close) { - return t->_close(t); - } - return 0; -} - -void *transport_get_context_data(transport_handle_t t) -{ - if (t) { - return t->data; - } - return NULL; -} - -esp_err_t transport_set_context_data(transport_handle_t t, void *data) -{ - if (t) { - t->data = data; - return ESP_OK; - } - return ESP_FAIL; -} - -esp_err_t transport_set_func(transport_handle_t t, - connect_func _connect, - io_read_func _read, - io_func _write, - trans_func _close, - poll_func _poll_read, - poll_func _poll_write, - trans_func _destroy) -{ - if (t == NULL) { - return ESP_FAIL; - } - t->_connect = _connect; - t->_read = _read; - t->_write = _write; - t->_close = _close; - t->_poll_read = _poll_read; - t->_poll_write = _poll_write; - t->_destroy = _destroy; - return ESP_OK; -} - -int transport_get_default_port(transport_handle_t t) -{ - if (t == NULL) { - return -1; - } - return t->port; -} - -esp_err_t transport_set_default_port(transport_handle_t t, int port) -{ - if (t == NULL) { - return ESP_FAIL; - } - t->port = port; - return ESP_OK; -} diff --git a/lib/transport_ssl.c b/lib/transport_ssl.c deleted file mode 100644 index a2169c3..0000000 --- a/lib/transport_ssl.c +++ /dev/null @@ -1,259 +0,0 @@ -#include -#include - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "lwip/err.h" -#include "lwip/sockets.h" -#include "lwip/sys.h" -#include "lwip/netdb.h" -#include "lwip/dns.h" - -#include "mbedtls/platform.h" -#include "mbedtls/net_sockets.h" -#include "mbedtls/esp_debug.h" -#include "mbedtls/ssl.h" -#include "mbedtls/entropy.h" -#include "mbedtls/ctr_drbg.h" -#include "mbedtls/error.h" -#include "mbedtls/certs.h" - - -#include "esp_log.h" -#include "esp_system.h" -#include "platform.h" - -#include "transport.h" -#include "transport_ssl.h" - -static const char *TAG = "TRANS_SSL"; -/** - * mbedtls specific transport data - */ -typedef struct { - mbedtls_entropy_context entropy; - mbedtls_ctr_drbg_context ctr_drbg; - mbedtls_ssl_context ctx; - mbedtls_x509_crt cacert; - mbedtls_ssl_config conf; - mbedtls_net_context client_fd; - void *cert_pem_data; - int cert_pem_len; - bool ssl_initialized; - bool verify_server; -} transport_ssl_t; - -static int ssl_close(transport_handle_t t); - -static int ssl_connect(transport_handle_t t, const char *host, int port, int timeout_ms) -{ - int ret = -1, flags; - struct timeval tv; - transport_ssl_t *ssl = transport_get_context_data(t); - - if (!ssl) { - return -1; - } - ssl->ssl_initialized = true; - mbedtls_ssl_init(&ssl->ctx); - mbedtls_ctr_drbg_init(&ssl->ctr_drbg); - mbedtls_ssl_config_init(&ssl->conf); - mbedtls_entropy_init(&ssl->entropy); - - if ((ret = mbedtls_ssl_config_defaults(&ssl->conf, - MBEDTLS_SSL_IS_CLIENT, - MBEDTLS_SSL_TRANSPORT_STREAM, - MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { - ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned %d", ret); - goto exit; - } - - if ((ret = mbedtls_ctr_drbg_seed(&ssl->ctr_drbg, mbedtls_entropy_func, &ssl->entropy, NULL, 0)) != 0) { - ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned %d", ret); - goto exit; - } - - if (ssl->cert_pem_data) { - mbedtls_x509_crt_init(&ssl->cacert); - ssl->verify_server = true; - if ((ret = mbedtls_x509_crt_parse(&ssl->cacert, ssl->cert_pem_data, ssl->cert_pem_len + 1)) < 0) { - ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x\n\nDATA=%s,len=%d", -ret, (char*)ssl->cert_pem_data, ssl->cert_pem_len); - goto exit; - } - mbedtls_ssl_conf_ca_chain(&ssl->conf, &ssl->cacert, NULL); - mbedtls_ssl_conf_authmode(&ssl->conf, MBEDTLS_SSL_VERIFY_REQUIRED); - - if ((ret = mbedtls_ssl_set_hostname(&ssl->ctx, host)) != 0) { - ESP_LOGE(TAG, "mbedtls_ssl_set_hostname returned -0x%x", -ret); - goto exit; - } - } else { - mbedtls_ssl_conf_authmode(&ssl->conf, MBEDTLS_SSL_VERIFY_NONE); - } - - - mbedtls_ssl_conf_rng(&ssl->conf, mbedtls_ctr_drbg_random, &ssl->ctr_drbg); - -#ifdef CONFIG_MBEDTLS_DEBUG - mbedtls_esp_enable_debug_log(&ssl->conf, 4); -#endif - - if ((ret = mbedtls_ssl_setup(&ssl->ctx, &ssl->conf)) != 0) { - ESP_LOGE(TAG, "mbedtls_ssl_setup returned -0x%x\n\n", -ret); - goto exit; - } - - mbedtls_net_init(&ssl->client_fd); - - ms_to_timeval(timeout_ms, &tv); - - setsockopt(ssl->client_fd.fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); - ESP_LOGD(TAG, "Connect to %s:%d", host, port); - char port_str[8] = {0}; - sprintf(port_str, "%d", port); - if ((ret = mbedtls_net_connect(&ssl->client_fd, host, port_str, MBEDTLS_NET_PROTO_TCP)) != 0) { - ESP_LOGE(TAG, "mbedtls_net_connect returned -%x", -ret); - goto exit; - } - - mbedtls_ssl_set_bio(&ssl->ctx, &ssl->client_fd, mbedtls_net_send, mbedtls_net_recv, NULL); - - if((ret = mbedtls_ssl_set_hostname(&ssl->ctx, host)) != 0) { - ESP_LOGE(TAG, " failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret); - goto exit; - } - - ESP_LOGD(TAG, "Performing the SSL/TLS handshake..."); - - while ((ret = mbedtls_ssl_handshake(&ssl->ctx)) != 0) { - if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { - ESP_LOGE(TAG, "mbedtls_ssl_handshake returned -0x%x", -ret); - goto exit; - } - } - - ESP_LOGD(TAG, "Verifying peer X.509 certificate..."); - - if ((flags = mbedtls_ssl_get_verify_result(&ssl->ctx)) != 0) { - /* In real life, we probably want to close connection if ret != 0 */ - ESP_LOGW(TAG, "Failed to verify peer certificate!"); - if (ssl->cert_pem_data) { - goto exit; - } - } else { - ESP_LOGD(TAG, "Certificate verified."); - } - - ESP_LOGD(TAG, "Cipher suite is %s", mbedtls_ssl_get_ciphersuite(&ssl->ctx)); - return ret; -exit: - ssl_close(t); - return ret; -} - -static int ssl_poll_read(transport_handle_t t, int timeout_ms) -{ - transport_ssl_t *ssl = transport_get_context_data(t); - fd_set readset; - FD_ZERO(&readset); - FD_SET(ssl->client_fd.fd, &readset); - struct timeval timeout; - ms_to_timeval(timeout_ms, &timeout); - - return select(ssl->client_fd.fd + 1, &readset, NULL, NULL, &timeout); -} - -static int ssl_poll_write(transport_handle_t t, int timeout_ms) -{ - transport_ssl_t *ssl = transport_get_context_data(t); - fd_set writeset; - FD_ZERO(&writeset); - FD_SET(ssl->client_fd.fd, &writeset); - struct timeval timeout; - ms_to_timeval(timeout_ms, &timeout); - return select(ssl->client_fd.fd + 1, NULL, &writeset, NULL, &timeout); -} - -static int ssl_write(transport_handle_t t, const char *buffer, int len, int timeout_ms) -{ - int poll, ret; - transport_ssl_t *ssl = transport_get_context_data(t); - - if ((poll = transport_poll_write(t, timeout_ms)) <= 0) { - ESP_LOGW(TAG, "Poll timeout or error, errno=%s, fd=%d, timeout_ms=%d", strerror(errno), ssl->client_fd.fd, timeout_ms); - return poll; - } - ret = mbedtls_ssl_write(&ssl->ctx, (const unsigned char *) buffer, len); - if (ret <= 0) { - ESP_LOGE(TAG, "mbedtls_ssl_write error, errno=%s", strerror(errno)); - } - return ret; -} - -static int ssl_read(transport_handle_t t, char *buffer, int len, int timeout_ms) -{ - int poll = -1, ret; - transport_ssl_t *ssl = transport_get_context_data(t); - - if (mbedtls_ssl_get_bytes_avail(&ssl->ctx) <= 0) { - if ((poll = transport_poll_read(t, timeout_ms)) <= 0) { - return poll; - } - } - ret = mbedtls_ssl_read(&ssl->ctx, (unsigned char *)buffer, len); - if (ret == 0) { - return -1; - } - return ret; -} - -static int ssl_close(transport_handle_t t) -{ - int ret = -1; - transport_ssl_t *ssl = transport_get_context_data(t); - if (ssl->ssl_initialized) { - ESP_LOGD(TAG, "Cleanup mbedtls"); - mbedtls_ssl_close_notify(&ssl->ctx); - mbedtls_ssl_session_reset(&ssl->ctx); - mbedtls_net_free(&ssl->client_fd); - mbedtls_ssl_config_free(&ssl->conf); - if (ssl->verify_server) { - mbedtls_x509_crt_free(&ssl->cacert); - } - mbedtls_ctr_drbg_free(&ssl->ctr_drbg); - mbedtls_entropy_free(&ssl->entropy); - mbedtls_ssl_free(&ssl->ctx); - ssl->ssl_initialized = false; - ssl->verify_server = false; - } - return ret; -} - -static int ssl_destroy(transport_handle_t t) -{ - transport_ssl_t *ssl = transport_get_context_data(t); - transport_close(t); - free(ssl); - return 0; -} - -void transport_ssl_set_cert_data(transport_handle_t t, const char *data, int len) -{ - transport_ssl_t *ssl = transport_get_context_data(t); - if (t && ssl) { - ssl->cert_pem_data = (void *)data; - ssl->cert_pem_len = len; - } -} - -transport_handle_t transport_ssl_init() -{ - transport_handle_t t = transport_init(); - transport_ssl_t *ssl = calloc(1, sizeof(transport_ssl_t)); - ESP_MEM_CHECK(TAG, ssl, return NULL); - mbedtls_net_init(&ssl->client_fd); - transport_set_context_data(t, ssl); - transport_set_func(t, ssl_connect, ssl_read, ssl_write, ssl_close, ssl_poll_read, ssl_poll_write, ssl_destroy); - return t; -} - diff --git a/lib/transport_tcp.c b/lib/transport_tcp.c deleted file mode 100644 index e98ce93..0000000 --- a/lib/transport_tcp.c +++ /dev/null @@ -1,152 +0,0 @@ -#include -#include - -#include "lwip/sockets.h" -#include "lwip/dns.h" -#include "lwip/netdb.h" - -#include "esp_log.h" -#include "esp_system.h" -#include "esp_err.h" - -#include "platform.h" -#include "transport.h" - -static const char *TAG = "TRANS_TCP"; - -typedef struct { - int sock; -} transport_tcp_t; - -static int resolve_dns(const char *host, struct sockaddr_in *ip) { - - struct hostent *he; - struct in_addr **addr_list; - he = gethostbyname(host); - if (he == NULL) { - return ESP_FAIL; - } - addr_list = (struct in_addr **)he->h_addr_list; - if (addr_list[0] == NULL) { - return ESP_FAIL; - } - ip->sin_family = AF_INET; - memcpy(&ip->sin_addr, addr_list[0], sizeof(ip->sin_addr)); - return ESP_OK; -} - -static int tcp_connect(transport_handle_t t, const char *host, int port, int timeout_ms) -{ - struct sockaddr_in remote_ip; - struct timeval tv; - transport_tcp_t *tcp = transport_get_context_data(t); - - bzero(&remote_ip, sizeof(struct sockaddr_in)); - - //if stream_host is not ip address, resolve it AF_INET,servername,&serveraddr.sin_addr - if (inet_pton(AF_INET, host, &remote_ip.sin_addr) != 1) { - if (resolve_dns(host, &remote_ip) < 0) { - return -1; - } - } - - tcp->sock = socket(PF_INET, SOCK_STREAM, 0); - - if (tcp->sock < 0) { - ESP_LOGE(TAG, "Error create socket"); - return -1; - } - - remote_ip.sin_family = AF_INET; - remote_ip.sin_port = htons(port); - - ms_to_timeval(timeout_ms, &tv); - - setsockopt(tcp->sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); - - ESP_LOGD(TAG, "[sock=%d],connecting to server IP:%s,Port:%d...", - tcp->sock, ipaddr_ntoa((const ip_addr_t*)&remote_ip.sin_addr.s_addr), port); - if (connect(tcp->sock, (struct sockaddr *)(&remote_ip), sizeof(struct sockaddr)) != 0) { - close(tcp->sock); - tcp->sock = -1; - return -1; - } - return tcp->sock; -} - -static int tcp_write(transport_handle_t t, const char *buffer, int len, int timeout_ms) -{ - int poll; - transport_tcp_t *tcp = transport_get_context_data(t); - if ((poll = transport_poll_write(t, timeout_ms)) <= 0) { - return poll; - } - return write(tcp->sock, buffer, len); -} - -static int tcp_read(transport_handle_t t, char *buffer, int len, int timeout_ms) -{ - transport_tcp_t *tcp = transport_get_context_data(t); - int poll = -1; - if ((poll = transport_poll_read(t, timeout_ms)) <= 0) { - return poll; - } - int read_len = read(tcp->sock, buffer, len); - if (read_len == 0) { - return -1; - } - return read_len; -} - -static int tcp_poll_read(transport_handle_t t, int timeout_ms) -{ - transport_tcp_t *tcp = transport_get_context_data(t); - fd_set readset; - FD_ZERO(&readset); - FD_SET(tcp->sock, &readset); - struct timeval timeout; - ms_to_timeval(timeout_ms, &timeout); - return select(tcp->sock + 1, &readset, NULL, NULL, &timeout); -} - -static int tcp_poll_write(transport_handle_t t, int timeout_ms) -{ - transport_tcp_t *tcp = transport_get_context_data(t); - fd_set writeset; - FD_ZERO(&writeset); - FD_SET(tcp->sock, &writeset); - struct timeval timeout; - ms_to_timeval(timeout_ms, &timeout); - return select(tcp->sock + 1, NULL, &writeset, NULL, &timeout); -} - -static int tcp_close(transport_handle_t t) -{ - transport_tcp_t *tcp = transport_get_context_data(t); - int ret = -1; - if (tcp->sock >= 0) { - ret = close(tcp->sock); - tcp->sock = -1; - } - return ret; -} - -static esp_err_t tcp_destroy(transport_handle_t t) -{ - transport_tcp_t *tcp = transport_get_context_data(t); - transport_close(t); - free(tcp); - return 0; -} - -transport_handle_t transport_tcp_init() -{ - transport_handle_t t = transport_init(); - transport_tcp_t *tcp = calloc(1, sizeof(transport_tcp_t)); - ESP_MEM_CHECK(TAG, tcp, return NULL); - tcp->sock = -1; - transport_set_func(t, tcp_connect, tcp_read, tcp_write, tcp_close, tcp_poll_read, tcp_poll_write, tcp_destroy); - transport_set_context_data(t, tcp); - - return t; -} diff --git a/lib/transport_ws.c b/lib/transport_ws.c index df0ae1b..59599ec 100644 --- a/lib/transport_ws.c +++ b/lib/transport_ws.c @@ -98,7 +98,7 @@ static int ws_connect(transport_handle_t t, const char *host, int port, int time unsigned char client_key_b64[64], valid_client_key[20], accept_key[32] = {0}; int key_len = sprintf((char*)client_key_b64, "%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11", (char*)client_key); - mbedtls_sha1(client_key_b64, (size_t)key_len, valid_client_key); + mbedtls_sha1_ret(client_key_b64, (size_t)key_len, valid_client_key); mbedtls_base64_encode(accept_key, 32, &outlen, valid_client_key, 20); accept_key[outlen] = 0; ESP_LOGD(TAG, "server key=%s, send_key=%s, accept_key=%s", (char *)server_key, (char*)client_key, accept_key); diff --git a/mqtt_client.c b/mqtt_client.c index f9f9a44..fd1cedb 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -844,6 +844,10 @@ int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, if (len <= 0) { len = strlen(data); } + // Note: Need to enqueue the qos>0 msg + // if (qos > 0) { + // mqtt_enqueue(client); + // } client->mqtt_state.outbound_message = mqtt_msg_publish(&client->mqtt_state.mqtt_connection, topic, data, len, @@ -853,6 +857,7 @@ int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data); client->mqtt_state.pending_msg_id = pending_msg_id; client->mqtt_state.pending_msg_count ++; + // Note: Need to enqueue the qos>0 msg to pass https://code.google.com/archive/p/mqtt4erl/wikis/QualityOfServiceUseCases.wiki mqtt_enqueue(client); } From 0c25441fddf163897477285ae90dfa7405a0a858 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 15 Aug 2018 17:24:46 +0200 Subject: [PATCH 02/56] support for custom implementation of msg outbox --- Kconfig | 18 +++++++++++------ examples/mqtt_tcp/main/Kconfig.projbuild | 4 ++++ examples/mqtt_tcp/main/app_main.c | 25 ++++++++++++++---------- examples/mqtt_ws/main/app_main.c | 9 +++------ lib/include/mqtt_outbox.h | 15 ++------------ lib/mqtt_outbox.c | 19 ++++++++++++++++++ mqtt_client.c | 6 +----- 7 files changed, 56 insertions(+), 40 deletions(-) diff --git a/Kconfig b/Kconfig index f798f2d..c17f83c 100644 --- a/Kconfig +++ b/Kconfig @@ -79,11 +79,11 @@ config MQTT_TASK_STACK_SIZE MQTT task stack size config MQTT_TASK_CORE_SELECTION_ENABLED - bool "Enable MQTT task core selection" - default false - help - This will enable core selection - + bool "Enable MQTT task core selection" + default false + help + This will enable core selection + choice depends on MQTT_TASK_CORE_SELECTION_ENABLED prompt "Core to use ?" @@ -92,5 +92,11 @@ choice config MQTT_USE_CORE_1 bool "Core 1" endchoice - + +config MQTT_CUSTOM_OUTBOX + bool "Enable custom outbox implementation" + default n + help + Set to true if a specific implementation of message outbox is needed (e.g. persistant outbox in NVM or similar). + endmenu diff --git a/examples/mqtt_tcp/main/Kconfig.projbuild b/examples/mqtt_tcp/main/Kconfig.projbuild index 0310c2c..c96a495 100644 --- a/examples/mqtt_tcp/main/Kconfig.projbuild +++ b/examples/mqtt_tcp/main/Kconfig.projbuild @@ -18,4 +18,8 @@ config BROKER_URL help URL of the broker to connect to +config BROKER_URL_FROM_STDIN + bool + default y if BROKER_URL = "FROM_STDIN" + endmenu diff --git a/examples/mqtt_tcp/main/app_main.c b/examples/mqtt_tcp/main/app_main.c index d690b1c..f2c855b 100755 --- a/examples/mqtt_tcp/main/app_main.c +++ b/examples/mqtt_tcp/main/app_main.c @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -38,14 +37,14 @@ static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event) msg_id = esp_mqtt_client_publish(client, "/topic/qos1", "data_3", 0, 1, 0); ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); - // msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0); - // ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); + msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0); + ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); - // msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1); - // ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); + msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1); + ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); - // msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1"); - // ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id); + msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1"); + ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id); break; case MQTT_EVENT_DISCONNECTED: ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); @@ -53,8 +52,8 @@ static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event) case MQTT_EVENT_SUBSCRIBED: ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); - // msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0); - // ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); + msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0); + ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); break; case MQTT_EVENT_UNSUBSCRIBED: ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); @@ -118,13 +117,15 @@ static void wifi_init(void) static void mqtt_app_start(void) { - char line[128]; esp_mqtt_client_config_t mqtt_cfg = { .uri = CONFIG_BROKER_URL, .event_handle = mqtt_event_handler, // .user_context = (void *)your_context }; +#if CONFIG_BROKER_URL_FROM_STDIN + char line[128]; + if (strcmp(mqtt_cfg.uri, "FROM_STDIN") == 0) { int count = 0; printf("Please enter url of mqtt broker\n"); @@ -141,7 +142,11 @@ static void mqtt_app_start(void) } mqtt_cfg.uri = line; printf("Broker url: %s\n", line); + } else { + ESP_LOGE(TAG, "Configuration mismatch: wrong broker url"); + abort(); } +#endif /* CONFIG_BROKER_URL_FROM_STDIN */ esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg); esp_mqtt_client_start(client); diff --git a/examples/mqtt_ws/main/app_main.c b/examples/mqtt_ws/main/app_main.c index 2ebc65e..c9c65a5 100755 --- a/examples/mqtt_ws/main/app_main.c +++ b/examples/mqtt_ws/main/app_main.c @@ -40,8 +40,8 @@ static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event) msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1); ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); - // msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1"); - // ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id); + msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1"); + ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id); break; case MQTT_EVENT_DISCONNECTED: ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); @@ -49,10 +49,7 @@ static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event) case MQTT_EVENT_SUBSCRIBED: ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); - msg_id = esp_mqtt_client_publish(client, "/topic/qos1", "data_1", 0, 1, 0); - printf("sending msgid=%d\n", msg_id); - msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data_0", 0, 0, 0); - printf("sending msgid=%d\n", msg_id); + msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0); ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); break; case MQTT_EVENT_UNSUBSCRIBED: diff --git a/lib/include/mqtt_outbox.h b/lib/include/mqtt_outbox.h index b94bd80..a87b466 100644 --- a/lib/include/mqtt_outbox.h +++ b/lib/include/mqtt_outbox.h @@ -11,21 +11,10 @@ extern "C" { #endif -typedef struct outbox_item { - char *buffer; - int len; - int msg_id; - int msg_type; - int tick; - int retry_count; - bool pending; - STAILQ_ENTRY(outbox_item) next; -} outbox_item_t; - -STAILQ_HEAD(outbox_list_t, outbox_item); +struct outbox_item; typedef struct outbox_list_t * outbox_handle_t; -typedef outbox_item_t *outbox_item_handle_t; +typedef struct outbox_item * outbox_item_handle_t; outbox_handle_t outbox_init(); outbox_item_handle_t outbox_enqueue(outbox_handle_t outbox, uint8_t *data, int len, int msg_id, int msg_type, int tick); diff --git a/lib/mqtt_outbox.c b/lib/mqtt_outbox.c index 8175475..300e698 100644 --- a/lib/mqtt_outbox.c +++ b/lib/mqtt_outbox.c @@ -4,8 +4,25 @@ #include "rom/queue.h" #include "esp_log.h" +#ifndef CONFIG_MQTT_CUSTOM_OUTBOX + + static const char *TAG = "OUTBOX"; +typedef struct outbox_item { + char *buffer; + int len; + int msg_id; + int msg_type; + int tick; + int retry_count; + bool pending; + STAILQ_ENTRY(outbox_item) next; +} outbox_item_t; + +STAILQ_HEAD(outbox_list_t, outbox_item); + + outbox_handle_t outbox_init() { outbox_handle_t outbox = calloc(1, sizeof(struct outbox_list_t)); @@ -149,3 +166,5 @@ void outbox_destroy(outbox_handle_t outbox) outbox_cleanup(outbox, 0); free(outbox); } + +#endif /* CONFIG_MQTT_CUSTOM_OUTBOX */ \ No newline at end of file diff --git a/mqtt_client.c b/mqtt_client.c index fd1cedb..2b2c6c4 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -844,10 +844,6 @@ int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, if (len <= 0) { len = strlen(data); } - // Note: Need to enqueue the qos>0 msg - // if (qos > 0) { - // mqtt_enqueue(client); - // } client->mqtt_state.outbound_message = mqtt_msg_publish(&client->mqtt_state.mqtt_connection, topic, data, len, @@ -857,7 +853,7 @@ int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data); client->mqtt_state.pending_msg_id = pending_msg_id; client->mqtt_state.pending_msg_count ++; - // Note: Need to enqueue the qos>0 msg to pass https://code.google.com/archive/p/mqtt4erl/wikis/QualityOfServiceUseCases.wiki + /* Have to enqueue all the qos>0 messages) */ mqtt_enqueue(client); } From 3bbdebcca9c4567f74ac14f810315f3409e31ffc Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 16 Aug 2018 18:35:08 +0200 Subject: [PATCH 03/56] bugfix for longer data on ws transport --- Kconfig | 2 +- include/mqtt_client.h | 48 +++---- lib/include/transport.h | 242 ------------------------------------ lib/include/transport_ssl.h | 39 ------ lib/include/transport_tcp.h | 27 ---- lib/transport_ws.c | 16 ++- mqtt_client.c | 12 +- 7 files changed, 50 insertions(+), 336 deletions(-) delete mode 100644 lib/include/transport.h delete mode 100644 lib/include/transport_ssl.h delete mode 100644 lib/include/transport_tcp.h diff --git a/Kconfig b/Kconfig index c17f83c..323cc39 100644 --- a/Kconfig +++ b/Kconfig @@ -1,4 +1,4 @@ -menu "ESPMQTT Configurations" +menu "ESP-MQTT Configurations" config MQTT_PROTOCOL_311 bool "Enable MQTT protocol 3.1.1" diff --git a/include/mqtt_client.h b/include/mqtt_client.h index 01a2fe1..6728ab4 100755 --- a/include/mqtt_client.h +++ b/include/mqtt_client.h @@ -32,10 +32,10 @@ typedef enum { typedef enum { MQTT_TRANSPORT_UNKNOWN = 0x0, - MQTT_TRANSPORT_OVER_TCP, - MQTT_TRANSPORT_OVER_SSL, - MQTT_TRANSPORT_OVER_WS, - MQTT_TRANSPORT_OVER_WSS + MQTT_TRANSPORT_OVER_TCP, /*!< MQTT over TCP, using scheme: ``mqtt`` */ + MQTT_TRANSPORT_OVER_SSL, /*!< MQTT over SSL, using scheme: ``mqtts`` */ + MQTT_TRANSPORT_OVER_WS, /*!< MQTT over Websocket, using scheme:: ``ws`` */ + MQTT_TRANSPORT_OVER_WSS /*!< MQTT over Websocket Secure, using scheme: ``wss`` */ } esp_mqtt_transport_t; typedef struct { @@ -57,27 +57,27 @@ typedef esp_err_t (* mqtt_event_callback_t)(esp_mqtt_event_handle_t event); typedef struct { - mqtt_event_callback_t event_handle; - const char *host; + mqtt_event_callback_t event_handle; /*!< handle for MQTT events */ + const char *host; /*!< MQTT server domain (ipv4 as string) */ const char *uri; - uint32_t port; - const char *client_id; - const char *username; - const char *password; - const char *lwt_topic; - const char *lwt_msg; - int lwt_qos; - int lwt_retain; - int lwt_msg_len; - int disable_clean_session; - int keepalive; - bool disable_auto_reconnect; - void *user_context; - int task_prio; - int task_stack; - int buffer_size; - const char *cert_pem; - esp_mqtt_transport_t transport; + uint32_t port; /*!< MQTT server port */ + const char *client_id; /*!< default client id is ``ESP32_%CHIPID%`` where %CHIPID% are last 3 bytes of MAC address in hex format */ + const char *username; /*!< MQTT username */ + const char *password; /*!< MQTT password */ + const char *lwt_topic; /*!< LWT (Last Will and Testament) message topic (NULL by default) */ + const char *lwt_msg; /*!< LWT message (NULL by default) */ + int lwt_qos; /*!< LWT message qos */ + int lwt_retain; /*!< LWT retained message flag */ + int lwt_msg_len; /*!< LWT message length */ + int disable_clean_session; /*!< mqtt clean session, default clean_session is true */ + int keepalive; /*!< mqtt keepalive, default is 120 seconds */ + bool disable_auto_reconnect; /*!< this mqtt client will reconnect to server (when errors/disconnect). Set disable_auto_reconnect=true to disable */ + void *user_context; /*!< pass user context to this option, then can receive that context in ``event->user_context`` */ + int task_prio; /*!< MQTT task priority, default is 5, can be changed in ``make menuconfig`` */ + int task_stack; /*!< MQTT task stack size, default is 6144 bytes, can be changed in ``make menuconfig`` */ + int buffer_size; /*!< size of MQTT send/receive buffer, default is 1024 */ + const char *cert_pem; /*!< pointer to CERT file for server verify (with SSL), default is NULL, not required to verify the server */ + esp_mqtt_transport_t transport; /*!< overrides URI transport */ } esp_mqtt_client_config_t; esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *config); diff --git a/lib/include/transport.h b/lib/include/transport.h deleted file mode 100644 index 9dbd880..0000000 --- a/lib/include/transport.h +++ /dev/null @@ -1,242 +0,0 @@ -/* - * This file is subject to the terms and conditions defined in - * file 'LICENSE', which is part of this source code package. - * Tuan PM - */ -#ifndef _TRANSPORT_H_ -#define _TRANSPORT_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - - -typedef struct transport_list_t* transport_list_handle_t; -typedef struct transport_item_t* transport_handle_t; - -typedef int (*connect_func)(transport_handle_t t, const char *host, int port, int timeout_ms); -typedef int (*io_func)(transport_handle_t t, const char *buffer, int len, int timeout_ms); -typedef int (*io_read_func)(transport_handle_t t, char *buffer, int len, int timeout_ms); -typedef int (*trans_func)(transport_handle_t t); -typedef int (*poll_func)(transport_handle_t t, int timeout_ms); - -/** - * @brief Create transport list - * - * @return A handle can hold all transports - */ -transport_list_handle_t transport_list_init(); - -/** - * @brief Cleanup and free all transports, include itself, - * this function will invoke transport_destroy of every transport have added this the list - * - * @param[in] list The list - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t transport_list_destroy(transport_list_handle_t list); - -/** - * @brief Add a transport to the list, and define a scheme to indentify this transport in the list - * - * @param[in] list The list - * @param[in] t The Transport - * @param[in] scheme The scheme - * - * @return - * - ESP_OK - */ -esp_err_t transport_list_add(transport_list_handle_t list, transport_handle_t t, const char *scheme); - -/** - * @brief This function will remove all transport from the list, - * invoke transport_destroy of every transport have added this the list - * - * @param[in] list The list - * - * @return - * - ESP_OK - * - ESP_ERR_INVALID_ARG - */ -esp_err_t transport_list_clean(transport_list_handle_t list); - -/** - * @brief Get the transport by scheme, which has been defined when calling function `transport_list_add` - * - * @param[in] list The list - * @param[in] tag The tag - * - * @return The transport handle - */ -transport_handle_t transport_list_get_transport(transport_list_handle_t list, const char *scheme); - -/** - * @brief Initialize a transport handle object - * - * @return The transport handle - */ -transport_handle_t transport_init(); - -/** - * @brief Cleanup and free memory the transport - * - * @param[in] t The transport handle - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t transport_destroy(transport_handle_t t); - -/** - * @brief Get default port number used by this transport - * - * @param[in] t The transport handle - * - * @return the port number - */ -int transport_get_default_port(transport_handle_t t); - -/** - * @brief Set default port number that can be used by this transport - * - * @param[in] t The transport handle - * @param[in] port The port number - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t transport_set_default_port(transport_handle_t t, int port); - -/** - * @brief Transport connection function, to make a connection to server - * - * @param t The transport handle - * @param[in] host Hostname - * @param[in] port Port - * @param[in] timeout_ms The timeout milliseconds - * - * @return - * - socket for will use by this transport - * - (-1) if there are any errors, should check errno - */ -int transport_connect(transport_handle_t t, const char *host, int port, int timeout_ms); - -/** - * @brief Transport read function - * - * @param t The transport handle - * @param buffer The buffer - * @param[in] len The length - * @param[in] timeout_ms The timeout milliseconds - * - * @return - * - Number of bytes was read - * - (-1) if there are any errors, should check errno - */ -int transport_read(transport_handle_t t, char *buffer, int len, int timeout_ms); - -/** - * @brief Poll the transport until readable or timeout - * - * @param[in] t The transport handle - * @param[in] timeout_ms The timeout milliseconds - * - * @return - * - 0 Timeout - * - (-1) If there are any errors, should check errno - * - other The transport can read - */ -int transport_poll_read(transport_handle_t t, int timeout_ms); - -/** - * @brief Transport write function - * - * @param t The transport handle - * @param buffer The buffer - * @param[in] len The length - * @param[in] timeout_ms The timeout milliseconds - * - * @return - * - Number of bytes was written - * - (-1) if there are any errors, should check errno - */ -int transport_write(transport_handle_t t, const char *buffer, int len, int timeout_ms); - -/** - * @brief Poll the transport until writeable or timeout - * - * @param[in] t The transport handle - * @param[in] timeout_ms The timeout milliseconds - * - * @return - * - 0 Timeout - * - (-1) If there are any errors, should check errno - * - other The transport can write - */ -int transport_poll_write(transport_handle_t t, int timeout_ms); - -/** - * @brief Transport close - * - * @param t The transport handle - * - * @return - * - 0 if ok - * - (-1) if there are any errors, should check errno - */ -int transport_close(transport_handle_t t); - -/** - * @brief Get user data context of this transport - * - * @param[in] t The transport handle - * - * @return The user data context - */ -void *transport_get_context_data(transport_handle_t t); - -/** - * @brief Set the user context data for this transport - * - * @param[in] t The transport handle - * @param data The user data context - * - * @return - * - ESP_OK - */ -esp_err_t transport_set_context_data(transport_handle_t t, void *data); - -/** - * @brief Set transport functions for the transport handle - * - * @param[in] t The transport handle - * @param[in] _connect The connect function pointer - * @param[in] _read The read function pointer - * @param[in] _write The write function pointer - * @param[in] _close The close function pointer - * @param[in] _poll_read The poll read function pointer - * @param[in] _poll_write The poll write function pointer - * @param[in] _destroy The destroy function pointer - * - * @return - * - ESP_OK - */ -esp_err_t transport_set_func(transport_handle_t t, - connect_func _connect, - io_read_func _read, - io_func _write, - trans_func _close, - poll_func _poll_read, - poll_func _poll_write, - trans_func _destroy); -#ifdef __cplusplus -} -#endif -#endif diff --git a/lib/include/transport_ssl.h b/lib/include/transport_ssl.h deleted file mode 100644 index 2469aa5..0000000 --- a/lib/include/transport_ssl.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * This file is subject to the terms and conditions defined in - * file 'LICENSE', which is part of this source code package. - * Tuan PM - */ -#ifndef _TRANSPORT_SSL_H_ -#define _TRANSPORT_SSL_H_ - -#include "transport.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -/** - * @brief Create new SSL transport, the transport handle must be release transport_destroy callback - * - * @return the allocated transport_handle_t, or NULL if the handle can not be allocated - */ -transport_handle_t transport_ssl_init(); - -/** - * @brief Set SSL certificate data (as PEM format). - * Note that, this function stores the pointer to data, rather than making a copy. - * So we need to make sure to keep the data lifetime before cleanup the connection - * - * @param t ssl transport - * @param[in] data The pem data - * @param[in] len The length - */ -void transport_ssl_set_cert_data(transport_handle_t t, const char *data, int len); - - -#ifdef __cplusplus -} -#endif -#endif - diff --git a/lib/include/transport_tcp.h b/lib/include/transport_tcp.h deleted file mode 100644 index 99160f3..0000000 --- a/lib/include/transport_tcp.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * This file is subject to the terms and conditions defined in - * file 'LICENSE', which is part of this source code package. - * Tuan PM - */ -#ifndef _TRANSPORT_TCP_H_ -#define _TRANSPORT_TCP_H_ - -#include "transport.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Create TCP transport, the transport handle must be release transport_destroy callback - * - * @return the allocated transport_handle_t, or NULL if the handle can not be allocated - */ -transport_handle_t transport_tcp_init(); - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/transport_ws.c b/lib/transport_ws.c index 59599ec..df880ca 100644 --- a/lib/transport_ws.c +++ b/lib/transport_ws.c @@ -19,6 +19,12 @@ typedef struct { transport_handle_t parent; } transport_ws_t; +transport_handle_t ws_transport_get_payload_transport_handle(transport_handle_t t) +{ + transport_ws_t *ws = transport_get_context_data(t); + return ws->parent; +} + static char *trimwhitespace(const char *str) { char *end; @@ -151,6 +157,7 @@ static int ws_read(transport_handle_t t, char *buffer, int len, int timeout_ms) { transport_ws_t *ws = transport_get_context_data(t); int payload_len; + int payload_len_buff = len; char *data_ptr = buffer, opcode, mask, *mask_key = NULL; int rlen; int poll_read; @@ -161,7 +168,6 @@ static int ws_read(transport_handle_t t, char *buffer, int len, int timeout_ms) ESP_LOGE(TAG, "Error read data"); return rlen; } - opcode = (*data_ptr & 0x0F); data_ptr ++; mask = ((*data_ptr >> 7) & 0x01); @@ -171,6 +177,7 @@ static int ws_read(transport_handle_t t, char *buffer, int len, int timeout_ms) if (payload_len == 126) { // headerLen += 2; payload_len = data_ptr[0] << 8 | data_ptr[1]; + payload_len_buff = len - 4; data_ptr += 2; } else if (payload_len == 127) { // headerLen += 8; @@ -182,6 +189,11 @@ static int ws_read(transport_handle_t t, char *buffer, int len, int timeout_ms) payload_len = data_ptr[4] << 24 | data_ptr[5] << 16 | data_ptr[6] << 8 | data_ptr[7]; } data_ptr += 8; + payload_len_buff = len - 10; + } + if (payload_len > payload_len_buff) { + ESP_LOGD(TAG, "Actual data received (%d) are longer than mqtt buffer (%d)", payload_len, payload_len_buff); + payload_len = payload_len_buff; } if (mask) { @@ -244,7 +256,7 @@ transport_handle_t transport_ws_init(transport_handle_t parent_handle) return NULL; }); - transport_set_func(t, ws_connect, ws_read, ws_write, ws_close, ws_poll_read, ws_poll_write, ws_destroy); + transport_set_func(t, ws_connect, ws_read, ws_write, ws_close, ws_poll_read, ws_poll_write, ws_destroy, ws_transport_get_payload_transport_handle); transport_set_context_data(t, ws); return t; } diff --git a/mqtt_client.c b/mqtt_client.c index 2b2c6c4..e73aa0c 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -461,6 +461,11 @@ static esp_err_t esp_mqtt_dispatch_event(esp_mqtt_client_handle_t client) } +typedef struct { + char *path; + char *buffer; + transport_handle_t parent; +} transport_ws_t; static void deliver_publish(esp_mqtt_client_handle_t client, uint8_t *message, int length) { @@ -468,6 +473,7 @@ static void deliver_publish(esp_mqtt_client_handle_t client, uint8_t *message, i uint32_t mqtt_topic_length, mqtt_data_length; uint32_t mqtt_len, mqtt_offset = 0, total_mqtt_len = 0; int len_read; + transport_handle_t transport = client->transport; do { @@ -478,9 +484,13 @@ static void deliver_publish(esp_mqtt_client_handle_t client, uint8_t *message, i mqtt_data = mqtt_get_publish_data(message, &mqtt_data_length); total_mqtt_len = client->mqtt_state.message_length - client->mqtt_state.message_length_read + mqtt_data_length; mqtt_len = mqtt_data_length; + /* any further reading only the underlying payload */ + transport = transport_get_payload_transport_handle(transport); } else { mqtt_len = len_read; mqtt_data = (const char*)client->mqtt_state.in_buffer; + mqtt_topic = NULL; + mqtt_topic_length = 0; } ESP_LOGD(TAG, "Get data len= %d, topic len=%d", mqtt_len, mqtt_topic_length); @@ -498,7 +508,7 @@ static void deliver_publish(esp_mqtt_client_handle_t client, uint8_t *message, i break; } - len_read = transport_read(client->transport, + len_read = transport_read(transport, (char *)client->mqtt_state.in_buffer, client->mqtt_state.message_length - client->mqtt_state.message_length_read > client->mqtt_state.in_buffer_length ? client->mqtt_state.in_buffer_length : client->mqtt_state.message_length - client->mqtt_state.message_length_read, From c1ce30f69302acaa0c25db531cfebbc9af706742 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 21 Aug 2018 15:31:10 +0200 Subject: [PATCH 04/56] Added doxygen tags for API reference documentation --- include/mqtt_client.h | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/include/mqtt_client.h b/include/mqtt_client.h index 6728ab4..45fcbe7 100755 --- a/include/mqtt_client.h +++ b/include/mqtt_client.h @@ -38,28 +38,33 @@ typedef enum { MQTT_TRANSPORT_OVER_WSS /*!< MQTT over Websocket Secure, using scheme: ``wss`` */ } esp_mqtt_transport_t; +/** + * MQTT event configuration structure + */ typedef struct { - esp_mqtt_event_id_t event_id; - esp_mqtt_client_handle_t client; - void *user_context; - char *data; - int data_len; - int total_data_len; - int current_data_offset; - char *topic; - int topic_len; - int msg_id; + 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 */ + 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 msg_id; /*!< MQTT messaged id of message */ } esp_mqtt_event_t; typedef esp_mqtt_event_t* esp_mqtt_event_handle_t; typedef esp_err_t (* mqtt_event_callback_t)(esp_mqtt_event_handle_t event); - +/** + * MQTT client configuration structure + */ typedef struct { mqtt_event_callback_t event_handle; /*!< handle for MQTT events */ const char *host; /*!< MQTT server domain (ipv4 as string) */ - const char *uri; + const char *uri; /*!< Complete MQTT broker URI */ uint32_t port; /*!< MQTT server port */ const char *client_id; /*!< default client id is ``ESP32_%CHIPID%`` where %CHIPID% are last 3 bytes of MAC address in hex format */ const char *username; /*!< MQTT username */ From abaab2abccc019aa57f5b9afaf57f0d49f7b1b6f Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 11 Sep 2018 11:33:10 +0200 Subject: [PATCH 05/56] Moved examples with tests to idf, renamed Kconfig to be included from component config in idf, All these changes are necessary to support new CMake based build system and documentation generation so that this version of esp-mqtt is no longer usable as standalone component, but a standart component of esp-idf --- Kconfig => Kconfig.included | 0 examples/mqtt_ssl/CMakeLists.txt | 19 --- examples/mqtt_ssl/Makefile | 13 -- examples/mqtt_ssl/README.md | 5 - examples/mqtt_ssl/main/Kconfig.projbuild | 15 -- examples/mqtt_ssl/main/app_main.c | 149 ------------------ examples/mqtt_ssl/main/component.mk | 1 - examples/mqtt_ssl/main/iot_eclipse_org.pem | 27 ---- examples/mqtt_tcp/CMakeLists.txt | 19 --- examples/mqtt_tcp/Makefile | 13 -- examples/mqtt_tcp/README.md | 1 - examples/mqtt_tcp/main/Kconfig.projbuild | 25 --- examples/mqtt_tcp/main/app_main.c | 171 --------------------- examples/mqtt_tcp/main/component.mk | 0 examples/mqtt_ws/CMakeLists.txt | 19 --- examples/mqtt_ws/Makefile | 13 -- examples/mqtt_ws/README.md | 1 - examples/mqtt_ws/main/Kconfig.projbuild | 15 -- examples/mqtt_ws/main/app_main.c | 144 ----------------- examples/mqtt_ws/main/component.mk | 0 examples/mqtt_wss/CMakeLists.txt | 19 --- examples/mqtt_wss/Makefile | 13 -- examples/mqtt_wss/README.md | 5 - examples/mqtt_wss/main/Kconfig.projbuild | 15 -- examples/mqtt_wss/main/app_main.c | 148 ------------------ examples/mqtt_wss/main/component.mk | 1 - examples/mqtt_wss/main/iot_eclipse_org.pem | 27 ---- 27 files changed, 878 deletions(-) rename Kconfig => Kconfig.included (100%) delete mode 100644 examples/mqtt_ssl/CMakeLists.txt delete mode 100644 examples/mqtt_ssl/Makefile delete mode 100644 examples/mqtt_ssl/README.md delete mode 100644 examples/mqtt_ssl/main/Kconfig.projbuild delete mode 100755 examples/mqtt_ssl/main/app_main.c delete mode 100644 examples/mqtt_ssl/main/component.mk delete mode 100644 examples/mqtt_ssl/main/iot_eclipse_org.pem delete mode 100644 examples/mqtt_tcp/CMakeLists.txt delete mode 100644 examples/mqtt_tcp/Makefile delete mode 100644 examples/mqtt_tcp/README.md delete mode 100644 examples/mqtt_tcp/main/Kconfig.projbuild delete mode 100755 examples/mqtt_tcp/main/app_main.c delete mode 100644 examples/mqtt_tcp/main/component.mk delete mode 100644 examples/mqtt_ws/CMakeLists.txt delete mode 100644 examples/mqtt_ws/Makefile delete mode 100644 examples/mqtt_ws/README.md delete mode 100644 examples/mqtt_ws/main/Kconfig.projbuild delete mode 100755 examples/mqtt_ws/main/app_main.c delete mode 100644 examples/mqtt_ws/main/component.mk delete mode 100644 examples/mqtt_wss/CMakeLists.txt delete mode 100644 examples/mqtt_wss/Makefile delete mode 100644 examples/mqtt_wss/README.md delete mode 100644 examples/mqtt_wss/main/Kconfig.projbuild delete mode 100755 examples/mqtt_wss/main/app_main.c delete mode 100644 examples/mqtt_wss/main/component.mk delete mode 100644 examples/mqtt_wss/main/iot_eclipse_org.pem diff --git a/Kconfig b/Kconfig.included similarity index 100% rename from Kconfig rename to Kconfig.included diff --git a/examples/mqtt_ssl/CMakeLists.txt b/examples/mqtt_ssl/CMakeLists.txt deleted file mode 100644 index 0dd1242..0000000 --- a/examples/mqtt_ssl/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -cmake_minimum_required(VERSION 3.5) - -get_filename_component(DEV_ROOT "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE) - -set(PROJECT_ROOT "${DEV_ROOT}/") - -set(SUBMODULE_ROOT "${DEV_ROOT}/../../../") - -set(PROJECT_NAME "mqtt_ssl") - -include($ENV{IDF_PATH}/tools/cmake/project.cmake) - -set(MAIN_SRCS ${PROJECT_ROOT}/main/app_main.c) - -set(EXTRA_COMPONENT_DIRS "${EXTRA_COMPONENT_DIRS} ${SUBMODULE_ROOT}") -set(BUILD_COMPONENTS "${BUILD_COMPONENTS} espmqtt") - -project(${PROJECT_NAME}) - diff --git a/examples/mqtt_ssl/Makefile b/examples/mqtt_ssl/Makefile deleted file mode 100644 index 69e081a..0000000 --- a/examples/mqtt_ssl/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# -# This is a project Makefile. It is assumed the directory this Makefile resides in is a -# project subdirectory. -# -# -# This is a project Makefile. It is assumed the directory this Makefile resides in is a -# project subdirectory. -# -PROJECT_NAME := mqtt_ssl -EXTRA_COMPONENT_DIRS += $(PROJECT_PATH)/../../../ - -include $(IDF_PATH)/make/project.mk - diff --git a/examples/mqtt_ssl/README.md b/examples/mqtt_ssl/README.md deleted file mode 100644 index 9e55af5..0000000 --- a/examples/mqtt_ssl/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# ESPMQTT SSL Sample application - -Get iot.eclipse.org Certification - -`openssl s_client -showcerts -connect iot.eclipse.org:8883 /dev/null|openssl x509 -outform PEM >iot_eclipse_org.pem` diff --git a/examples/mqtt_ssl/main/Kconfig.projbuild b/examples/mqtt_ssl/main/Kconfig.projbuild deleted file mode 100644 index 1c9c2e6..0000000 --- a/examples/mqtt_ssl/main/Kconfig.projbuild +++ /dev/null @@ -1,15 +0,0 @@ -menu "MQTT Application sample" - -config WIFI_SSID - string "WiFi SSID" - default "myssid" - help - SSID (network name) for the example to connect to. - -config WIFI_PASSWORD - string "WiFi Password" - default "mypassword" - help - WiFi password (WPA or WPA2) for the example to use. - -endmenu diff --git a/examples/mqtt_ssl/main/app_main.c b/examples/mqtt_ssl/main/app_main.c deleted file mode 100755 index 6fcc312..0000000 --- a/examples/mqtt_ssl/main/app_main.c +++ /dev/null @@ -1,149 +0,0 @@ -#include -#include -#include -#include -#include "esp_wifi.h" -#include "esp_system.h" -#include "nvs_flash.h" -#include "esp_event_loop.h" - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" -#include "freertos/queue.h" -#include "freertos/event_groups.h" - -#include "lwip/sockets.h" -#include "lwip/dns.h" -#include "lwip/netdb.h" - -#include "esp_log.h" -#include "mqtt_client.h" - -static const char *TAG = "MQTTS_SAMPLE"; - -static EventGroupHandle_t wifi_event_group; -const static int CONNECTED_BIT = BIT0; - - - -static esp_err_t wifi_event_handler(void *ctx, system_event_t *event) -{ - switch (event->event_id) { - case SYSTEM_EVENT_STA_START: - esp_wifi_connect(); - break; - case SYSTEM_EVENT_STA_GOT_IP: - xEventGroupSetBits(wifi_event_group, CONNECTED_BIT); - - break; - case SYSTEM_EVENT_STA_DISCONNECTED: - esp_wifi_connect(); - xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); - break; - default: - break; - } - return ESP_OK; -} - -static void wifi_init(void) -{ - tcpip_adapter_init(); - wifi_event_group = xEventGroupCreate(); - ESP_ERROR_CHECK(esp_event_loop_init(wifi_event_handler, NULL)); - wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); - ESP_ERROR_CHECK(esp_wifi_init(&cfg)); - ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); - wifi_config_t wifi_config = { - .sta = { - .ssid = CONFIG_WIFI_SSID, - .password = CONFIG_WIFI_PASSWORD, - }, - }; - ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); - ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config)); - ESP_LOGI(TAG, "start the WIFI SSID:[%s] password:[%s]", CONFIG_WIFI_SSID, "******"); - ESP_ERROR_CHECK(esp_wifi_start()); - ESP_LOGI(TAG, "Waiting for wifi"); - xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY); -} - -extern const uint8_t iot_eclipse_org_pem_start[] asm("_binary_iot_eclipse_org_pem_start"); -extern const uint8_t iot_eclipse_org_pem_end[] asm("_binary_iot_eclipse_org_pem_end"); - -static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event) -{ - esp_mqtt_client_handle_t client = event->client; - int msg_id; - // your_context_t *context = event->context; - switch (event->event_id) { - case MQTT_EVENT_CONNECTED: - ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); - msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0); - ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); - - msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1); - ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); - - msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1"); - ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id); - break; - case MQTT_EVENT_DISCONNECTED: - ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); - break; - - case MQTT_EVENT_SUBSCRIBED: - ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); - msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0); - ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); - break; - case MQTT_EVENT_UNSUBSCRIBED: - ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); - break; - case MQTT_EVENT_PUBLISHED: - ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id); - break; - case MQTT_EVENT_DATA: - ESP_LOGI(TAG, "MQTT_EVENT_DATA"); - printf("TOPIC=%.*s\r\n", event->topic_len, event->topic); - printf("DATA=%.*s\r\n", event->data_len, event->data); - break; - case MQTT_EVENT_ERROR: - ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); - break; - } - return ESP_OK; -} - -static void mqtt_app_start(void) -{ - const esp_mqtt_client_config_t mqtt_cfg = { - .uri = "mqtts://iot.eclipse.org:8883", - .event_handle = mqtt_event_handler, - .cert_pem = (const char *)iot_eclipse_org_pem_start, - }; - - ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size()); - esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg); - esp_mqtt_client_start(client); -} - -void app_main() -{ - ESP_LOGI(TAG, "[APP] Startup.."); - ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size()); - ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version()); - - esp_log_level_set("*", ESP_LOG_INFO); - esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE); - esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE); - - nvs_flash_init(); - wifi_init(); - mqtt_app_start(); - -} diff --git a/examples/mqtt_ssl/main/component.mk b/examples/mqtt_ssl/main/component.mk deleted file mode 100644 index 797c4a1..0000000 --- a/examples/mqtt_ssl/main/component.mk +++ /dev/null @@ -1 +0,0 @@ -COMPONENT_EMBED_TXTFILES := iot_eclipse_org.pem diff --git a/examples/mqtt_ssl/main/iot_eclipse_org.pem b/examples/mqtt_ssl/main/iot_eclipse_org.pem deleted file mode 100644 index edb593b..0000000 --- a/examples/mqtt_ssl/main/iot_eclipse_org.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/ -MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT -DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow -SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT -GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF -q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8 -SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0 -Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA -a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj -/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T -AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG -CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv -bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k -c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw -VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC -ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz -MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu -Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF -AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo -uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/ -wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu -X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG -PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6 -KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg== ------END CERTIFICATE----- \ No newline at end of file diff --git a/examples/mqtt_tcp/CMakeLists.txt b/examples/mqtt_tcp/CMakeLists.txt deleted file mode 100644 index 384ac48..0000000 --- a/examples/mqtt_tcp/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -cmake_minimum_required(VERSION 3.5) - -get_filename_component(DEV_ROOT "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE) - -set(PROJECT_ROOT "${DEV_ROOT}/") - -set(SUBMODULE_ROOT "${DEV_ROOT}/../../../") - -set(PROJECT_NAME "mqtt_tcp") - -include($ENV{IDF_PATH}/tools/cmake/project.cmake) - -set(MAIN_SRCS ${PROJECT_ROOT}/main/app_main.c) - -set(EXTRA_COMPONENT_DIRS "${EXTRA_COMPONENT_DIRS} ${SUBMODULE_ROOT}") -set(BUILD_COMPONENTS "${BUILD_COMPONENTS} espmqtt") - -project(${PROJECT_NAME}) - diff --git a/examples/mqtt_tcp/Makefile b/examples/mqtt_tcp/Makefile deleted file mode 100644 index 43fd8ce..0000000 --- a/examples/mqtt_tcp/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# -# This is a project Makefile. It is assumed the directory this Makefile resides in is a -# project subdirectory. -# -# -# This is a project Makefile. It is assumed the directory this Makefile resides in is a -# project subdirectory. -# -PROJECT_NAME := mqtt_tcp -EXTRA_COMPONENT_DIRS += $(PROJECT_PATH)/../../../ - -include $(IDF_PATH)/make/project.mk - diff --git a/examples/mqtt_tcp/README.md b/examples/mqtt_tcp/README.md deleted file mode 100644 index 6362714..0000000 --- a/examples/mqtt_tcp/README.md +++ /dev/null @@ -1 +0,0 @@ -# ESPMQTT Sample application diff --git a/examples/mqtt_tcp/main/Kconfig.projbuild b/examples/mqtt_tcp/main/Kconfig.projbuild deleted file mode 100644 index c96a495..0000000 --- a/examples/mqtt_tcp/main/Kconfig.projbuild +++ /dev/null @@ -1,25 +0,0 @@ -menu "MQTT Application sample" - -config WIFI_SSID - string "WiFi SSID" - default "myssid" - help - SSID (network name) for the example to connect to. - -config WIFI_PASSWORD - string "WiFi Password" - default "mypassword" - help - WiFi password (WPA or WPA2) for the example to use. - -config BROKER_URL - string "Broker URL" - default "mqtt://iot.eclipse.org" - help - URL of the broker to connect to - -config BROKER_URL_FROM_STDIN - bool - default y if BROKER_URL = "FROM_STDIN" - -endmenu diff --git a/examples/mqtt_tcp/main/app_main.c b/examples/mqtt_tcp/main/app_main.c deleted file mode 100755 index f2c855b..0000000 --- a/examples/mqtt_tcp/main/app_main.c +++ /dev/null @@ -1,171 +0,0 @@ -#include -#include -#include -#include -#include "esp_wifi.h" -#include "esp_system.h" -#include "nvs_flash.h" -#include "esp_event_loop.h" - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" -#include "freertos/queue.h" -#include "freertos/event_groups.h" - -#include "lwip/sockets.h" -#include "lwip/dns.h" -#include "lwip/netdb.h" - -#include "esp_log.h" -#include "mqtt_client.h" - -static const char *TAG = "MQTT_SAMPLE"; - -static EventGroupHandle_t wifi_event_group; -const static int CONNECTED_BIT = BIT0; - - -static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event) -{ - esp_mqtt_client_handle_t client = event->client; - int msg_id; - // your_context_t *context = event->context; - switch (event->event_id) { - case MQTT_EVENT_CONNECTED: - ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); - msg_id = esp_mqtt_client_publish(client, "/topic/qos1", "data_3", 0, 1, 0); - ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); - - msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0); - ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); - - msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1); - ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); - - msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1"); - ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id); - break; - case MQTT_EVENT_DISCONNECTED: - ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); - break; - - case MQTT_EVENT_SUBSCRIBED: - ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); - msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0); - ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); - break; - case MQTT_EVENT_UNSUBSCRIBED: - ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); - break; - case MQTT_EVENT_PUBLISHED: - ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id); - break; - case MQTT_EVENT_DATA: - ESP_LOGI(TAG, "MQTT_EVENT_DATA"); - printf("TOPIC=%.*s\r\n", event->topic_len, event->topic); - printf("DATA=%.*s\r\n", event->data_len, event->data); - break; - case MQTT_EVENT_ERROR: - ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); - break; - } - return ESP_OK; -} - -static esp_err_t wifi_event_handler(void *ctx, system_event_t *event) -{ - switch (event->event_id) { - case SYSTEM_EVENT_STA_START: - esp_wifi_connect(); - break; - case SYSTEM_EVENT_STA_GOT_IP: - xEventGroupSetBits(wifi_event_group, CONNECTED_BIT); - - break; - case SYSTEM_EVENT_STA_DISCONNECTED: - esp_wifi_connect(); - xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); - break; - default: - break; - } - return ESP_OK; -} - -static void wifi_init(void) -{ - tcpip_adapter_init(); - wifi_event_group = xEventGroupCreate(); - ESP_ERROR_CHECK(esp_event_loop_init(wifi_event_handler, NULL)); - wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); - ESP_ERROR_CHECK(esp_wifi_init(&cfg)); - ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); - wifi_config_t wifi_config = { - .sta = { - .ssid = CONFIG_WIFI_SSID, - .password = CONFIG_WIFI_PASSWORD, - }, - }; - ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); - ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config)); - ESP_LOGI(TAG, "start the WIFI SSID:[%s] password:[%s]", CONFIG_WIFI_SSID, "******"); - ESP_ERROR_CHECK(esp_wifi_start()); - ESP_LOGI(TAG, "Waiting for wifi"); - xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY); -} - -static void mqtt_app_start(void) -{ - esp_mqtt_client_config_t mqtt_cfg = { - .uri = CONFIG_BROKER_URL, - .event_handle = mqtt_event_handler, - // .user_context = (void *)your_context - }; - -#if CONFIG_BROKER_URL_FROM_STDIN - char line[128]; - - if (strcmp(mqtt_cfg.uri, "FROM_STDIN") == 0) { - int count = 0; - printf("Please enter url of mqtt broker\n"); - while (count < 128) { - int c = fgetc(stdin); - if (c == '\n') { - line[count] = '\0'; - break; - } else if (c > 0 && c < 127) { - line[count] = c; - ++count; - } - vTaskDelay(10 / portTICK_PERIOD_MS); - } - mqtt_cfg.uri = line; - printf("Broker url: %s\n", line); - } else { - ESP_LOGE(TAG, "Configuration mismatch: wrong broker url"); - abort(); - } -#endif /* CONFIG_BROKER_URL_FROM_STDIN */ - - esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg); - esp_mqtt_client_start(client); -} - -void app_main() -{ - ESP_LOGI(TAG, "[APP] Startup.."); - ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size()); - ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version()); - - esp_log_level_set("*", ESP_LOG_INFO); - esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE); - esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE); - - nvs_flash_init(); - wifi_init(); - mqtt_app_start(); -} diff --git a/examples/mqtt_tcp/main/component.mk b/examples/mqtt_tcp/main/component.mk deleted file mode 100644 index e69de29..0000000 diff --git a/examples/mqtt_ws/CMakeLists.txt b/examples/mqtt_ws/CMakeLists.txt deleted file mode 100644 index 39cf967..0000000 --- a/examples/mqtt_ws/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -cmake_minimum_required(VERSION 3.5) - -get_filename_component(DEV_ROOT "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE) - -set(PROJECT_ROOT "${DEV_ROOT}/") - -set(SUBMODULE_ROOT "${DEV_ROOT}/../../../") - -set(PROJECT_NAME "mqtt_ws") - -include($ENV{IDF_PATH}/tools/cmake/project.cmake) - -set(MAIN_SRCS ${PROJECT_ROOT}/main/app_main.c) - -set(EXTRA_COMPONENT_DIRS "${EXTRA_COMPONENT_DIRS} ${SUBMODULE_ROOT}") -set(BUILD_COMPONENTS "${BUILD_COMPONENTS} espmqtt") - -project(${PROJECT_NAME}) - diff --git a/examples/mqtt_ws/Makefile b/examples/mqtt_ws/Makefile deleted file mode 100644 index 003aff4..0000000 --- a/examples/mqtt_ws/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# -# This is a project Makefile. It is assumed the directory this Makefile resides in is a -# project subdirectory. -# -# -# This is a project Makefile. It is assumed the directory this Makefile resides in is a -# project subdirectory. -# -PROJECT_NAME := mqtt_ws -EXTRA_COMPONENT_DIRS += $(PROJECT_PATH)/../../../ - -include $(IDF_PATH)/make/project.mk - diff --git a/examples/mqtt_ws/README.md b/examples/mqtt_ws/README.md deleted file mode 100644 index 3f71327..0000000 --- a/examples/mqtt_ws/README.md +++ /dev/null @@ -1 +0,0 @@ -# ESPMQTT MQTT over Websocket diff --git a/examples/mqtt_ws/main/Kconfig.projbuild b/examples/mqtt_ws/main/Kconfig.projbuild deleted file mode 100644 index 1c9c2e6..0000000 --- a/examples/mqtt_ws/main/Kconfig.projbuild +++ /dev/null @@ -1,15 +0,0 @@ -menu "MQTT Application sample" - -config WIFI_SSID - string "WiFi SSID" - default "myssid" - help - SSID (network name) for the example to connect to. - -config WIFI_PASSWORD - string "WiFi Password" - default "mypassword" - help - WiFi password (WPA or WPA2) for the example to use. - -endmenu diff --git a/examples/mqtt_ws/main/app_main.c b/examples/mqtt_ws/main/app_main.c deleted file mode 100755 index c9c65a5..0000000 --- a/examples/mqtt_ws/main/app_main.c +++ /dev/null @@ -1,144 +0,0 @@ -#include -#include -#include -#include -#include "esp_wifi.h" -#include "esp_system.h" -#include "nvs_flash.h" -#include "esp_event_loop.h" - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" -#include "freertos/queue.h" -#include "freertos/event_groups.h" - -#include "lwip/sockets.h" -#include "lwip/dns.h" -#include "lwip/netdb.h" - -#include "esp_log.h" -#include "mqtt_client.h" - -static const char *TAG = "MQTTWS_SAMPLE"; - -static EventGroupHandle_t wifi_event_group; -const static int CONNECTED_BIT = BIT0; - - -static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event) -{ - esp_mqtt_client_handle_t client = event->client; - int msg_id; - // your_context_t *context = event->context; - switch (event->event_id) { - case MQTT_EVENT_CONNECTED: - ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); - msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0); - ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); - - msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1); - ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); - - msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1"); - ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id); - break; - case MQTT_EVENT_DISCONNECTED: - ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); - break; - - case MQTT_EVENT_SUBSCRIBED: - ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); - msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0); - ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); - break; - case MQTT_EVENT_UNSUBSCRIBED: - ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); - break; - case MQTT_EVENT_PUBLISHED: - ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id); - break; - case MQTT_EVENT_DATA: - ESP_LOGI(TAG, "MQTT_EVENT_DATA"); - printf("TOPIC=%.*s\r\n", event->topic_len, event->topic); - printf("DATA=%.*s\r\n", event->data_len, event->data); - break; - case MQTT_EVENT_ERROR: - ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); - break; - } - return ESP_OK; -} - -static esp_err_t wifi_event_handler(void *ctx, system_event_t *event) -{ - switch (event->event_id) { - case SYSTEM_EVENT_STA_START: - esp_wifi_connect(); - break; - case SYSTEM_EVENT_STA_GOT_IP: - xEventGroupSetBits(wifi_event_group, CONNECTED_BIT); - - break; - case SYSTEM_EVENT_STA_DISCONNECTED: - esp_wifi_connect(); - xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); - break; - default: - break; - } - return ESP_OK; -} - -static void wifi_init(void) -{ - tcpip_adapter_init(); - wifi_event_group = xEventGroupCreate(); - ESP_ERROR_CHECK(esp_event_loop_init(wifi_event_handler, NULL)); - wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); - ESP_ERROR_CHECK(esp_wifi_init(&cfg)); - ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); - wifi_config_t wifi_config = { - .sta = { - .ssid = CONFIG_WIFI_SSID, - .password = CONFIG_WIFI_PASSWORD, - }, - }; - ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); - ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config)); - ESP_LOGI(TAG, "start the WIFI SSID:[%s] password:[%s]", CONFIG_WIFI_SSID, "******"); - ESP_ERROR_CHECK(esp_wifi_start()); - ESP_LOGI(TAG, "Waiting for wifi"); - xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY); -} - -static void mqtt_app_start(void) -{ - const esp_mqtt_client_config_t mqtt_cfg = { - .uri = "ws://iot.eclipse.org:80/ws", - .event_handle = mqtt_event_handler, - // .user_context = (void *)your_context - }; - - esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg); - esp_mqtt_client_start(client); -} - -void app_main() -{ - ESP_LOGI(TAG, "[APP] Startup.."); - ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size()); - ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version()); - - esp_log_level_set("*", ESP_LOG_INFO); - esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_WS", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE); - esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE); - - nvs_flash_init(); - wifi_init(); - mqtt_app_start(); -} diff --git a/examples/mqtt_ws/main/component.mk b/examples/mqtt_ws/main/component.mk deleted file mode 100644 index e69de29..0000000 diff --git a/examples/mqtt_wss/CMakeLists.txt b/examples/mqtt_wss/CMakeLists.txt deleted file mode 100644 index a8e668a..0000000 --- a/examples/mqtt_wss/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -cmake_minimum_required(VERSION 3.5) - -get_filename_component(DEV_ROOT "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE) - -set(PROJECT_ROOT "${DEV_ROOT}/") - -set(SUBMODULE_ROOT "${DEV_ROOT}/../../../") - -set(PROJECT_NAME "mqtt_wss") - -include($ENV{IDF_PATH}/tools/cmake/project.cmake) - -set(MAIN_SRCS ${PROJECT_ROOT}/main/app_main.c) - -set(EXTRA_COMPONENT_DIRS "${EXTRA_COMPONENT_DIRS} ${SUBMODULE_ROOT}") -set(BUILD_COMPONENTS "${BUILD_COMPONENTS} espmqtt") - -project(${PROJECT_NAME}) - diff --git a/examples/mqtt_wss/Makefile b/examples/mqtt_wss/Makefile deleted file mode 100644 index 2b3dcda..0000000 --- a/examples/mqtt_wss/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# -# This is a project Makefile. It is assumed the directory this Makefile resides in is a -# project subdirectory. -# -# -# This is a project Makefile. It is assumed the directory this Makefile resides in is a -# project subdirectory. -# -PROJECT_NAME := mqtt_wss -EXTRA_COMPONENT_DIRS += $(PROJECT_PATH)/../../../ - -include $(IDF_PATH)/make/project.mk - diff --git a/examples/mqtt_wss/README.md b/examples/mqtt_wss/README.md deleted file mode 100644 index 561456f..0000000 --- a/examples/mqtt_wss/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# ESPMQTT MQTT over WSS Sample application - -Get iot.eclipse.org Certification - -`openssl s_client -showcerts -connect iot.eclipse.org:8883 /dev/null|openssl x509 -outform PEM >iot_eclipse_org.pem` diff --git a/examples/mqtt_wss/main/Kconfig.projbuild b/examples/mqtt_wss/main/Kconfig.projbuild deleted file mode 100644 index 1c9c2e6..0000000 --- a/examples/mqtt_wss/main/Kconfig.projbuild +++ /dev/null @@ -1,15 +0,0 @@ -menu "MQTT Application sample" - -config WIFI_SSID - string "WiFi SSID" - default "myssid" - help - SSID (network name) for the example to connect to. - -config WIFI_PASSWORD - string "WiFi Password" - default "mypassword" - help - WiFi password (WPA or WPA2) for the example to use. - -endmenu diff --git a/examples/mqtt_wss/main/app_main.c b/examples/mqtt_wss/main/app_main.c deleted file mode 100755 index ce4104c..0000000 --- a/examples/mqtt_wss/main/app_main.c +++ /dev/null @@ -1,148 +0,0 @@ -#include -#include -#include -#include -#include "esp_wifi.h" -#include "esp_system.h" -#include "nvs_flash.h" -#include "esp_event_loop.h" - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" -#include "freertos/queue.h" -#include "freertos/event_groups.h" - -#include "lwip/sockets.h" -#include "lwip/dns.h" -#include "lwip/netdb.h" - -#include "esp_log.h" -#include "mqtt_client.h" - -static const char *TAG = "MQTTWSS_SAMPLE"; - -static EventGroupHandle_t wifi_event_group; -const static int CONNECTED_BIT = BIT0; - - - -static esp_err_t wifi_event_handler(void *ctx, system_event_t *event) -{ - switch (event->event_id) { - case SYSTEM_EVENT_STA_START: - esp_wifi_connect(); - break; - case SYSTEM_EVENT_STA_GOT_IP: - xEventGroupSetBits(wifi_event_group, CONNECTED_BIT); - - break; - case SYSTEM_EVENT_STA_DISCONNECTED: - esp_wifi_connect(); - xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); - break; - default: - break; - } - return ESP_OK; -} - -static void wifi_init(void) -{ - tcpip_adapter_init(); - wifi_event_group = xEventGroupCreate(); - ESP_ERROR_CHECK(esp_event_loop_init(wifi_event_handler, NULL)); - wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); - ESP_ERROR_CHECK(esp_wifi_init(&cfg)); - ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); - wifi_config_t wifi_config = { - .sta = { - .ssid = CONFIG_WIFI_SSID, - .password = CONFIG_WIFI_PASSWORD, - }, - }; - ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); - ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config)); - ESP_LOGI(TAG, "start the WIFI SSID:[%s] password:[%s]", CONFIG_WIFI_SSID, "******"); - ESP_ERROR_CHECK(esp_wifi_start()); - ESP_LOGI(TAG, "Waiting for wifi"); - xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY); -} - -extern const uint8_t iot_eclipse_org_pem_start[] asm("_binary_iot_eclipse_org_pem_start"); -extern const uint8_t iot_eclipse_org_pem_end[] asm("_binary_iot_eclipse_org_pem_end"); - -static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event) -{ - esp_mqtt_client_handle_t client = event->client; - int msg_id; - // your_context_t *context = event->context; - switch (event->event_id) { - case MQTT_EVENT_CONNECTED: - ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); - msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0); - ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); - - msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1); - ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); - - msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1"); - ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id); - break; - case MQTT_EVENT_DISCONNECTED: - ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); - break; - - case MQTT_EVENT_SUBSCRIBED: - ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); - msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0); - ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); - break; - case MQTT_EVENT_UNSUBSCRIBED: - ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); - break; - case MQTT_EVENT_PUBLISHED: - ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id); - break; - case MQTT_EVENT_DATA: - ESP_LOGI(TAG, "MQTT_EVENT_DATA"); - printf("TOPIC=%.*s\r\n", event->topic_len, event->topic); - printf("DATA=%.*s\r\n", event->data_len, event->data); - break; - case MQTT_EVENT_ERROR: - ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); - break; - } - return ESP_OK; -} - -static void mqtt_app_start(void) -{ - const esp_mqtt_client_config_t mqtt_cfg = { - .uri = "wss://iot.eclipse.org:443/ws", - .event_handle = mqtt_event_handler, - .cert_pem = (const char *)iot_eclipse_org_pem_start, - }; - - ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size()); - esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg); - esp_mqtt_client_start(client); -} - -void app_main() -{ - ESP_LOGI(TAG, "[APP] Startup.."); - ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size()); - ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version()); - - esp_log_level_set("*", ESP_LOG_INFO); - esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE); - esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE); - esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE); - - nvs_flash_init(); - wifi_init(); - mqtt_app_start(); -} diff --git a/examples/mqtt_wss/main/component.mk b/examples/mqtt_wss/main/component.mk deleted file mode 100644 index 797c4a1..0000000 --- a/examples/mqtt_wss/main/component.mk +++ /dev/null @@ -1 +0,0 @@ -COMPONENT_EMBED_TXTFILES := iot_eclipse_org.pem diff --git a/examples/mqtt_wss/main/iot_eclipse_org.pem b/examples/mqtt_wss/main/iot_eclipse_org.pem deleted file mode 100644 index edb593b..0000000 --- a/examples/mqtt_wss/main/iot_eclipse_org.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/ -MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT -DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow -SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT -GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF -q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8 -SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0 -Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA -a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj -/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T -AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG -CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv -bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k -c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw -VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC -ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz -MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu -Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF -AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo -uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/ -wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu -X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG -PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6 -KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg== ------END CERTIFICATE----- \ No newline at end of file From bcb38e45f521085f997439a8b6c4ead34dff9043 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 13 Sep 2018 11:33:52 +0200 Subject: [PATCH 06/56] deleted Kconfig as this is used as component in esp-idf --- Kconfig.included | 102 ----------------------------------------------- 1 file changed, 102 deletions(-) delete mode 100644 Kconfig.included diff --git a/Kconfig.included b/Kconfig.included deleted file mode 100644 index 323cc39..0000000 --- a/Kconfig.included +++ /dev/null @@ -1,102 +0,0 @@ -menu "ESP-MQTT Configurations" - -config MQTT_PROTOCOL_311 - bool "Enable MQTT protocol 3.1.1" - default y - help - If not, this library will use MQTT protocol 3.1 - -config MQTT_TRANSPORT_SSL - bool "Enable MQTT over SSL" - default y - help - Enable MQTT transport over SSL with mbedtls - -config MQTT_TRANSPORT_WEBSOCKET - bool "Enable MQTT over Websocket" - default y - help - Enable MQTT transport over Websocket. - -config MQTT_TRANSPORT_WEBSOCKET_SECURE - bool "Enable MQTT over Websocket Secure" - default y - depends on MQTT_TRANSPORT_WEBSOCKET - depends on MQTT_TRANSPORT_SSL - help - Enable MQTT transport over Websocket Secure. - -config MQTT_USE_CUSTOM_CONFIG - bool "MQTT Using custom configurations" - default n - help - Custom MQTT configurations. - -config MQTT_TCP_DEFAULT_PORT - int "Default MQTT over TCP port" - default 1883 - depends on MQTT_USE_CUSTOM_CONFIG - help - Default MQTT over TCP port - -config MQTT_SSL_DEFAULT_PORT - int "Default MQTT over SSL port" - default 8883 - depends on MQTT_USE_CUSTOM_CONFIG - depends on MQTT_TRANSPORT_SSL - help - Default MQTT over SSL port - -config MQTT_WS_DEFAULT_PORT - int "Default MQTT over Websocket port" - default 80 - depends on MQTT_USE_CUSTOM_CONFIG - depends on MQTT_TRANSPORT_WEBSOCKET - help - Default MQTT over Websocket port - -config MQTT_WSS_DEFAULT_PORT - int "Default MQTT over Websocket Secure port" - default 443 - depends on MQTT_USE_CUSTOM_CONFIG - depends on MQTT_TRANSPORT_WEBSOCKET - depends on MQTT_TRANSPORT_WEBSOCKET_SECURE - help - Default MQTT over Websocket Secure port - -config MQTT_BUFFER_SIZE - int "Default MQTT Buffer Size" - default 1024 - depends on MQTT_USE_CUSTOM_CONFIG - help - This buffer size using for both transmit and receive - -config MQTT_TASK_STACK_SIZE - int "MQTT task stack size" - default 6144 - depends on MQTT_USE_CUSTOM_CONFIG - help - MQTT task stack size - -config MQTT_TASK_CORE_SELECTION_ENABLED - bool "Enable MQTT task core selection" - default false - help - This will enable core selection - -choice - depends on MQTT_TASK_CORE_SELECTION_ENABLED - prompt "Core to use ?" - config MQTT_USE_CORE_0 - bool "Core 0" - config MQTT_USE_CORE_1 - bool "Core 1" - endchoice - -config MQTT_CUSTOM_OUTBOX - bool "Enable custom outbox implementation" - default n - help - Set to true if a specific implementation of message outbox is needed (e.g. persistant outbox in NVM or similar). - -endmenu From cbeaf67fe39e1ab557e111c36f8e5a422ad49621 Mon Sep 17 00:00:00 2001 From: Jitin George Date: Tue, 18 Sep 2018 17:49:41 +0530 Subject: [PATCH 07/56] esp-mqtt: Add support for modified transport_set_func() API from esp-idf/component/tcp_transport --- lib/transport_ws.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/transport_ws.c b/lib/transport_ws.c index df880ca..5164414 100644 --- a/lib/transport_ws.c +++ b/lib/transport_ws.c @@ -256,7 +256,7 @@ transport_handle_t transport_ws_init(transport_handle_t parent_handle) return NULL; }); - transport_set_func(t, ws_connect, ws_read, ws_write, ws_close, ws_poll_read, ws_poll_write, ws_destroy, ws_transport_get_payload_transport_handle); + transport_set_func(t, ws_connect, ws_read, ws_write, ws_close, ws_poll_read, ws_poll_write, ws_destroy, NULL, ws_transport_get_payload_transport_handle); transport_set_context_data(t, ws); return t; } From 61f411c1f97e15da45617c1b71ca5dbc4e396510 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 24 Sep 2018 13:25:04 +0800 Subject: [PATCH 08/56] Revert "Merge branch 'feature/idf_transport_API_change' into 'idf'" This reverts merge request !3 --- lib/transport_ws.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/transport_ws.c b/lib/transport_ws.c index 5164414..df880ca 100644 --- a/lib/transport_ws.c +++ b/lib/transport_ws.c @@ -256,7 +256,7 @@ transport_handle_t transport_ws_init(transport_handle_t parent_handle) return NULL; }); - transport_set_func(t, ws_connect, ws_read, ws_write, ws_close, ws_poll_read, ws_poll_write, ws_destroy, NULL, ws_transport_get_payload_transport_handle); + transport_set_func(t, ws_connect, ws_read, ws_write, ws_close, ws_poll_read, ws_poll_write, ws_destroy, ws_transport_get_payload_transport_handle); transport_set_context_data(t, ws); return t; } From d344f928ca9fe43bd80603695bb5d9748884b3b9 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 25 Sep 2018 10:29:43 +0200 Subject: [PATCH 09/56] transport: renamed transport headers to avoid compilation collisions --- lib/include/transport_ws.h | 46 ------- lib/transport_ws.c | 263 ------------------------------------- mqtt_client.c | 8 +- 3 files changed, 4 insertions(+), 313 deletions(-) delete mode 100644 lib/include/transport_ws.h delete mode 100644 lib/transport_ws.c diff --git a/lib/include/transport_ws.h b/lib/include/transport_ws.h deleted file mode 100644 index 7393088..0000000 --- a/lib/include/transport_ws.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * This file is subject to the terms and conditions defined in - * file 'LICENSE', which is part of this source code package. - * Tuan PM - */ - -#ifndef _TRANSPORT_WS_H_ -#define _TRANSPORT_WS_H_ - -#include "transport.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define WS_FIN 0x80 -#define WS_OPCODE_TEXT 0x01 -#define WS_OPCODE_BINARY 0x02 -#define WS_OPCODE_CLOSE 0x08 -#define WS_OPCODE_PING 0x09 -#define WS_OPCODE_PONG 0x0a -// Second byte -#define WS_MASK 0x80 -#define WS_SIZE16 126 -#define WS_SIZE64 127 -#define MAX_WEBSOCKET_HEADER_SIZE 10 -#define WS_RESPONSE_OK 101 - -/** - * @brief Create TCP transport - * - * @return - * - transport - * - NULL - */ -transport_handle_t transport_ws_init(transport_handle_t parent_handle); - -void transport_ws_set_path(transport_handle_t t, const char *path); - - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/transport_ws.c b/lib/transport_ws.c deleted file mode 100644 index df880ca..0000000 --- a/lib/transport_ws.c +++ /dev/null @@ -1,263 +0,0 @@ -#include -#include -#include - -#include "platform.h" -#include "transport.h" -#include "transport_tcp.h" -#include "transport_ws.h" -#include "mbedtls/base64.h" -#include "mbedtls/sha1.h" - -static const char *TAG = "TRANSPORT_WS"; - -#define DEFAULT_WS_BUFFER (1024) - -typedef struct { - char *path; - char *buffer; - transport_handle_t parent; -} transport_ws_t; - -transport_handle_t ws_transport_get_payload_transport_handle(transport_handle_t t) -{ - transport_ws_t *ws = transport_get_context_data(t); - return ws->parent; -} - -static char *trimwhitespace(const char *str) -{ - char *end; - - // Trim leading space - while (isspace((unsigned char)*str)) str++; - - if (*str == 0) { - return (char *)str; - } - - // Trim trailing space - end = (char *)(str + strlen(str) - 1); - while (end > str && isspace((unsigned char)*end)) end--; - - // Write new null terminator - *(end + 1) = 0; - - return (char *)str; -} - - -static char *get_http_header(const char *buffer, const char *key) -{ - char *found = strstr(buffer, key); - if (found) { - found += strlen(key); - char *found_end = strstr(found, "\r\n"); - if (found_end) { - found_end[0] = 0;//terminal string - - return trimwhitespace(found); - } - } - return NULL; -} - -static int ws_connect(transport_handle_t t, const char *host, int port, int timeout_ms) -{ - transport_ws_t *ws = transport_get_context_data(t); - if (transport_connect(ws->parent, host, port, timeout_ms) < 0) { - ESP_LOGE(TAG, "Error connect to ther server"); - } - unsigned char random_key[16] = { 0 }, client_key[32] = {0}; - int i; - for (i = 0; i < sizeof(random_key); i++) { - random_key[i] = rand() & 0xFF; - } - size_t outlen = 0; - mbedtls_base64_encode(client_key, 32, &outlen, random_key, 16); - int len = snprintf(ws->buffer, DEFAULT_WS_BUFFER, - "GET %s HTTP/1.1\r\n" - "Connection: Upgrade\r\n" - "Host: %s:%d\r\n" - "Upgrade: websocket\r\n" - "Sec-WebSocket-Version: 13\r\n" - "Sec-WebSocket-Protocol: mqtt\r\n" - "Sec-WebSocket-Key: %s\r\n" - "User-Agent: ESP32 MQTT Client\r\n\r\n", - ws->path, - host, port, - client_key); - ESP_LOGD(TAG, "Write upgrate request\r\n%s", ws->buffer); - if (transport_write(ws->parent, ws->buffer, len, timeout_ms) <= 0) { - ESP_LOGE(TAG, "Error write Upgrade header %s", ws->buffer); - return -1; - } - if ((len = transport_read(ws->parent, ws->buffer, DEFAULT_WS_BUFFER, timeout_ms)) <= 0) { - ESP_LOGE(TAG, "Error read response for Upgrade header %s", ws->buffer); - return -1; - } - char *server_key = get_http_header(ws->buffer, "Sec-WebSocket-Accept:"); - if (server_key == NULL) { - ESP_LOGE(TAG, "Sec-WebSocket-Accept not found"); - return -1; - } - - unsigned char client_key_b64[64], valid_client_key[20], accept_key[32] = {0}; - int key_len = sprintf((char*)client_key_b64, "%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11", (char*)client_key); - mbedtls_sha1_ret(client_key_b64, (size_t)key_len, valid_client_key); - mbedtls_base64_encode(accept_key, 32, &outlen, valid_client_key, 20); - accept_key[outlen] = 0; - ESP_LOGD(TAG, "server key=%s, send_key=%s, accept_key=%s", (char *)server_key, (char*)client_key, accept_key); - if (strcmp((char*)accept_key, (char*)server_key) != 0) { - ESP_LOGE(TAG, "Invalid websocket key"); - return -1; - } - return 0; -} - -static int ws_write(transport_handle_t t, const char *buff, int len, int timeout_ms) -{ - transport_ws_t *ws = transport_get_context_data(t); - char ws_header[MAX_WEBSOCKET_HEADER_SIZE]; - char *mask; - int header_len = 0, i; - char *buffer = (char *)buff; - int poll_write; - if ((poll_write = transport_poll_write(ws->parent, timeout_ms)) <= 0) { - return poll_write; - } - - ws_header[header_len++] = WS_OPCODE_BINARY | WS_FIN; - - // NOTE: no support for > 16-bit sized messages - if (len > 125) { - ws_header[header_len++] = WS_SIZE16 | WS_MASK; - ws_header[header_len++] = (uint8_t)(len >> 8); - ws_header[header_len++] = (uint8_t)(len & 0xFF); - } else { - ws_header[header_len++] = (uint8_t)(len | WS_MASK); - } - mask = &ws_header[header_len]; - ws_header[header_len++] = rand() & 0xFF; - ws_header[header_len++] = rand() & 0xFF; - ws_header[header_len++] = rand() & 0xFF; - ws_header[header_len++] = rand() & 0xFF; - - for (i = 0; i < len; ++i) { - buffer[i] = (buffer[i] ^ mask[i % 4]); - } - if (transport_write(ws->parent, ws_header, header_len, timeout_ms) != header_len) { - ESP_LOGE(TAG, "Error write header"); - return -1; - } - return transport_write(ws->parent, buffer, len, timeout_ms); -} - -static int ws_read(transport_handle_t t, char *buffer, int len, int timeout_ms) -{ - transport_ws_t *ws = transport_get_context_data(t); - int payload_len; - int payload_len_buff = len; - char *data_ptr = buffer, opcode, mask, *mask_key = NULL; - int rlen; - int poll_read; - if ((poll_read = transport_poll_read(ws->parent, timeout_ms)) <= 0) { - return poll_read; - } - if ((rlen = transport_read(ws->parent, buffer, len, timeout_ms)) <= 0) { - ESP_LOGE(TAG, "Error read data"); - return rlen; - } - opcode = (*data_ptr & 0x0F); - data_ptr ++; - mask = ((*data_ptr >> 7) & 0x01); - payload_len = (*data_ptr & 0x7F); - data_ptr++; - ESP_LOGD(TAG, "Opcode: %d, mask: %d, len: %d\r\n", opcode, mask, payload_len); - if (payload_len == 126) { - // headerLen += 2; - payload_len = data_ptr[0] << 8 | data_ptr[1]; - payload_len_buff = len - 4; - data_ptr += 2; - } else if (payload_len == 127) { - // headerLen += 8; - - if (data_ptr[0] != 0 || data_ptr[1] != 0 || data_ptr[2] != 0 || data_ptr[3] != 0) { - // really too big! - payload_len = 0xFFFFFFFF; - } else { - payload_len = data_ptr[4] << 24 | data_ptr[5] << 16 | data_ptr[6] << 8 | data_ptr[7]; - } - data_ptr += 8; - payload_len_buff = len - 10; - } - if (payload_len > payload_len_buff) { - ESP_LOGD(TAG, "Actual data received (%d) are longer than mqtt buffer (%d)", payload_len, payload_len_buff); - payload_len = payload_len_buff; - } - - if (mask) { - mask_key = data_ptr; - data_ptr += 4; - for (int i = 0; i < payload_len; i++) { - buffer[i] = (data_ptr[i] ^ mask_key[i % 4]); - } - } else { - memmove(buffer, data_ptr, payload_len); - } - return payload_len; -} - -static int ws_poll_read(transport_handle_t t, int timeout_ms) -{ - transport_ws_t *ws = transport_get_context_data(t); - return transport_poll_read(ws->parent, timeout_ms); -} - -static int ws_poll_write(transport_handle_t t, int timeout_ms) -{ - transport_ws_t *ws = transport_get_context_data(t); - return transport_poll_write(ws->parent, timeout_ms);; -} - -static int ws_close(transport_handle_t t) -{ - transport_ws_t *ws = transport_get_context_data(t); - return transport_close(ws->parent); -} - -static esp_err_t ws_destroy(transport_handle_t t) -{ - transport_ws_t *ws = transport_get_context_data(t); - free(ws->buffer); - free(ws->path); - free(ws); - return 0; -} -void transport_ws_set_path(transport_handle_t t, const char *path) -{ - transport_ws_t *ws = transport_get_context_data(t); - ws->path = realloc(ws->path, strlen(path) + 1); - strcpy(ws->path, path); -} -transport_handle_t transport_ws_init(transport_handle_t parent_handle) -{ - transport_handle_t t = transport_init(); - transport_ws_t *ws = calloc(1, sizeof(transport_ws_t)); - ESP_MEM_CHECK(TAG, ws, return NULL); - ws->parent = parent_handle; - - ws->path = strdup("/"); - ESP_MEM_CHECK(TAG, ws->path, return NULL); - ws->buffer = malloc(DEFAULT_WS_BUFFER); - ESP_MEM_CHECK(TAG, ws->buffer, { - free(ws->path); - free(ws); - return NULL; - }); - - transport_set_func(t, ws_connect, ws_read, ws_write, ws_close, ws_poll_read, ws_poll_write, ws_destroy, ws_transport_get_payload_transport_handle); - transport_set_context_data(t, ws); - return t; -} - diff --git a/mqtt_client.c b/mqtt_client.c index e73aa0c..ca785dc 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -3,10 +3,10 @@ #include "mqtt_client.h" #include "mqtt_msg.h" -#include "transport.h" -#include "transport_tcp.h" -#include "transport_ssl.h" -#include "transport_ws.h" +#include "esp_transport.h" +#include "esp_transport_tcp.h" +#include "esp_transport_ssl.h" +#include "esp_transport_ws.h" #include "platform.h" #include "mqtt_outbox.h" From 85ee406d03fd84f5613c6dead1ea653e384b9559 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 26 Sep 2018 11:53:54 +0200 Subject: [PATCH 10/56] tcp_transport: renamed possibly generic function names to be esp_ prefixed and not to colide with user namespace --- mqtt_client.c | 68 +++++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/mqtt_client.c b/mqtt_client.c index ca785dc..253b137 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -55,8 +55,8 @@ typedef enum { } mqtt_client_state_t; struct esp_mqtt_client { - transport_list_handle_t transport_list; - transport_handle_t transport; + esp_transport_list_handle_t transport_list; + esp_transport_handle_t transport; mqtt_config_storage_t *config; mqtt_state_t mqtt_state; mqtt_connect_info_t connect_info; @@ -204,7 +204,7 @@ static esp_err_t esp_mqtt_connect(esp_mqtt_client_handle_t client, int timeout_m client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id); - write_len = transport_write(client->transport, + write_len = esp_transport_write(client->transport, (char *)client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length, client->config->network_timeout_ms); @@ -212,7 +212,7 @@ static esp_err_t esp_mqtt_connect(esp_mqtt_client_handle_t client, int timeout_m ESP_LOGE(TAG, "Writing failed, errno= %d", errno); return ESP_FAIL; } - read_len = transport_read(client->transport, + read_len = esp_transport_read(client->transport, (char *)client->mqtt_state.in_buffer, client->mqtt_state.outbound_message->length, client->config->network_timeout_ms); @@ -251,7 +251,7 @@ static esp_err_t esp_mqtt_connect(esp_mqtt_client_handle_t client, int timeout_m static esp_err_t esp_mqtt_abort_connection(esp_mqtt_client_handle_t client) { - transport_close(client->transport); + esp_transport_close(client->transport); client->wait_timeout_ms = MQTT_RECONNECT_TIMEOUT_MS; client->reconnect_tick = platform_tick_get_ms(); client->state = MQTT_STATE_WAIT_TIMEOUT; @@ -269,23 +269,23 @@ esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *co esp_mqtt_set_config(client, config); - client->transport_list = transport_list_init(); + client->transport_list = esp_transport_list_init(); ESP_MEM_CHECK(TAG, client->transport_list, goto _mqtt_init_failed); - transport_handle_t tcp = transport_tcp_init(); + esp_transport_handle_t tcp = esp_transport_tcp_init(); ESP_MEM_CHECK(TAG, tcp, goto _mqtt_init_failed); - transport_set_default_port(tcp, MQTT_TCP_DEFAULT_PORT); - transport_list_add(client->transport_list, tcp, "mqtt"); + esp_transport_set_default_port(tcp, MQTT_TCP_DEFAULT_PORT); + esp_transport_list_add(client->transport_list, tcp, "mqtt"); if (config->transport == MQTT_TRANSPORT_OVER_TCP) { client->config->scheme = create_string("mqtt", 4); ESP_MEM_CHECK(TAG, client->config->scheme, goto _mqtt_init_failed); } #if MQTT_ENABLE_WS - transport_handle_t ws = transport_ws_init(tcp); + esp_transport_handle_t ws = esp_transport_ws_init(tcp); ESP_MEM_CHECK(TAG, ws, goto _mqtt_init_failed); - transport_set_default_port(ws, MQTT_WS_DEFAULT_PORT); - transport_list_add(client->transport_list, ws, "ws"); + esp_transport_set_default_port(ws, MQTT_WS_DEFAULT_PORT); + esp_transport_list_add(client->transport_list, ws, "ws"); if (config->transport == MQTT_TRANSPORT_OVER_WS) { client->config->scheme = create_string("ws", 2); ESP_MEM_CHECK(TAG, client->config->scheme, goto _mqtt_init_failed); @@ -293,13 +293,13 @@ esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *co #endif #if MQTT_ENABLE_SSL - transport_handle_t ssl = transport_ssl_init(); + esp_transport_handle_t ssl = esp_transport_ssl_init(); ESP_MEM_CHECK(TAG, ssl, goto _mqtt_init_failed); - transport_set_default_port(ssl, MQTT_SSL_DEFAULT_PORT); + esp_transport_set_default_port(ssl, MQTT_SSL_DEFAULT_PORT); if (config->cert_pem) { - transport_ssl_set_cert_data(ssl, config->cert_pem, strlen(config->cert_pem)); + esp_transport_ssl_set_cert_data(ssl, config->cert_pem, strlen(config->cert_pem)); } - transport_list_add(client->transport_list, ssl, "mqtts"); + esp_transport_list_add(client->transport_list, ssl, "mqtts"); if (config->transport == MQTT_TRANSPORT_OVER_SSL) { client->config->scheme = create_string("mqtts", 5); ESP_MEM_CHECK(TAG, client->config->scheme, goto _mqtt_init_failed); @@ -307,10 +307,10 @@ esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *co #endif #if MQTT_ENABLE_WSS - transport_handle_t wss = transport_ws_init(ssl); + esp_transport_handle_t wss = esp_transport_ws_init(ssl); ESP_MEM_CHECK(TAG, wss, goto _mqtt_init_failed); - transport_set_default_port(wss, MQTT_WSS_DEFAULT_PORT); - transport_list_add(client->transport_list, wss, "wss"); + esp_transport_set_default_port(wss, MQTT_WSS_DEFAULT_PORT); + esp_transport_list_add(client->transport_list, wss, "wss"); if (config->transport == MQTT_TRANSPORT_OVER_WSS) { client->config->scheme = create_string("wss", 3); ESP_MEM_CHECK(TAG, client->config->scheme, goto _mqtt_init_failed); @@ -357,7 +357,7 @@ esp_err_t esp_mqtt_client_destroy(esp_mqtt_client_handle_t client) { esp_mqtt_client_stop(client); esp_mqtt_destroy_config(client); - transport_list_destroy(client->transport_list); + esp_transport_list_destroy(client->transport_list); outbox_destroy(client->outbox); vEventGroupDelete(client->status_bits); free(client->mqtt_state.in_buffer); @@ -400,13 +400,13 @@ esp_err_t esp_mqtt_client_set_uri(esp_mqtt_client_handle_t client, const char *u client->config->path = create_string(uri + puri.field_data[UF_PATH].off, puri.field_data[UF_PATH].len); } if (client->config->path) { - transport_handle_t trans = transport_list_get_transport(client->transport_list, "ws"); + esp_transport_handle_t trans = esp_transport_list_get_transport(client->transport_list, "ws"); if (trans) { - transport_ws_set_path(trans, client->config->path); + esp_transport_ws_set_path(trans, client->config->path); } - trans = transport_list_get_transport(client->transport_list, "wss"); + trans = esp_transport_list_get_transport(client->transport_list, "wss"); if (trans) { - transport_ws_set_path(trans, client->config->path); + esp_transport_ws_set_path(trans, client->config->path); } } @@ -432,7 +432,7 @@ esp_err_t esp_mqtt_client_set_uri(esp_mqtt_client_handle_t client, const char *u static esp_err_t mqtt_write_data(esp_mqtt_client_handle_t client) { - int write_len = transport_write(client->transport, + int write_len = esp_transport_write(client->transport, (char *)client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length, client->config->network_timeout_ms); @@ -464,7 +464,7 @@ static esp_err_t esp_mqtt_dispatch_event(esp_mqtt_client_handle_t client) typedef struct { char *path; char *buffer; - transport_handle_t parent; + esp_transport_handle_t parent; } transport_ws_t; static void deliver_publish(esp_mqtt_client_handle_t client, uint8_t *message, int length) @@ -473,7 +473,7 @@ static void deliver_publish(esp_mqtt_client_handle_t client, uint8_t *message, i uint32_t mqtt_topic_length, mqtt_data_length; uint32_t mqtt_len, mqtt_offset = 0, total_mqtt_len = 0; int len_read; - transport_handle_t transport = client->transport; + esp_transport_handle_t transport = client->transport; do { @@ -485,7 +485,7 @@ static void deliver_publish(esp_mqtt_client_handle_t client, uint8_t *message, i total_mqtt_len = client->mqtt_state.message_length - client->mqtt_state.message_length_read + mqtt_data_length; mqtt_len = mqtt_data_length; /* any further reading only the underlying payload */ - transport = transport_get_payload_transport_handle(transport); + transport = esp_transport_get_payload_transport_handle(transport); } else { mqtt_len = len_read; mqtt_data = (const char*)client->mqtt_state.in_buffer; @@ -508,7 +508,7 @@ static void deliver_publish(esp_mqtt_client_handle_t client, uint8_t *message, i break; } - len_read = transport_read(transport, + len_read = esp_transport_read(transport, (char *)client->mqtt_state.in_buffer, client->mqtt_state.message_length - client->mqtt_state.message_length_read > client->mqtt_state.in_buffer_length ? client->mqtt_state.in_buffer_length : client->mqtt_state.message_length - client->mqtt_state.message_length_read, @@ -565,7 +565,7 @@ static esp_err_t mqtt_process_receive(esp_mqtt_client_handle_t client) uint8_t msg_qos; uint16_t msg_id; - read_len = transport_read(client->transport, (char *)client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length, 1000); + read_len = esp_transport_read(client->transport, (char *)client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length, 1000); if (read_len < 0) { ESP_LOGE(TAG, "Read error or end of stream"); @@ -662,7 +662,7 @@ static void esp_mqtt_task(void *pv) client->run = true; //get transport by scheme - client->transport = transport_list_get_transport(client->transport_list, client->config->scheme); + client->transport = esp_transport_list_get_transport(client->transport_list, client->config->scheme); if (client->transport == NULL) { ESP_LOGE(TAG, "There are no transports valid, stop mqtt client, config scheme = %s", client->config->scheme); @@ -670,7 +670,7 @@ static void esp_mqtt_task(void *pv) } //default port if (client->config->port == 0) { - client->config->port = transport_get_default_port(client->transport); + client->config->port = esp_transport_get_default_port(client->transport); } client->state = MQTT_STATE_INIT; @@ -684,7 +684,7 @@ static void esp_mqtt_task(void *pv) client->run = false; } - if (transport_connect(client->transport, + if (esp_transport_connect(client->transport, client->config->host, client->config->port, client->config->network_timeout_ms) < 0) { @@ -748,7 +748,7 @@ static void esp_mqtt_task(void *pv) break; } } - transport_close(client->transport); + esp_transport_close(client->transport); xEventGroupSetBits(client->status_bits, STOPPED_BIT); vTaskDelete(NULL); From e26764502a108d2ad618e385362163082e418844 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 4 Oct 2018 13:50:37 +0200 Subject: [PATCH 11/56] mqtt_client_stop stops only if started, fixed tabs->spaces, updated README, removed unused config closes #62 --- .travis.yml | 45 +++++++----- CMakeLists.txt | 8 -- README.md | 153 +-------------------------------------- component.mk | 10 --- modify_for_legacy_idf.sh | 27 +++++++ mqtt_client.c | 34 +++++---- 6 files changed, 74 insertions(+), 203 deletions(-) delete mode 100644 CMakeLists.txt delete mode 100644 component.mk create mode 100755 modify_for_legacy_idf.sh diff --git a/.travis.yml b/.travis.yml index 6410b55..0b8a459 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,7 @@ addons: before_install: # Save path to the git respository - PROJECT_PATH=$(pwd) + - CI_COMMIT_SHA=$(git rev-parse HEAD) install: # Install ESP32 toochain following steps as desribed @@ -24,31 +25,35 @@ install: - mkdir -p ~/esp - cd ~/esp # Download binary toolchain for the ESP32 - - wget https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-61-gab8375a-5.2.0.tar.gz - - tar -xzf xtensa-esp32-elf-linux64-1.22.0-61-gab8375a-5.2.0.tar.gz - # Make xtensa-esp32-elf available for all terminal sessions - - export PATH=$PATH:$HOME/esp/xtensa-esp32-elf/bin + - wget https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz + - tar -xzf xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz # Get ESP-IDF from github - git clone --recursive https://github.com/espressif/esp-idf.git # Set the path to ESP-IDF directory - export IDF_PATH=~/esp/esp-idf + - python -m pip install --user -r $IDF_PATH/requirements.txt + # Setup build tool: xtensa-esp32-elf and idf.py + - export PATH=$PATH:$HOME/esp/xtensa-esp32-elf/bin:$IDF_PATH/tools script: - # Go back to the git repository - - cd $PROJECT_PATH/examples/mqtt_tcp - # Update configuration so that kconfig doesn't start interactive mode - - make defconfig - # Build project from the git repository - - make -j4 - - cd $PROJECT_PATH/examples/mqtt_ssl - - make defconfig - - make -j4 - - cd $PROJECT_PATH/examples/mqtt_ws - - make defconfig - - make -j4 - - cd $PROJECT_PATH/examples/mqtt_wss - - make defconfig - - make -j4 - - cd $PROJECT_PATH/examples/emitter-client + # Legacy build with IDF < 3.2 + - cd $IDF_PATH && git checkout --recurse-submodules v3.1 + - cd $PROJECT_PATH + - ./modify_for_legacy_idf.sh || true + - cd $PROJECT_PATH/examples/tcp - make defconfig - make -j4 + # Master build with latest IDF + - cd $IDF_PATH && git checkout --recurse-submodules master + - cd $IDF_PATH/components/mqtt/esp-mqtt + - git remote add local $PROJECT_PATH/.git + - git fetch local + - git checkout $CI_COMMIT_SHA + - cd $IDF_PATH/examples/protocols/mqtt/tcp + - idf.py build + - cd $IDF_PATH/examples/protocols/mqtt/ssl + - idf.py build + - cd $IDF_PATH/examples/protocols/mqtt/ws + - idf.py build + - cd $IDF_PATH/examples/protocols/mqtt/wss + - idf.py build \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 7ae4f9b..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -set(COMPONENT_ADD_INCLUDEDIRS "include") -set(COMPONENT_PRIV_INCLUDEDIRS "lib/include") -set(COMPONENT_SRCDIRS ". lib") - -set(COMPONENT_REQUIRES lwip nghttp mbedtls) - -register_component() - diff --git a/README.md b/README.md index f083ab0..abe4822 100644 --- a/README.md +++ b/README.md @@ -15,158 +15,11 @@ ## How to use -Clone this component to [ESP-IDF](https://github.com/espressif/esp-idf) project (as submodule): -``` -git submodule add https://github.com/tuanpmt/espmqtt.git components/espmqtt -``` - -Or run a sample (make sure you have installed the [toolchain](http://esp-idf.readthedocs.io/en/latest/get-started/index.html#setup-toolchain)): - -``` -git clone https://github.com/tuanpmt/espmqtt.git -cd espmqtt/examples/mqtt_tcp -make menuconfig -make flash monitor -``` +[ESP-MQTT](https://github.com/espressif/esp-mqtt) is a standard [ESP-IDF](https://github.com/espressif/esp-idf) component. +Please refer to instructions in [ESP-IDF](https://github.com/espressif/esp-idf) ## Documentation -### URI - -- Curently support `mqtt`, `mqtts`, `ws`, `wss` schemes -- MQTT over TCP samples: - + `mqtt://iot.eclipse.org`: MQTT over TCP, default port 1883: - + `mqtt://iot.eclipse.org:1884` MQTT over TCP, port 1884: - + `mqtt://username:password@iot.eclipse.org:1884` MQTT over TCP, port 1884, with username and password -- MQTT over SSL samples: - + `mqtts://iot.eclipse.org`: MQTT over SSL, port 8883 - + `mqtts://iot.eclipse.org:8884`: MQTT over SSL, port 8884 -- MQTT over Websocket samples: - + `ws://iot.eclipse.org:80/ws` -- MQTT over Websocket Secure samples: - + `wss://iot.eclipse.org:443/ws` -- Minimal configurations: - -```c -const esp_mqtt_client_config_t mqtt_cfg = { - .uri = "mqtt://iot.eclipse.org", - .event_handle = mqtt_event_handler, - // .user_context = (void *)your_context -}; -``` - -- If there are any options related to the URI in `esp_mqtt_client_config_t`, the option defined by the URI will be overridden. Sample: - -```c -const esp_mqtt_client_config_t mqtt_cfg = { - .uri = "mqtt://iot.eclipse.org:1234", - .event_handle = mqtt_event_handler, - .port = 4567, -}; -//MQTT client will connect to iot.eclipse.org using port 4567 -``` - -### SSL - -- Get Certification from server, example: `iot.eclipse.org` `openssl s_client -showcerts -connect iot.eclipse.org:8883 /dev/null|openssl x509 -outform PEM >iot_eclipse_org.pem` -- Check the sample application: `examples/mqtt_ssl` -- Configuration: - -```cpp -const esp_mqtt_client_config_t mqtt_cfg = { - .uri = "mqtts://iot.eclipse.org:8883", - .event_handle = mqtt_event_handler, - .cert_pem = (const char *)iot_eclipse_org_pem_start, -}; -``` - - -### More options for `esp_mqtt_client_config_t` - -- `event_handle` for MQTT events -- `host`: MQTT server domain (ipv4 as string) -- `port`: MQTT server port -- `client_id`: default client id is `ESP32_%CHIPID%` -- `username`: MQTT username -- `password`: MQTT password -- `lwt_topic, lwt_msg, lwt_qos, lwt_retain, lwt_msg_len`: are mqtt lwt options, default NULL -- `disable_clean_session`: mqtt clean session, default clean_session is true -- `keepalive`: (value in seconds) mqtt keepalive, default is 120 seconds -- `disable_auto_reconnect`: this mqtt client will reconnect to server (when errors/disconnect). Set `disable_auto_reconnect=true` to disable -- `user_context` pass user context to this option, then can receive that context in `event->user_context` -- `task_prio, task_stack` for MQTT task, default priority is 5, and task_stack = 6144 bytes (or default task stack can be set via `make menucofig`). -- `buffer_size` for MQTT send/receive buffer, default is 1024 -- `cert_pem` pointer to CERT file for server verify (with SSL), default is NULL, not required to verify the server -- `transport`: override URI transport - + `MQTT_TRANSPORT_OVER_TCP`: MQTT over TCP, using scheme: `mqtt` - + `MQTT_TRANSPORT_OVER_SSL`: MQTT over SSL, using scheme: `mqtts` - + `MQTT_TRANSPORT_OVER_WS`: MQTT over Websocket, using scheme: `ws` - + `MQTT_TRANSPORT_OVER_WSS`: MQTT over Websocket Secure, using scheme: `wss` - -### Change settings in `menuconfig` - -``` -make menuconfig --> Component config -> ESPMQTT Configuration -``` - -## Example - -Check `examples/mqtt_tcp` and `examples/mqtt_ssl` project. In Short: - -```cpp - -static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event) -{ - esp_mqtt_client_handle_t client = event->client; - int msg_id; - // your_context_t *context = event->context; - switch (event->event_id) { - case MQTT_EVENT_CONNECTED: - ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); - msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0); - ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); - - msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1); - ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); - - msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1"); - ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id); - break; - case MQTT_EVENT_DISCONNECTED: - ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); - break; - - case MQTT_EVENT_SUBSCRIBED: - ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); - msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0); - ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); - break; - case MQTT_EVENT_UNSUBSCRIBED: - ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); - break; - case MQTT_EVENT_PUBLISHED: - ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id); - break; - case MQTT_EVENT_DATA: - ESP_LOGI(TAG, "MQTT_EVENT_DATA"); - printf("TOPIC=%.*s\r\n", event->topic_len, event->topic); - printf("DATA=%.*s\r\n", event->data_len, event->data); - break; - case MQTT_EVENT_ERROR: - ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); - break; - } - return ESP_OK; -} -const esp_mqtt_client_config_t mqtt_cfg = { - .uri = "mqtt://iot.eclipse.org", - .event_handle = mqtt_event_handler, - // .user_context = (void *)your_context -}; - -esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg); -esp_mqtt_client_start(client); -``` +Please refer to the standard [ESP-IDF](https://github.com/espressif/esp-idf) documentation here https://github.com/espressif/esp-idf/blob/master/docs/en/api-reference/protocols/mqtt.rst ## License - MQTT Package - [Stephen Robinson - contiki-mqtt](https://github.com/esar/contiki-mqtt) diff --git a/component.mk b/component.mk deleted file mode 100644 index 79bcc62..0000000 --- a/component.mk +++ /dev/null @@ -1,10 +0,0 @@ -# -# Component Makefile -# -# This Makefile should, at the very least, just include $(SDK_PATH)/make/component.mk. By default, -# this will take the sources in this directory, compile them and link them into -# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable, -# please read the SDK documents if you need to do this. -# -COMPONENT_SRCDIRS := . lib -COMPONENT_PRIV_INCLUDEDIRS := lib/include diff --git a/modify_for_legacy_idf.sh b/modify_for_legacy_idf.sh new file mode 100755 index 0000000..6c43074 --- /dev/null +++ b/modify_for_legacy_idf.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +# This snipped prepares environment for using esp-mqtt repository separately from idf -- legacy use before IDFv3.2 +# +esp_mqtt_path=`pwd` +mkdir -p ${esp_mqtt_path}/examples +pushd +cd $IDF_PATH +former_commit_id=`git rev-parse HEAD` +git checkout master + +for example in tcp; do + cp -r $IDF_PATH/examples/protocols/mqtt/${example} ${esp_mqtt_path}/examples + echo 'EXTRA_COMPONENT_DIRS += $(PROJECT_PATH)/../../../' > ${esp_mqtt_path}/examples/${example}/Makefile + cat $IDF_PATH/examples/protocols/mqtt/${example}/Makefile >> ${esp_mqtt_path}/examples/${example}/Makefile + echo "CONFIG_MQTT_TRANSPORT_SSL=" >> ${esp_mqtt_path}/examples/${example}/sdkconfig.defaults + echo "CONFIG_MQTT_TRANSPORT_WEBSOCKET=" >> ${esp_mqtt_path}/examples/${example}/sdkconfig.defaults +done + +cp -r $IDF_PATH/components/tcp_transport ${esp_mqtt_path}/.. +rm ${esp_mqtt_path}/../tcp_transport/transport_ssl.c +echo -e "#include \"esp_transport.h\"\nvoid esp_transport_ws_set_path(esp_transport_handle_t t, const char *path) {}" > ${esp_mqtt_path}/../tcp_transport/transport_ws.c + +cp $IDF_PATH/components/mqtt/Kconfig ${esp_mqtt_path} +sed 's/esp-mqtt/\./g' $IDF_PATH/components/mqtt/component.mk > ${esp_mqtt_path}/component.mk +git checkout $former_commit_id +popd \ No newline at end of file diff --git a/mqtt_client.c b/mqtt_client.c index 253b137..a433f4e 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -761,28 +761,32 @@ esp_err_t esp_mqtt_client_start(esp_mqtt_client_handle_t client) return ESP_FAIL; } #if MQTT_CORE_SELECTION_ENABLED - ESP_LOGD(TAG, "Core selection enabled on %u", MQTT_TASK_CORE); - if (xTaskCreatePinnedToCore(esp_mqtt_task, "mqtt_task", client->config->task_stack, client, client->config->task_prio, NULL, MQTT_TASK_CORE) != pdTRUE) { - ESP_LOGE(TAG, "Error create mqtt task"); - return ESP_FAIL; - } + ESP_LOGD(TAG, "Core selection enabled on %u", MQTT_TASK_CORE); + if (xTaskCreatePinnedToCore(esp_mqtt_task, "mqtt_task", client->config->task_stack, client, client->config->task_prio, NULL, MQTT_TASK_CORE) != pdTRUE) { + ESP_LOGE(TAG, "Error create mqtt task"); + return ESP_FAIL; + } #else - ESP_LOGD(TAG, "Core selection disabled"); - if (xTaskCreate(esp_mqtt_task, "mqtt_task", client->config->task_stack, client, client->config->task_prio, NULL) != pdTRUE) { - ESP_LOGE(TAG, "Error create mqtt task") ; - return ESP_FAIL; - } + ESP_LOGD(TAG, "Core selection disabled"); + if (xTaskCreate(esp_mqtt_task, "mqtt_task", client->config->task_stack, client, client->config->task_prio, NULL) != pdTRUE) { + ESP_LOGE(TAG, "Error create mqtt task"); + return ESP_FAIL; + } #endif return ESP_OK; } - esp_err_t esp_mqtt_client_stop(esp_mqtt_client_handle_t client) { - client->run = false; - xEventGroupWaitBits(client->status_bits, STOPPED_BIT, false, true, portMAX_DELAY); - client->state = MQTT_STATE_UNKNOWN; - return ESP_OK; + if (client->run) { + client->run = false; + xEventGroupWaitBits(client->status_bits, STOPPED_BIT, false, true, portMAX_DELAY); + client->state = MQTT_STATE_UNKNOWN; + return ESP_OK; + } else { + ESP_LOGW(TAG, "Client asked to stop, but was not started"); + return ESP_FAIL; + } } static esp_err_t esp_mqtt_client_ping(esp_mqtt_client_handle_t client) From c2f3b9f4b40a82c5287572c74b848f89717bad86 Mon Sep 17 00:00:00 2001 From: Riccardo Binetti Date: Fri, 5 Oct 2018 17:30:31 +0200 Subject: [PATCH 12/56] Fix bug in esp_mqtt_client_publish message enqueueing We have to enqueue first and then assign to outbound/pending variables, otherwise the previous pending message is lost and the publish message is present twice --- mqtt_client.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/mqtt_client.c b/mqtt_client.c index a433f4e..d513d6b 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -859,16 +859,20 @@ int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, len = strlen(data); } - client->mqtt_state.outbound_message = mqtt_msg_publish(&client->mqtt_state.mqtt_connection, - topic, data, len, - qos, retain, - &pending_msg_id); + mqtt_message_t *publish_msg = mqtt_msg_publish(&client->mqtt_state.mqtt_connection, + topic, data, len, + qos, retain, + &pending_msg_id); + + /* We have to set as pending all the qos>0 messages) */ if (qos > 0) { + mqtt_enqueue(client); + client->mqtt_state.outbound_message = publish_msg; client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data); client->mqtt_state.pending_msg_id = pending_msg_id; client->mqtt_state.pending_msg_count ++; - /* Have to enqueue all the qos>0 messages) */ - mqtt_enqueue(client); + } else { + client->mqtt_state.outbound_message = publish_msg; } if (mqtt_write_data(client) != ESP_OK) { From a9e796025aa97084b94c98cf5bf981e8fb2ce4e6 Mon Sep 17 00:00:00 2001 From: Riccardo Binetti Date: Tue, 2 Oct 2018 13:04:36 +0200 Subject: [PATCH 13/56] Fix buffer length during connection read Use the in_buffer length instead of the out msg length --- mqtt_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mqtt_client.c b/mqtt_client.c index d513d6b..a32b130 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -214,7 +214,7 @@ static esp_err_t esp_mqtt_connect(esp_mqtt_client_handle_t client, int timeout_m } read_len = esp_transport_read(client->transport, (char *)client->mqtt_state.in_buffer, - client->mqtt_state.outbound_message->length, + client->mqtt_state.in_buffer_length, client->config->network_timeout_ms); if (read_len < 0) { ESP_LOGE(TAG, "Error network response"); From 8bd85832161c03184e1794698b554ca4e6e60b22 Mon Sep 17 00:00:00 2001 From: Riccardo Binetti Date: Thu, 4 Oct 2018 15:49:50 +0200 Subject: [PATCH 14/56] Add mqtt_get_connect_session_present --- lib/include/mqtt_msg.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/include/mqtt_msg.h b/lib/include/mqtt_msg.h index fd04cd0..049c738 100644 --- a/lib/include/mqtt_msg.h +++ b/lib/include/mqtt_msg.h @@ -102,6 +102,7 @@ typedef struct mqtt_connect_info static inline int mqtt_get_type(uint8_t* buffer) { return (buffer[0] & 0xf0) >> 4; } +static inline int mqtt_get_connect_session_present(uint8_t* buffer) { return buffer[2] & 0x01; } static inline int mqtt_get_connect_return_code(uint8_t* buffer) { return buffer[3]; } static inline int mqtt_get_dup(uint8_t* buffer) { return (buffer[0] & 0x08) >> 3; } static inline int mqtt_get_qos(uint8_t* buffer) { return (buffer[0] & 0x06) >> 1; } From 4db99182202334ce7493001a6625e69107881abe Mon Sep 17 00:00:00 2001 From: Riccardo Binetti Date: Thu, 4 Oct 2018 16:06:17 +0200 Subject: [PATCH 15/56] mqtt_client: add session_present field to mqtt_event Populate it using the CONNACK packet --- include/mqtt_client.h | 1 + mqtt_client.c | 1 + 2 files changed, 2 insertions(+) diff --git a/include/mqtt_client.h b/include/mqtt_client.h index 45fcbe7..6e8d23c 100755 --- a/include/mqtt_client.h +++ b/include/mqtt_client.h @@ -52,6 +52,7 @@ typedef struct { char *topic; /*!< Topic asociated with this event */ int topic_len; /*!< Length of the topic for this event asociated with this event */ int msg_id; /*!< MQTT messaged id of message */ + int session_present; /*!< MQTT session_present flag for connection event */ } esp_mqtt_event_t; typedef esp_mqtt_event_t* esp_mqtt_event_handle_t; diff --git a/mqtt_client.c b/mqtt_client.c index d513d6b..0ad20c1 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -699,6 +699,7 @@ static void esp_mqtt_task(void *pv) break; } client->event.event_id = MQTT_EVENT_CONNECTED; + client->event.session_present = mqtt_get_connect_session_present(client->mqtt_state.in_buffer); client->state = MQTT_STATE_CONNECTED; esp_mqtt_dispatch_event(client); From d2bcdd84a1938f2e9c191cc6bf9b915b8dbf8c9d Mon Sep 17 00:00:00 2001 From: Riccardo Binetti Date: Mon, 6 Aug 2018 16:29:41 +0200 Subject: [PATCH 16/56] Add mutual SSL auth config to mqtt_client picked from master --- include/mqtt_client.h | 2 ++ mqtt_client.c | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/include/mqtt_client.h b/include/mqtt_client.h index 6e8d23c..93f0d7e 100755 --- a/include/mqtt_client.h +++ b/include/mqtt_client.h @@ -83,6 +83,8 @@ typedef struct { int task_stack; /*!< MQTT task stack size, default is 6144 bytes, can be changed in ``make menuconfig`` */ int buffer_size; /*!< size of MQTT send/receive buffer, default is 1024 */ const char *cert_pem; /*!< pointer to CERT file for server verify (with SSL), default is NULL, not required to verify the server */ + const char *client_cert_pem; /*!< pointer to CERT file for SSL mutual authentication, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_key_pem` has to be provided. */ + const char *client_key_pem; /*!< pointer to PEM private key file for SSL mutual authentication, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_cert_pem` has to be provided. */ esp_mqtt_transport_t transport; /*!< overrides URI transport */ } esp_mqtt_client_config_t; diff --git a/mqtt_client.c b/mqtt_client.c index 74ceb9f..17e78fa 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -299,6 +299,12 @@ esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *co if (config->cert_pem) { esp_transport_ssl_set_cert_data(ssl, config->cert_pem, strlen(config->cert_pem)); } + if (config->client_cert_pem) { + transport_ssl_set_client_cert_data(ssl, config->client_cert_pem, strlen(config->client_cert_pem)); + } + if (config->client_key_pem) { + transport_ssl_set_client_key_data(ssl, config->client_key_pem, strlen(config->client_key_pem)); + } esp_transport_list_add(client->transport_list, ssl, "mqtts"); if (config->transport == MQTT_TRANSPORT_OVER_SSL) { client->config->scheme = create_string("mqtts", 5); From 8b45c25fdca6e4bfe693321c368080db86b9c8ae Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 11 Oct 2018 17:29:19 +0200 Subject: [PATCH 17/56] corrections per renaming transports to esp_ prefixed --- mqtt_client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mqtt_client.c b/mqtt_client.c index 17e78fa..7ee0126 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -300,10 +300,10 @@ esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *co esp_transport_ssl_set_cert_data(ssl, config->cert_pem, strlen(config->cert_pem)); } if (config->client_cert_pem) { - transport_ssl_set_client_cert_data(ssl, config->client_cert_pem, strlen(config->client_cert_pem)); + esp_transport_ssl_set_client_cert_data(ssl, config->client_cert_pem, strlen(config->client_cert_pem)); } if (config->client_key_pem) { - transport_ssl_set_client_key_data(ssl, config->client_key_pem, strlen(config->client_key_pem)); + esp_transport_ssl_set_client_key_data(ssl, config->client_key_pem, strlen(config->client_key_pem)); } esp_transport_list_add(client->transport_list, ssl, "mqtts"); if (config->transport == MQTT_TRANSPORT_OVER_SSL) { From 85f2eddabd80152264dd7362c8219306df3314ef Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 16 Oct 2018 09:15:44 +0200 Subject: [PATCH 18/56] commented event fields, added description of supplied user data to user event handler closes #66 --- include/mqtt_client.h | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/include/mqtt_client.h b/include/mqtt_client.h index 93f0d7e..630ba17 100755 --- a/include/mqtt_client.h +++ b/include/mqtt_client.h @@ -20,14 +20,31 @@ extern "C" { typedef struct esp_mqtt_client* esp_mqtt_client_handle_t; +/** + * @brief MQTT event types. + * + * User event handler receives context data in `esp_mqtt_event_t` structure with + * - `user_context` - user data from `esp_mqtt_client_config_t` + * - `client` - mqtt client handle + * - various other data depending on event type + * + */ typedef enum { MQTT_EVENT_ERROR = 0, - MQTT_EVENT_CONNECTED, - MQTT_EVENT_DISCONNECTED, - MQTT_EVENT_SUBSCRIBED, - MQTT_EVENT_UNSUBSCRIBED, - MQTT_EVENT_PUBLISHED, - MQTT_EVENT_DATA, + MQTT_EVENT_CONNECTED, /*!< connected event, additional context: session_present flag */ + MQTT_EVENT_DISCONNECTED, /*!< disconnected event */ + MQTT_EVENT_SUBSCRIBED, /*!< subscribed event, additional context: msg_id */ + MQTT_EVENT_UNSUBSCRIBED, /*!< unsubscribed event */ + MQTT_EVENT_PUBLISHED, /*!< published event, additional context: msg_id */ + MQTT_EVENT_DATA, /*!< data event, additional context: + - msg_id message id + - topic pointer to the received topic + - topic_len length of the topic + - data pointer to the received data + - data_len length of the data for this event + - current_data_offset offset of the current data for this event + - total_data_len total length of the data received + */ } esp_mqtt_event_id_t; typedef enum { @@ -82,9 +99,9 @@ typedef struct { int task_prio; /*!< MQTT task priority, default is 5, can be changed in ``make menuconfig`` */ int task_stack; /*!< MQTT task stack size, default is 6144 bytes, can be changed in ``make menuconfig`` */ int buffer_size; /*!< size of MQTT send/receive buffer, default is 1024 */ - const char *cert_pem; /*!< pointer to CERT file for server verify (with SSL), default is NULL, not required to verify the server */ - const char *client_cert_pem; /*!< pointer to CERT file for SSL mutual authentication, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_key_pem` has to be provided. */ - const char *client_key_pem; /*!< pointer to PEM private key file for SSL mutual authentication, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_cert_pem` has to be provided. */ + const char *cert_pem; /*!< Pointer to certificate data in PEM format for server verify (with SSL), default is NULL, not required to verify the server */ + const char *client_cert_pem; /*!< Pointer to certificate data in PEM format for SSL mutual authentication, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_key_pem` has to be provided. */ + const char *client_key_pem; /*!< Pointer to private key data in PEM format for SSL mutual authentication, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_cert_pem` has to be provided. */ esp_mqtt_transport_t transport; /*!< overrides URI transport */ } esp_mqtt_client_config_t; From 2b49d37f8db500d41efc9739a485d1ce3a7040e1 Mon Sep 17 00:00:00 2001 From: Tuan Date: Fri, 9 Nov 2018 23:26:35 +0800 Subject: [PATCH 19/56] Add BEFORE_CONNECt event and refresh the connection option --- include/mqtt_client.h | 3 ++ mqtt_client.c | 105 ++++++++++++++++++++++++++++++------------ 2 files changed, 79 insertions(+), 29 deletions(-) diff --git a/include/mqtt_client.h b/include/mqtt_client.h index 630ba17..56d6aea 100755 --- a/include/mqtt_client.h +++ b/include/mqtt_client.h @@ -45,6 +45,7 @@ typedef enum { - current_data_offset offset of the current data for this event - total_data_len total length of the data received */ + MQTT_EVENT_BEFORE_CONNECT, /*!< The event occurs before connecting */ } esp_mqtt_event_id_t; typedef enum { @@ -103,6 +104,7 @@ typedef struct { const char *client_cert_pem; /*!< Pointer to certificate data in PEM format for SSL mutual authentication, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_key_pem` has to be provided. */ const char *client_key_pem; /*!< Pointer to private key data in PEM format for SSL mutual authentication, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_cert_pem` has to be provided. */ esp_mqtt_transport_t transport; /*!< overrides URI transport */ + int refresh_connection_after_ms; /*!< Refresh connection after this value (in milliseconds) */ } esp_mqtt_client_config_t; esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *config); @@ -113,6 +115,7 @@ esp_err_t esp_mqtt_client_subscribe(esp_mqtt_client_handle_t client, const char esp_err_t esp_mqtt_client_unsubscribe(esp_mqtt_client_handle_t client, const char *topic); int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, const char *data, int len, int qos, int retain); esp_err_t esp_mqtt_client_destroy(esp_mqtt_client_handle_t client); +esp_err_t esp_mqtt_set_config(esp_mqtt_client_handle_t client, const esp_mqtt_client_config_t *config); #ifdef __cplusplus } diff --git a/mqtt_client.c b/mqtt_client.c index 7ee0126..0f8656e 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -44,6 +44,7 @@ typedef struct { bool auto_reconnect; void *user_context; int network_timeout_ms; + int refresh_connection_after_ms; } mqtt_config_storage_t; typedef enum { @@ -61,8 +62,9 @@ struct esp_mqtt_client { mqtt_state_t mqtt_state; mqtt_connect_info_t connect_info; mqtt_client_state_t state; - long long keepalive_tick; - long long reconnect_tick; + uint64_t refresh_connection_tick; + uint64_t keepalive_tick; + uint64_t reconnect_tick; int wait_timeout_ms; int auto_reconnect; esp_mqtt_event_t event; @@ -75,98 +77,129 @@ struct esp_mqtt_client { const static int STOPPED_BIT = BIT0; static esp_err_t esp_mqtt_dispatch_event(esp_mqtt_client_handle_t client); -static esp_err_t esp_mqtt_set_config(esp_mqtt_client_handle_t client, const esp_mqtt_client_config_t *config); static esp_err_t esp_mqtt_destroy_config(esp_mqtt_client_handle_t client); static esp_err_t esp_mqtt_connect(esp_mqtt_client_handle_t client, int timeout_ms); static esp_err_t esp_mqtt_abort_connection(esp_mqtt_client_handle_t client); static esp_err_t esp_mqtt_client_ping(esp_mqtt_client_handle_t client); static char *create_string(const char *ptr, int len); -static esp_err_t esp_mqtt_set_config(esp_mqtt_client_handle_t client, const esp_mqtt_client_config_t *config) +esp_err_t esp_mqtt_set_config(esp_mqtt_client_handle_t client, const esp_mqtt_client_config_t *config) { //Copy user configurations to client context esp_err_t err = ESP_OK; - mqtt_config_storage_t *cfg = calloc(1, sizeof(mqtt_config_storage_t)); - ESP_MEM_CHECK(TAG, cfg, return ESP_ERR_NO_MEM); + mqtt_config_storage_t *cfg; + if (client->config) { + cfg = client->config; + } else { + cfg = calloc(1, sizeof(mqtt_config_storage_t)); + ESP_MEM_CHECK(TAG, cfg, return ESP_ERR_NO_MEM); + client->config = cfg; + } + if (config->task_prio) { + cfg->task_prio = config->task_prio; + } - client->config = cfg; - - cfg->task_prio = config->task_prio; if (cfg->task_prio <= 0) { cfg->task_prio = MQTT_TASK_PRIORITY; } - - cfg->task_stack = config->task_stack; + if (config->task_stack) { + cfg->task_stack = config->task_stack; + } if (cfg->task_stack == 0) { cfg->task_stack = MQTT_TASK_STACK; } + if (config->port) { + cfg->port = config->port; + } + err = ESP_ERR_NO_MEM; if (config->host) { + free(cfg->host); cfg->host = strdup(config->host); ESP_MEM_CHECK(TAG, cfg->host, goto _mqtt_set_config_failed); } - cfg->port = config->port; if (config->username) { + free(client->connect_info.username); client->connect_info.username = strdup(config->username); ESP_MEM_CHECK(TAG, client->connect_info.username, goto _mqtt_set_config_failed); } if (config->password) { + free(client->connect_info.password); client->connect_info.password = strdup(config->password); ESP_MEM_CHECK(TAG, client->connect_info.password, goto _mqtt_set_config_failed); } if (config->client_id) { + free(client->connect_info.client_id); client->connect_info.client_id = strdup(config->client_id); - } else { + ESP_MEM_CHECK(TAG, client->connect_info.client_id, goto _mqtt_set_config_failed); + } else if (client->connect_info.client_id == NULL) { client->connect_info.client_id = platform_create_id_string(); } ESP_MEM_CHECK(TAG, client->connect_info.client_id, goto _mqtt_set_config_failed); ESP_LOGD(TAG, "MQTT client_id=%s", client->connect_info.client_id); if (config->uri) { + free(cfg->uri); cfg->uri = strdup(config->uri); ESP_MEM_CHECK(TAG, cfg->uri, goto _mqtt_set_config_failed); } if (config->lwt_topic) { + free(client->connect_info.will_topic); client->connect_info.will_topic = strdup(config->lwt_topic); ESP_MEM_CHECK(TAG, client->connect_info.will_topic, goto _mqtt_set_config_failed); } - if (config->lwt_msg_len) { + if (config->lwt_msg_len && config->lwt_msg) { + free(client->connect_info.will_message); client->connect_info.will_message = malloc(config->lwt_msg_len); ESP_MEM_CHECK(TAG, client->connect_info.will_message, goto _mqtt_set_config_failed); memcpy(client->connect_info.will_message, config->lwt_msg, config->lwt_msg_len); client->connect_info.will_length = config->lwt_msg_len; } else if (config->lwt_msg) { + free(client->connect_info.will_message); client->connect_info.will_message = strdup(config->lwt_msg); ESP_MEM_CHECK(TAG, client->connect_info.will_message, goto _mqtt_set_config_failed); client->connect_info.will_length = strlen(config->lwt_msg); } - - client->connect_info.will_qos = config->lwt_qos; - client->connect_info.will_retain = config->lwt_retain; - - client->connect_info.clean_session = 1; - if (config->disable_clean_session) { - client->connect_info.clean_session = false; + if (config->lwt_qos) { + client->connect_info.will_qos = config->lwt_qos; + } + if (config->lwt_retain) { + client->connect_info.will_retain = config->lwt_retain; + } + + if (config->disable_clean_session == client->connect_info.clean_session) { + client->connect_info.clean_session = !config->disable_clean_session; + } + if (config->keepalive) { + client->connect_info.keepalive = config->keepalive; } - client->connect_info.keepalive = config->keepalive; if (client->connect_info.keepalive == 0) { client->connect_info.keepalive = MQTT_KEEPALIVE_TICK; } cfg->network_timeout_ms = MQTT_NETWORK_TIMEOUT_MS; - cfg->user_context = config->user_context; - cfg->event_handle = config->event_handle; - cfg->auto_reconnect = true; - if (config->disable_auto_reconnect) { - cfg->auto_reconnect = false; + if (config->user_context) { + cfg->user_context = config->user_context; } + if (config->event_handle) { + cfg->event_handle = config->event_handle; + } - return err; + if (config->refresh_connection_after_ms) { + cfg->refresh_connection_after_ms = config->refresh_connection_after_ms; + } + + cfg->auto_reconnect = true; + if (config->disable_auto_reconnect == cfg->auto_reconnect) { + cfg->auto_reconnect = !config->disable_auto_reconnect; + } + + return ESP_OK; _mqtt_set_config_failed: esp_mqtt_destroy_config(client); return err; @@ -179,11 +212,13 @@ static esp_err_t esp_mqtt_destroy_config(esp_mqtt_client_handle_t client) free(cfg->uri); free(cfg->path); free(cfg->scheme); + memset(cfg, 0, sizeof(mqtt_config_storage_t)); free(client->connect_info.will_topic); free(client->connect_info.will_message); free(client->connect_info.client_id); free(client->connect_info.username); free(client->connect_info.password); + memset(&client->connect_info, 0, sizeof(mqtt_connect_info_t)); free(client->config); return ESP_OK; } @@ -255,7 +290,7 @@ static esp_err_t esp_mqtt_abort_connection(esp_mqtt_client_handle_t client) client->wait_timeout_ms = MQTT_RECONNECT_TIMEOUT_MS; client->reconnect_tick = platform_tick_get_ms(); client->state = MQTT_STATE_WAIT_TIMEOUT; - ESP_LOGI(TAG, "Reconnect after %d ms", client->wait_timeout_ms); + ESP_LOGD(TAG, "Reconnect after %d ms", client->wait_timeout_ms); client->event.event_id = MQTT_EVENT_DISCONNECTED; client->wait_for_ping_resp = false; esp_mqtt_dispatch_event(client); @@ -335,6 +370,7 @@ esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *co client->keepalive_tick = platform_tick_get_ms(); client->reconnect_tick = platform_tick_get_ms(); + client->refresh_connection_tick = platform_tick_get_ms(); client->wait_for_ping_resp = false; int buffer_size = config->buffer_size; if (buffer_size <= 0) { @@ -685,6 +721,9 @@ static void esp_mqtt_task(void *pv) switch ((int)client->state) { case MQTT_STATE_INIT: + client->event.event_id = MQTT_EVENT_BEFORE_CONNECT; + esp_mqtt_dispatch_event(client); + if (client->transport == NULL) { ESP_LOGE(TAG, "There are no transport"); client->run = false; @@ -708,6 +747,7 @@ static void esp_mqtt_task(void *pv) client->event.session_present = mqtt_get_connect_session_present(client->mqtt_state.in_buffer); client->state = MQTT_STATE_CONNECTED; esp_mqtt_dispatch_event(client); + client->refresh_connection_tick = platform_tick_get_ms(); break; case MQTT_STATE_CONNECTED: @@ -735,6 +775,13 @@ static void esp_mqtt_task(void *pv) ESP_LOGD(TAG, "PING sent"); } + if (client->config->refresh_connection_after_ms && + platform_tick_get_ms() - client->refresh_connection_tick > client->config->refresh_connection_after_ms) { + ESP_LOGD(TAG, "Refreshing the connection..."); + esp_mqtt_abort_connection(client); + client->state = MQTT_STATE_INIT; + } + //Delete mesaage after 30 senconds outbox_delete_expired(client->outbox, platform_tick_get_ms(), OUTBOX_EXPIRED_TIMEOUT_MS); // From db64b791205c8dbcd0f3826a9544f0aa0301baaf Mon Sep 17 00:00:00 2001 From: Laurent Louf Date: Tue, 2 Oct 2018 17:23:14 +0200 Subject: [PATCH 20/56] Fix for case where multiple MQTT messages are fitted into a single TCP packet : iterate over the buffer received. Merges https://github.com/espressif/esp-mqtt/pull/82 Closes #64 Closes #80 --- mqtt_client.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/mqtt_client.c b/mqtt_client.c index 0f8656e..9f27538 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -606,6 +606,7 @@ static esp_err_t mqtt_process_receive(esp_mqtt_client_handle_t client) uint8_t msg_type; uint8_t msg_qos; uint16_t msg_id; + uint32_t transport_message_offset = 0 ; read_len = esp_transport_read(client->transport, (char *)client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length, 1000); @@ -618,9 +619,13 @@ static esp_err_t mqtt_process_receive(esp_mqtt_client_handle_t client) return ESP_OK; } - msg_type = mqtt_get_type(client->mqtt_state.in_buffer); - msg_qos = mqtt_get_qos(client->mqtt_state.in_buffer); - msg_id = mqtt_get_id(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length); + // In case of fragmented packet (when receiving a large publish message), the deliver_publish function will read the rest of the message with more transport read, which means the MQTT message length will be greater than the initial transport read length. That explains that the stopping condition is not the equality here + while ( transport_message_offset < read_len ){ + // If the message was valid, get the type, quality of service and id of the message + msg_type = mqtt_get_type(&client->mqtt_state.in_buffer[transport_message_offset]); + msg_qos = mqtt_get_qos(&client->mqtt_state.in_buffer[transport_message_offset]); + msg_id = mqtt_get_id(&client->mqtt_state.in_buffer[transport_message_offset], read_len - transport_message_offset); + ESP_LOGD(TAG, "msg_type=%d, msg_id=%d", msg_type, msg_id); ESP_LOGD(TAG, "msg_type=%d, msg_id=%d", msg_type, msg_id); switch (msg_type) @@ -656,9 +661,12 @@ static esp_err_t mqtt_process_receive(esp_mqtt_client_handle_t client) // return ESP_FAIL; } } - client->mqtt_state.message_length_read = read_len; - client->mqtt_state.message_length = mqtt_get_total_length(client->mqtt_state.in_buffer, client->mqtt_state.message_length_read); + + // Deliver the publish message + client->mqtt_state.message_length_read = read_len - transport_message_offset; + client->mqtt_state.message_length = mqtt_get_total_length(&client->mqtt_state.in_buffer[transport_message_offset], client->mqtt_state.message_length_read); ESP_LOGI(TAG, "deliver_publish, message_length_read=%d, message_length=%d", read_len, client->mqtt_state.message_length); + deliver_publish(client, &client->mqtt_state.in_buffer[transport_message_offset], client->mqtt_state.message_length_read); deliver_publish(client, client->mqtt_state.in_buffer, client->mqtt_state.message_length_read); break; @@ -695,6 +703,9 @@ static esp_err_t mqtt_process_receive(esp_mqtt_client_handle_t client) break; } + transport_message_offset += mqtt_get_total_length(&client->mqtt_state.in_buffer[transport_message_offset], read_len - transport_message_offset) ; + } + return ESP_OK; } From cf5b8eda89057f5eb49654d2eaf4d1a209af2d11 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 4 Dec 2018 15:29:14 +0100 Subject: [PATCH 21/56] added a fix for incomplete header message received (topic or data could not be resolved from msg) --- mqtt_client.c | 59 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/mqtt_client.c b/mqtt_client.c index 9f27538..d50e3c0 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -511,23 +511,32 @@ typedef struct { static void deliver_publish(esp_mqtt_client_handle_t client, uint8_t *message, int length) { - const char *mqtt_topic, *mqtt_data; + const char *mqtt_topic = NULL, *mqtt_data = NULL; uint32_t mqtt_topic_length, mqtt_data_length; - uint32_t mqtt_len, mqtt_offset = 0, total_mqtt_len = 0; - int len_read; + uint32_t mqtt_len = 0, mqtt_offset = 0, total_mqtt_len = 0; + int len_read= length; + int max_to_read = client->mqtt_state.in_buffer_length; + int buffer_offset = 0; esp_transport_handle_t transport = client->transport; do { if (total_mqtt_len == 0) { - mqtt_topic_length = length; - mqtt_topic = mqtt_get_publish_topic(message, &mqtt_topic_length); - mqtt_data_length = length; - mqtt_data = mqtt_get_publish_data(message, &mqtt_data_length); - total_mqtt_len = client->mqtt_state.message_length - client->mqtt_state.message_length_read + mqtt_data_length; - mqtt_len = mqtt_data_length; /* any further reading only the underlying payload */ transport = esp_transport_get_payload_transport_handle(transport); + mqtt_data_length = mqtt_topic_length = length; + if (NULL == (mqtt_topic = mqtt_get_publish_topic(message, &mqtt_topic_length)) || + NULL == (mqtt_data = mqtt_get_publish_data(message, &mqtt_data_length)) ) { + // mqtt header is not complete, continue reading + memmove(client->mqtt_state.in_buffer, message, length); + buffer_offset = length; + message = client->mqtt_state.in_buffer; + max_to_read = client->mqtt_state.in_buffer_length - length; + mqtt_len = 0; + } else { + total_mqtt_len = client->mqtt_state.message_length - client->mqtt_state.message_length_read + mqtt_data_length; + mqtt_len = mqtt_data_length; + } } else { mqtt_len = len_read; mqtt_data = (const char*)client->mqtt_state.in_buffer; @@ -535,15 +544,17 @@ static void deliver_publish(esp_mqtt_client_handle_t client, uint8_t *message, i mqtt_topic_length = 0; } - ESP_LOGD(TAG, "Get data len= %d, topic len=%d", mqtt_len, mqtt_topic_length); - client->event.event_id = MQTT_EVENT_DATA; - client->event.data = (char *)mqtt_data; - client->event.data_len = mqtt_len; - client->event.total_data_len = total_mqtt_len; - client->event.current_data_offset = mqtt_offset; - client->event.topic = (char *)mqtt_topic; - client->event.topic_len = mqtt_topic_length; - esp_mqtt_dispatch_event(client); + if (total_mqtt_len != 0) { + ESP_LOGD(TAG, "Get data len= %d, topic len=%d", mqtt_len, mqtt_topic_length); + client->event.event_id = MQTT_EVENT_DATA; + client->event.data = (char *)mqtt_data; + client->event.data_len = mqtt_len; + client->event.total_data_len = total_mqtt_len; + client->event.current_data_offset = mqtt_offset; + client->event.topic = (char *)mqtt_topic; + client->event.topic_len = mqtt_topic_length; + esp_mqtt_dispatch_event(client); + } mqtt_offset += mqtt_len; if (client->mqtt_state.message_length_read >= client->mqtt_state.message_length) { @@ -551,10 +562,13 @@ static void deliver_publish(esp_mqtt_client_handle_t client, uint8_t *message, i } len_read = esp_transport_read(transport, - (char *)client->mqtt_state.in_buffer, - client->mqtt_state.message_length - client->mqtt_state.message_length_read > client->mqtt_state.in_buffer_length ? - client->mqtt_state.in_buffer_length : client->mqtt_state.message_length - client->mqtt_state.message_length_read, + (char *)client->mqtt_state.in_buffer + buffer_offset, + client->mqtt_state.message_length - client->mqtt_state.message_length_read > max_to_read ? + max_to_read : client->mqtt_state.message_length - client->mqtt_state.message_length_read, client->config->network_timeout_ms); + length = len_read + buffer_offset; + buffer_offset = 0; + max_to_read = client->mqtt_state.in_buffer_length; if (len_read <= 0) { ESP_LOGE(TAG, "Read error or timeout: %d", errno); break; @@ -562,7 +576,6 @@ static void deliver_publish(esp_mqtt_client_handle_t client, uint8_t *message, i client->mqtt_state.message_length_read += len_read; } while (1); - } static bool is_valid_mqtt_msg(esp_mqtt_client_handle_t client, int msg_type, int msg_id) @@ -667,8 +680,6 @@ static esp_err_t mqtt_process_receive(esp_mqtt_client_handle_t client) client->mqtt_state.message_length = mqtt_get_total_length(&client->mqtt_state.in_buffer[transport_message_offset], client->mqtt_state.message_length_read); ESP_LOGI(TAG, "deliver_publish, message_length_read=%d, message_length=%d", read_len, client->mqtt_state.message_length); deliver_publish(client, &client->mqtt_state.in_buffer[transport_message_offset], client->mqtt_state.message_length_read); - - deliver_publish(client, client->mqtt_state.in_buffer, client->mqtt_state.message_length_read); break; case MQTT_MSG_TYPE_PUBACK: if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_PUBLISH, msg_id)) { From e0bbbebc08884118931f7adaedb0b8cba06db00c Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 25 Oct 2018 16:38:25 +0200 Subject: [PATCH 22/56] mqtt support for sending fragmented messages and full mqtt message length support --- lib/include/mqtt_msg.h | 3 +- lib/include/mqtt_outbox.h | 12 +++++- lib/mqtt_msg.c | 68 ++++++++++++++++++++++---------- lib/mqtt_outbox.c | 17 ++++---- mqtt_client.c | 81 ++++++++++++++++++++++++++++++++++----- 5 files changed, 142 insertions(+), 39 deletions(-) diff --git a/lib/include/mqtt_msg.h b/lib/include/mqtt_msg.h index 049c738..931cbf9 100644 --- a/lib/include/mqtt_msg.h +++ b/lib/include/mqtt_msg.h @@ -72,7 +72,8 @@ typedef struct mqtt_message { uint8_t* data; uint32_t length; - + uint32_t fragmented_msg_total_length; /*!< total len of fragmented messages (zero for all other messages) */ + uint32_t fragmented_msg_data_offset; /*!< data offset of fragmented messages (zero for all other messages) */ } mqtt_message_t; typedef struct mqtt_connection diff --git a/lib/include/mqtt_outbox.h b/lib/include/mqtt_outbox.h index a87b466..31dd5b9 100644 --- a/lib/include/mqtt_outbox.h +++ b/lib/include/mqtt_outbox.h @@ -15,9 +15,19 @@ struct outbox_item; typedef struct outbox_list_t * outbox_handle_t; typedef struct outbox_item * outbox_item_handle_t; +typedef struct outbox_message * outbox_message_handle_t; + +typedef struct outbox_message { + uint8_t *data; + int len; + int msg_id; + int msg_type; + uint8_t *remaining_data; + int remaining_len; +} outbox_message_t; outbox_handle_t outbox_init(); -outbox_item_handle_t outbox_enqueue(outbox_handle_t outbox, uint8_t *data, int len, int msg_id, int msg_type, int tick); +outbox_item_handle_t outbox_enqueue(outbox_handle_t outbox, outbox_message_handle_t message, int tick); outbox_item_handle_t outbox_dequeue(outbox_handle_t outbox); outbox_item_handle_t outbox_get(outbox_handle_t outbox, int msg_id); esp_err_t outbox_delete(outbox_handle_t outbox, int msg_id, int msg_type); diff --git a/lib/mqtt_msg.c b/lib/mqtt_msg.c index eb97847..15eb93e 100644 --- a/lib/mqtt_msg.c +++ b/lib/mqtt_msg.c @@ -34,7 +34,7 @@ #include "mqtt_config.h" #include "platform.h" -#define MQTT_MAX_FIXED_HEADER_SIZE 3 +#define MQTT_MAX_FIXED_HEADER_SIZE 5 enum mqtt_connect_flag { @@ -105,22 +105,42 @@ static mqtt_message_t* fail_message(mqtt_connection_t* connection) static mqtt_message_t* fini_message(mqtt_connection_t* connection, int type, int dup, int qos, int retain) { - int remaining_length = connection->message.length - MQTT_MAX_FIXED_HEADER_SIZE; - - if (remaining_length > 127) - { - connection->buffer[0] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1); - connection->buffer[1] = 0x80 | (remaining_length % 128); - connection->buffer[2] = remaining_length / 128; - connection->message.length = remaining_length + 3; - connection->message.data = connection->buffer; + int message_length = connection->message.length - MQTT_MAX_FIXED_HEADER_SIZE; + int total_length = message_length; + int encoded_length = 0; + uint8_t encoded_lens[4] = {0}; + // Check if we have fragmented message and update total_len + if (connection->message.fragmented_msg_total_length) { + total_length = connection->message.fragmented_msg_total_length - MQTT_MAX_FIXED_HEADER_SIZE; } - else - { - connection->buffer[1] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1); - connection->buffer[2] = remaining_length; - connection->message.length = remaining_length + 2; - connection->message.data = connection->buffer + 1; + + // Encode MQTT message length + int len_bytes = 0; // size of encoded message length + do { + encoded_length = total_length % 128; + total_length /= 128; + if (total_length > 0) { + encoded_length |= 0x80; + } + encoded_lens[len_bytes] = encoded_length; + len_bytes++; + } while (total_length > 0); + + // Sanity check for MQTT header + if (len_bytes + 1 > MQTT_MAX_FIXED_HEADER_SIZE) { + return fail_message(connection); + } + + // Save the header bytes + connection->message.length = message_length + len_bytes + 1; // msg len + encoded_size len + type (1 byte) + int offs = MQTT_MAX_FIXED_HEADER_SIZE - 1 - len_bytes; + connection->message.data = connection->buffer + offs; + connection->message.fragmented_msg_data_offset -= offs; + // type byte + connection->buffer[offs++] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1); + // length bytes + for (int j = 0; jbuffer[offs++] = encoded_lens[j]; } return &connection->message; @@ -377,11 +397,17 @@ mqtt_message_t* mqtt_msg_publish(mqtt_connection_t* connection, const char* topi else *message_id = 0; - if (connection->message.length + data_length > connection->buffer_length) - return fail_message(connection); - memcpy(connection->buffer + connection->message.length, data, data_length); - connection->message.length += data_length; - + if (connection->message.length + data_length > connection->buffer_length) { + // Not enough size in buffer -> fragment this message + connection->message.fragmented_msg_data_offset = connection->message.length; + memcpy(connection->buffer + connection->message.length, data, connection->buffer_length - connection->message.length); + connection->message.length = connection->buffer_length; + connection->message.fragmented_msg_total_length = data_length + connection->message.fragmented_msg_data_offset; + } else { + memcpy(connection->buffer + connection->message.length, data, data_length); + connection->message.length += data_length; + connection->message.fragmented_msg_total_length = 0; + } return fini_message(connection, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain); } diff --git a/lib/mqtt_outbox.c b/lib/mqtt_outbox.c index 300e698..6d6efc5 100644 --- a/lib/mqtt_outbox.c +++ b/lib/mqtt_outbox.c @@ -31,22 +31,25 @@ outbox_handle_t outbox_init() return outbox; } -outbox_item_handle_t outbox_enqueue(outbox_handle_t outbox, uint8_t *data, int len, int msg_id, int msg_type, int tick) +outbox_item_handle_t outbox_enqueue(outbox_handle_t outbox, outbox_message_handle_t message, int tick) { outbox_item_handle_t item = calloc(1, sizeof(outbox_item_t)); ESP_MEM_CHECK(TAG, item, return NULL); - item->msg_id = msg_id; - item->msg_type = msg_type; + item->msg_id = message->msg_id; + item->msg_type = message->msg_type; item->tick = tick; - item->len = len; - item->buffer = malloc(len); + item->len = message->len; + item->buffer = malloc(message->len + message->remaining_len); ESP_MEM_CHECK(TAG, item->buffer, { free(item); return NULL; }); - memcpy(item->buffer, data, len); + memcpy(item->buffer, message->data, message->len); + if (message->remaining_data) { + memcpy(item->buffer+message->len, message->remaining_data, message->remaining_len); + } STAILQ_INSERT_TAIL(outbox, item, next); - ESP_LOGD(TAG, "ENQUEUE msgid=%d, msg_type=%d, len=%d, size=%d", msg_id, msg_type, len, outbox_get_size(outbox)); + ESP_LOGD(TAG, "ENQUEUE msgid=%d, msg_type=%d, len=%d, size=%d", message->msg_id, message->msg_type, message->len + message->remaining_len, outbox_get_size(outbox)); return item; } diff --git a/mqtt_client.c b/mqtt_client.c index d50e3c0..6c5a795 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -596,19 +596,40 @@ static bool is_valid_mqtt_msg(esp_mqtt_client_handle_t client, int msg_type, int return false; } +static void mqtt_enqueue_oversized(esp_mqtt_client_handle_t client, uint8_t *remaining_data, int remaining_len) +{ + ESP_LOGD(TAG, "mqtt_enqueue_oversized id: %d, type=%d successful", + client->mqtt_state.pending_msg_id, client->mqtt_state.pending_msg_type); + //lock mutex + outbox_message_t msg = { 0 }; + if (client->mqtt_state.pending_msg_count > 0) { + client->mqtt_state.pending_msg_count --; + } + msg.data = client->mqtt_state.outbound_message->data; + msg.len = client->mqtt_state.outbound_message->length; + msg.msg_id = client->mqtt_state.pending_msg_id; + msg.msg_type = client->mqtt_state.pending_msg_type; + msg.remaining_data = remaining_data; + msg.remaining_len = remaining_len; + //Copy to queue buffer + outbox_enqueue(client->outbox, &msg, platform_tick_get_ms()); + + //unlock +} + static void mqtt_enqueue(esp_mqtt_client_handle_t client) { ESP_LOGD(TAG, "mqtt_enqueue id: %d, type=%d successful", client->mqtt_state.pending_msg_id, client->mqtt_state.pending_msg_type); //lock mutex if (client->mqtt_state.pending_msg_count > 0) { + outbox_message_t msg = { 0 }; + msg.data = client->mqtt_state.outbound_message->data; + msg.len = client->mqtt_state.outbound_message->length; + msg.msg_id = client->mqtt_state.pending_msg_id; + msg.msg_type = client->mqtt_state.pending_msg_type; //Copy to queue buffer - outbox_enqueue(client->outbox, - client->mqtt_state.outbound_message->data, - client->mqtt_state.outbound_message->length, - client->mqtt_state.pending_msg_id, - client->mqtt_state.pending_msg_type, - platform_tick_get_ms()); + outbox_enqueue(client->outbox, &msg, platform_tick_get_ms()); } //unlock } @@ -951,9 +972,51 @@ int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, client->mqtt_state.outbound_message = publish_msg; } - if (mqtt_write_data(client) != ESP_OK) { - ESP_LOGE(TAG, "Error to public data to topic=%s, qos=%d", topic, qos); - return -1; + /* Provide support for sending fragmented message if it doesn't fit buffer */ + int remaining_len = len; + const char *current_data = data; + bool sending = true; + + while (sending) { + + if (mqtt_write_data(client) != ESP_OK) { + ESP_LOGE(TAG, "Error to public data to topic=%s, qos=%d", topic, qos); + return -1; + } + + int data_sent = client->mqtt_state.outbound_message->length - client->mqtt_state.outbound_message->fragmented_msg_data_offset; + remaining_len -= data_sent; + current_data += data_sent; + + if (remaining_len > 0) { + mqtt_connection_t* connection = &client->mqtt_state.mqtt_connection; + ESP_LOGD(TAG, "Sending fragmented message, remains to send %d bytes of %d", remaining_len, len); + if (connection->message.fragmented_msg_data_offset) { + // asked to enqueue oversized message (first time only) + connection->message.fragmented_msg_data_offset = 0; + connection->message.fragmented_msg_total_length = 0; + if (qos > 0) { + // internally enqueue all big messages, as they dont fit 'pending msg' structure + mqtt_enqueue_oversized(client, (uint8_t*)current_data, remaining_len); + } + } + + if (remaining_len > connection->buffer_length) { + // Continue with sending + memcpy(connection->buffer, current_data, connection->buffer_length); + connection->message.length = connection->buffer_length; + sending = true; + } else { + memcpy(connection->buffer, current_data, remaining_len); + connection->message.length = remaining_len; + sending = true; + } + connection->message.data = connection->buffer; + client->mqtt_state.outbound_message = &connection->message; + } else { + // Message was sent correctly + sending = false; + } } return pending_msg_id; } From 06fe5cca8ed78dc5922cff5c406214b244b35a26 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Fri, 2 Nov 2018 08:37:05 +0100 Subject: [PATCH 23/56] mqtt data events fixed to keep consistent msg_id when fragmented message received closes #70 --- mqtt_client.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/mqtt_client.c b/mqtt_client.c index 6c5a795..627222c 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -77,6 +77,7 @@ struct esp_mqtt_client { const static int STOPPED_BIT = BIT0; static esp_err_t esp_mqtt_dispatch_event(esp_mqtt_client_handle_t client); +static esp_err_t esp_mqtt_dispatch_event_with_msgid(esp_mqtt_client_handle_t client); static esp_err_t esp_mqtt_destroy_config(esp_mqtt_client_handle_t client); static esp_err_t esp_mqtt_connect(esp_mqtt_client_handle_t client, int timeout_ms); static esp_err_t esp_mqtt_abort_connection(esp_mqtt_client_handle_t client); @@ -293,7 +294,7 @@ static esp_err_t esp_mqtt_abort_connection(esp_mqtt_client_handle_t client) ESP_LOGD(TAG, "Reconnect after %d ms", client->wait_timeout_ms); client->event.event_id = MQTT_EVENT_DISCONNECTED; client->wait_for_ping_resp = false; - esp_mqtt_dispatch_event(client); + esp_mqtt_dispatch_event_with_msgid(client); return ESP_OK; } @@ -490,9 +491,14 @@ static esp_err_t mqtt_write_data(esp_mqtt_client_handle_t client) return ESP_OK; } -static esp_err_t esp_mqtt_dispatch_event(esp_mqtt_client_handle_t client) +static esp_err_t esp_mqtt_dispatch_event_with_msgid(esp_mqtt_client_handle_t client) { client->event.msg_id = mqtt_get_id(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length); + return esp_mqtt_dispatch_event(client); +} + +static esp_err_t esp_mqtt_dispatch_event(esp_mqtt_client_handle_t client) +{ client->event.user_context = client->config->user_context; client->event.client = client; @@ -536,6 +542,12 @@ static void deliver_publish(esp_mqtt_client_handle_t client, uint8_t *message, i } else { total_mqtt_len = client->mqtt_state.message_length - client->mqtt_state.message_length_read + mqtt_data_length; mqtt_len = mqtt_data_length; + if (client->mqtt_state.message_length_read < client->mqtt_state.message_length) { + /* if message is framented -> correct the size for the first DATA event */ + mqtt_data_length = client->mqtt_state.message_length_read - ((uint8_t*)mqtt_data- message); + } + /* read msg id only once */ + client->event.msg_id = mqtt_get_id(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length); } } else { mqtt_len = len_read; @@ -668,14 +680,14 @@ static esp_err_t mqtt_process_receive(esp_mqtt_client_handle_t client) if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_SUBSCRIBE, msg_id)) { ESP_LOGD(TAG, "Subscribe successful"); client->event.event_id = MQTT_EVENT_SUBSCRIBED; - esp_mqtt_dispatch_event(client); + esp_mqtt_dispatch_event_with_msgid(client); } break; case MQTT_MSG_TYPE_UNSUBACK: if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_UNSUBSCRIBE, msg_id)) { ESP_LOGD(TAG, "UnSubscribe successful"); client->event.event_id = MQTT_EVENT_UNSUBSCRIBED; - esp_mqtt_dispatch_event(client); + esp_mqtt_dispatch_event_with_msgid(client); } break; case MQTT_MSG_TYPE_PUBLISH: @@ -706,7 +718,7 @@ static esp_err_t mqtt_process_receive(esp_mqtt_client_handle_t client) if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_PUBLISH, msg_id)) { ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBACK, finish QoS1 publish"); client->event.event_id = MQTT_EVENT_PUBLISHED; - esp_mqtt_dispatch_event(client); + esp_mqtt_dispatch_event_with_msgid(client); } break; @@ -726,7 +738,7 @@ static esp_err_t mqtt_process_receive(esp_mqtt_client_handle_t client) if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_PUBLISH, msg_id)) { ESP_LOGD(TAG, "Receive MQTT_MSG_TYPE_PUBCOMP, finish QoS2 publish"); client->event.event_id = MQTT_EVENT_PUBLISHED; - esp_mqtt_dispatch_event(client); + esp_mqtt_dispatch_event_with_msgid(client); } break; case MQTT_MSG_TYPE_PINGRESP: @@ -765,7 +777,7 @@ static void esp_mqtt_task(void *pv) switch ((int)client->state) { case MQTT_STATE_INIT: client->event.event_id = MQTT_EVENT_BEFORE_CONNECT; - esp_mqtt_dispatch_event(client); + esp_mqtt_dispatch_event_with_msgid(client); if (client->transport == NULL) { ESP_LOGE(TAG, "There are no transport"); @@ -789,7 +801,7 @@ static void esp_mqtt_task(void *pv) client->event.event_id = MQTT_EVENT_CONNECTED; client->event.session_present = mqtt_get_connect_session_present(client->mqtt_state.in_buffer); client->state = MQTT_STATE_CONNECTED; - esp_mqtt_dispatch_event(client); + esp_mqtt_dispatch_event_with_msgid(client); client->refresh_connection_tick = platform_tick_get_ms(); break; From f08f3b678717865234637164a29ed3a63e756ca7 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 3 Jan 2019 07:56:22 +0100 Subject: [PATCH 24/56] update log levels, logging complete error code, removed unnecessary struct --- mqtt_client.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/mqtt_client.c b/mqtt_client.c index 627222c..bf695f8 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -508,13 +508,6 @@ static esp_err_t esp_mqtt_dispatch_event(esp_mqtt_client_handle_t client) return ESP_FAIL; } - -typedef struct { - char *path; - char *buffer; - esp_transport_handle_t parent; -} transport_ws_t; - static void deliver_publish(esp_mqtt_client_handle_t client, uint8_t *message, int length) { const char *mqtt_topic = NULL, *mqtt_data = NULL; @@ -582,7 +575,7 @@ static void deliver_publish(esp_mqtt_client_handle_t client, uint8_t *message, i buffer_offset = 0; max_to_read = client->mqtt_state.in_buffer_length; if (len_read <= 0) { - ESP_LOGE(TAG, "Read error or timeout: %d", errno); + ESP_LOGE(TAG, "Read error or timeout: len_read=%d, errno=%d", len_read, errno); break; } client->mqtt_state.message_length_read += len_read; @@ -711,7 +704,7 @@ static esp_err_t mqtt_process_receive(esp_mqtt_client_handle_t client) // Deliver the publish message client->mqtt_state.message_length_read = read_len - transport_message_offset; client->mqtt_state.message_length = mqtt_get_total_length(&client->mqtt_state.in_buffer[transport_message_offset], client->mqtt_state.message_length_read); - ESP_LOGI(TAG, "deliver_publish, message_length_read=%d, message_length=%d", read_len, client->mqtt_state.message_length); + ESP_LOGD(TAG, "deliver_publish, message_length_read=%d, message_length=%d", read_len, client->mqtt_state.message_length); deliver_publish(client, &client->mqtt_state.in_buffer[transport_message_offset], client->mqtt_state.message_length_read); break; case MQTT_MSG_TYPE_PUBACK: From dc801ce8eaf121b15b760b17ec8357f8dc80a43e Mon Sep 17 00:00:00 2001 From: David Cermak Date: Fri, 2 Nov 2018 10:13:36 +0100 Subject: [PATCH 25/56] ci: added basic support for building + static analysis with IDF master --- .clang-tidy-limits.yml | 32 +++++++++++ .gitlab-ci.yml | 122 +++++++++++++++++++++++++++++++++++++++++ .travis.yml | 2 + 3 files changed, 156 insertions(+) create mode 100644 .clang-tidy-limits.yml create mode 100644 .gitlab-ci.yml diff --git a/.clang-tidy-limits.yml b/.clang-tidy-limits.yml new file mode 100644 index 0000000..f0b5377 --- /dev/null +++ b/.clang-tidy-limits.yml @@ -0,0 +1,32 @@ +limits: + "google-readability-braces-around-statements" : 30 + "readability-braces-around-statements" : 30 + "clang-diagnostic-error" : 10 + "readability-non-const-parameter" : 10 + "misc-misplaced-const" : 10 + "clang-diagnostic-typedef-redefinition" : 10 + "hicpp-braces-around-statements" : 10 + "clang-diagnostic-int-to-pointer-cast" : 10 + "hicpp-no-assembler" : 10 + "readability-else-after-return" : 10 + "readability-redundant-declaration" : 10 + "clang-diagnostic-unknown-attributes" : 10 + "misc-unused-parameters" : 10 + "readability-inconsistent-declaration-parameter-name" : 10 + "google-readability-todo" : 10 + "clang-diagnostic-macro-redefined" : 10 + "google-readability-casting" : 10 + "readability-inconsistent-declaration-parameter-name": 10 + "readability-named-parameter": 10 + "readability-container-size-empty": 10 + "modernize-use-using": 10 + "modernize-use-override": 10 + "readability-implicit-bool-cast": 10 + "modernize-use-default-member-init": 10 + "performance-unnecessary-value-param": 10 + "modernize-use-equals-default": 10 + "modernize-use-nullptr": 10 + +ignore: + + diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..c628af5 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,122 @@ +stages: + - build + - static_analysis + - deploy_report + - deploy + + +variables: + IDF_REPO: ${GITLAB_SSH_SERVER}/idf/esp-idf.git + +.add_gh_key_remote: &add_gh_key_remote | + cit_add_ssh_key "${GH_PUSH_KEY}" + git remote remove github || true + git remote add github ${GH_PUSH_REPO} + +before_script: + # Use CI Tools + - curl -sSL ${CIT_LOADER_URL} | sh + - source citools/import_functions + - PATH=$CI_PROJECT_DIR/esp-idf/tools:$PATH + +build_with_idf: + stage: build + image: ${CI_DOCKER_REGISTRY}/esp32-ci-env + tags: + - build + dependencies: [] + artifacts: + when: always + paths: + - tidybuild/* + expire_in: 1 day + script: + - cit_add_ssh_key "${GITLAB_KEY}" + - git clone "${IDF_REPO}" + - cd esp-idf + - ./tools/ci/mirror-submodule-update.sh + - export IDF_PATH=$(pwd) + - cd $IDF_PATH/components/mqtt/esp-mqtt + - rm -rf .git + - cp -r $CI_PROJECT_DIR/.git . + - git checkout $CI_COMMIT_SHA + # build one example and capture compile commands/flags for static analysis + - cd $IDF_PATH/examples/protocols/mqtt/tcp + - export PEDANTIC_CFLAGS="-Werror -Werror=deprecated-declarations -Werror=unused-variable -Werror=unused-but-set-variable -Werror=unused-function" + - export EXTRA_CFLAGS=${PEDANTIC_CFLAGS} && export EXTRA_CXXFLAGS=${EXTRA_CFLAGS} + - idf.py build + - mkdir -p tidybuild + - cd tidybuild + - cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .. + - cd $CI_PROJECT_DIR + - mv $IDF_PATH/examples/protocols/mqtt/tcp/tidybuild $CI_PROJECT_DIR/tidybuild + # build other examples + - cd $IDF_PATH/examples/protocols/mqtt/ssl && idf.py build + - cd $IDF_PATH/examples/protocols/mqtt/ssl_mutual_auth && idf.py build + - cd $IDF_PATH/examples/protocols/mqtt/ws && idf.py build + - cd $IDF_PATH/examples/protocols/mqtt/wss && idf.py build + +clang_tidy_check: + stage: static_analysis + image: ${CI_DOCKER_REGISTRY}/clang-static-analysis + tags: + - host_test + dependencies: + - build_with_idf + artifacts: + reports: + junit: esp-idf/examples/protocols/mqtt/tcp/tidybuild/output.xml + when: always + paths: + - esp-idf/examples/protocols/mqtt/tcp/tidybuild/report/* + expire_in: 1 day + script: + - cit_add_ssh_key "${GITLAB_KEY}" + - git clone "${IDF_REPO}" + - cd esp-idf + - ./tools/ci/mirror-submodule-update.sh + - export IDF_PATH=$(pwd) + - cd $IDF_PATH/components/mqtt/esp-mqtt + - rm -rf .git + - cp -r $CI_PROJECT_DIR/.git . + - git checkout $CI_COMMIT_SHA + - mv $CI_PROJECT_DIR/tidybuild $IDF_PATH/examples/protocols/mqtt/tcp/tidybuild + - cd $IDF_PATH/examples/protocols/mqtt/tcp/tidybuild + - git clone "${CI_REPORT_TOOLS}" + - cd static-analysis-utils + - ./generate_report.sh $CI_PROJECT_DIR/.clang-tidy-limits.yml $IDF_PATH/examples/protocols/mqtt/tcp/tidybuild/report $IDF_PATH/examples/protocols/mqtt/tcp/tidybuild/output.xml + +deploy_report: + stage: deploy_report + image: $CI_DOCKER_REGISTRY/esp32-ci-env + tags: + - deploy + dependencies: + - clang_tidy_check + script: + - cit_add_ssh_key "${DOCS_DEPLOY_KEY}" + - echo -e "Host $DOCS_SERVER\n\tStrictHostKeyChecking no\n\tUser $DOCS_SERVER_USER\n" >> ~/.ssh/config + - export GIT_VER=$(git describe --always) + - cd esp-idf/examples/protocols/mqtt/tcp/tidybuild + - mv report $GIT_VER + - tar czvf $GIT_VER.tar.gz $GIT_VER + - ssh $DOCS_SERVER -x "mkdir -p $DOCS_PATH/clang-tidy" + - scp $GIT_VER.tar.gz $DOCS_SERVER:$DOCS_PATH/clang-tidy + - ssh $DOCS_SERVER -x "cd $DOCS_PATH/clang-tidy && tar xzvf $GIT_VER.tar.gz && rm -f latest && ln -s $GIT_VER latest" + # add link to view the report + - echo "[static analysis][clang tidy] $CI_DOCKER_REGISTRY/static_analysis/esp-idf/clang-tidy/${GIT_VER}/index.html" + +push_master_to_github: + stage: deploy + image: ${CI_DOCKER_REGISTRY}/esp32-ci-env + tags: + - build + only: + - master + - idf + when: on_success + variables: + GIT_STRATEGY: clone + script: + - *add_gh_key_remote + - git push github HEAD:${CI_COMMIT_REF_NAME} diff --git a/.travis.yml b/.travis.yml index 0b8a459..521d293 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,8 @@ addons: before_install: # Save path to the git respository - PROJECT_PATH=$(pwd) + # Have to checkout a temp branch for later in tree reference + - git checkout -b temporary_ref_branch - CI_COMMIT_SHA=$(git rev-parse HEAD) install: From 17fd713bced4f2d00df7ed664ed82a7d108ab317 Mon Sep 17 00:00:00 2001 From: Mikael Kanstrup Date: Thu, 25 Oct 2018 09:50:01 +0200 Subject: [PATCH 26/56] Avoid further wait period after reconnect timeout occurs When reconnect timer expires an additional waiting period of half the timeout period is seen. Skip this extra waiting period when timeout is detected and perform the connect attempt right away. This change makes configured reconnect timeout value MQTT_RECONNECT_TIMEOUT_MS accurate. --- mqtt_client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mqtt_client.c b/mqtt_client.c index bf695f8..fa63fc7 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -845,6 +845,7 @@ static void esp_mqtt_task(void *pv) client->state = MQTT_STATE_INIT; client->reconnect_tick = platform_tick_get_ms(); ESP_LOGD(TAG, "Reconnecting..."); + break; } vTaskDelay(client->wait_timeout_ms / 2 / portTICK_RATE_MS); break; From df455d2a5fe562dd1b8351da99a1d6d82b66eff3 Mon Sep 17 00:00:00 2001 From: Mikael Kanstrup Date: Wed, 24 Oct 2018 10:57:45 +0200 Subject: [PATCH 27/56] Add client force reconnect function esp-mqtt library is unaware of underlying network connectivity states and current auto reconnect mechanism is built around timed retry attempts every MQTT_RECONNECT_TIMEOUT_MS. As application code usually keeps track of network connectity state export a new function that application can use to request a forced reconnect attempt as soon as connected to the network. --- include/mqtt_client.h | 1 + mqtt_client.c | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/include/mqtt_client.h b/include/mqtt_client.h index 56d6aea..e4e11d4 100755 --- a/include/mqtt_client.h +++ b/include/mqtt_client.h @@ -110,6 +110,7 @@ typedef struct { esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *config); esp_err_t esp_mqtt_client_set_uri(esp_mqtt_client_handle_t client, const char *uri); esp_err_t esp_mqtt_client_start(esp_mqtt_client_handle_t client); +esp_err_t esp_mqtt_client_reconnect(esp_mqtt_client_handle_t client); esp_err_t esp_mqtt_client_stop(esp_mqtt_client_handle_t client); esp_err_t esp_mqtt_client_subscribe(esp_mqtt_client_handle_t client, const char *topic, int qos); esp_err_t esp_mqtt_client_unsubscribe(esp_mqtt_client_handle_t client, const char *topic); diff --git a/mqtt_client.c b/mqtt_client.c index fa63fc7..9903462 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -75,6 +75,7 @@ struct esp_mqtt_client { }; const static int STOPPED_BIT = BIT0; +const static int RECONNECT_BIT = BIT1; static esp_err_t esp_mqtt_dispatch_event(esp_mqtt_client_handle_t client); static esp_err_t esp_mqtt_dispatch_event_with_msgid(esp_mqtt_client_handle_t client); @@ -769,6 +770,7 @@ static void esp_mqtt_task(void *pv) switch ((int)client->state) { case MQTT_STATE_INIT: + xEventGroupClearBits(client->status_bits, RECONNECT_BIT); client->event.event_id = MQTT_EVENT_BEFORE_CONNECT; esp_mqtt_dispatch_event_with_msgid(client); @@ -847,7 +849,8 @@ static void esp_mqtt_task(void *pv) ESP_LOGD(TAG, "Reconnecting..."); break; } - vTaskDelay(client->wait_timeout_ms / 2 / portTICK_RATE_MS); + xEventGroupWaitBits(client->status_bits, RECONNECT_BIT, false, true, + client->wait_timeout_ms / 2 / portTICK_RATE_MS); break; } } @@ -879,6 +882,18 @@ esp_err_t esp_mqtt_client_start(esp_mqtt_client_handle_t client) return ESP_OK; } +esp_err_t esp_mqtt_client_reconnect(esp_mqtt_client_handle_t client) +{ + ESP_LOGI(TAG, "Client force reconnect requested"); + if (client->state != MQTT_STATE_WAIT_TIMEOUT) { + ESP_LOGD(TAG, "The client is not waiting for reconnection. Ignore the request"); + return ESP_FAIL; + } + client->wait_timeout_ms = 0; + xEventGroupSetBits(client->status_bits, RECONNECT_BIT); + return ESP_OK; +} + esp_err_t esp_mqtt_client_stop(esp_mqtt_client_handle_t client) { if (client->run) { From d4b66556186141e09db89c57781c6709e0e71d8a Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 30 Jan 2019 16:38:46 +0100 Subject: [PATCH 28/56] minor fixes for issues present with fragmented/packed data --- mqtt_client.c | 158 ++++++++++++++++++++++++-------------------------- 1 file changed, 77 insertions(+), 81 deletions(-) diff --git a/mqtt_client.c b/mqtt_client.c index 9903462..919189e 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -536,12 +536,9 @@ static void deliver_publish(esp_mqtt_client_handle_t client, uint8_t *message, i } else { total_mqtt_len = client->mqtt_state.message_length - client->mqtt_state.message_length_read + mqtt_data_length; mqtt_len = mqtt_data_length; - if (client->mqtt_state.message_length_read < client->mqtt_state.message_length) { - /* if message is framented -> correct the size for the first DATA event */ - mqtt_data_length = client->mqtt_state.message_length_read - ((uint8_t*)mqtt_data- message); - } + mqtt_data_length = client->mqtt_state.message_length - ((uint8_t*)mqtt_data- message); /* read msg id only once */ - client->event.msg_id = mqtt_get_id(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length); + client->event.msg_id = mqtt_get_id(message, length); } } else { mqtt_len = len_read; @@ -555,7 +552,7 @@ static void deliver_publish(esp_mqtt_client_handle_t client, uint8_t *message, i client->event.event_id = MQTT_EVENT_DATA; client->event.data = (char *)mqtt_data; client->event.data_len = mqtt_len; - client->event.total_data_len = total_mqtt_len; + client->event.total_data_len = mqtt_data_length; client->event.current_data_offset = mqtt_offset; client->event.topic = (char *)mqtt_topic; client->event.topic_len = mqtt_topic_length; @@ -660,88 +657,87 @@ static esp_err_t mqtt_process_receive(esp_mqtt_client_handle_t client) } // In case of fragmented packet (when receiving a large publish message), the deliver_publish function will read the rest of the message with more transport read, which means the MQTT message length will be greater than the initial transport read length. That explains that the stopping condition is not the equality here - while ( transport_message_offset < read_len ){ - // If the message was valid, get the type, quality of service and id of the message - msg_type = mqtt_get_type(&client->mqtt_state.in_buffer[transport_message_offset]); - msg_qos = mqtt_get_qos(&client->mqtt_state.in_buffer[transport_message_offset]); - msg_id = mqtt_get_id(&client->mqtt_state.in_buffer[transport_message_offset], read_len - transport_message_offset); - ESP_LOGD(TAG, "msg_type=%d, msg_id=%d", msg_type, msg_id); + while ( transport_message_offset < read_len ) { + // If the message was valid, get the type, quality of service and id of the message + msg_type = mqtt_get_type(&client->mqtt_state.in_buffer[transport_message_offset]); + msg_qos = mqtt_get_qos(&client->mqtt_state.in_buffer[transport_message_offset]); + msg_id = mqtt_get_id(&client->mqtt_state.in_buffer[transport_message_offset], read_len - transport_message_offset); + client->mqtt_state.message_length_read = read_len - transport_message_offset; + client->mqtt_state.message_length = mqtt_get_total_length(&client->mqtt_state.in_buffer[transport_message_offset], client->mqtt_state.message_length_read); - ESP_LOGD(TAG, "msg_type=%d, msg_id=%d", msg_type, msg_id); - switch (msg_type) - { - case MQTT_MSG_TYPE_SUBACK: - if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_SUBSCRIBE, msg_id)) { - ESP_LOGD(TAG, "Subscribe successful"); - client->event.event_id = MQTT_EVENT_SUBSCRIBED; - esp_mqtt_dispatch_event_with_msgid(client); - } - break; - case MQTT_MSG_TYPE_UNSUBACK: - if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_UNSUBSCRIBE, msg_id)) { - ESP_LOGD(TAG, "UnSubscribe successful"); - client->event.event_id = MQTT_EVENT_UNSUBSCRIBED; - esp_mqtt_dispatch_event_with_msgid(client); - } - break; - case MQTT_MSG_TYPE_PUBLISH: - if (msg_qos == 1) { - client->mqtt_state.outbound_message = mqtt_msg_puback(&client->mqtt_state.mqtt_connection, msg_id); - } - else if (msg_qos == 2) { - client->mqtt_state.outbound_message = mqtt_msg_pubrec(&client->mqtt_state.mqtt_connection, msg_id); - } + ESP_LOGD(TAG, "msg_type=%d, msg_id=%d", msg_type, msg_id); - if (msg_qos == 1 || msg_qos == 2) { - ESP_LOGD(TAG, "Queue response QoS: %d", msg_qos); - - if (mqtt_write_data(client) != ESP_OK) { - ESP_LOGE(TAG, "Error write qos msg repsonse, qos = %d", msg_qos); - // TODO: Shoule reconnect? - // return ESP_FAIL; + switch (msg_type) + { + case MQTT_MSG_TYPE_SUBACK: + if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_SUBSCRIBE, msg_id)) { + ESP_LOGD(TAG, "Subscribe successful"); + client->event.event_id = MQTT_EVENT_SUBSCRIBED; + esp_mqtt_dispatch_event_with_msgid(client); + } + break; + case MQTT_MSG_TYPE_UNSUBACK: + if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_UNSUBSCRIBE, msg_id)) { + ESP_LOGD(TAG, "UnSubscribe successful"); + client->event.event_id = MQTT_EVENT_UNSUBSCRIBED; + esp_mqtt_dispatch_event_with_msgid(client); + } + break; + case MQTT_MSG_TYPE_PUBLISH: + if (msg_qos == 1) { + client->mqtt_state.outbound_message = mqtt_msg_puback(&client->mqtt_state.mqtt_connection, msg_id); + } + else if (msg_qos == 2) { + client->mqtt_state.outbound_message = mqtt_msg_pubrec(&client->mqtt_state.mqtt_connection, msg_id); } - } - // Deliver the publish message - client->mqtt_state.message_length_read = read_len - transport_message_offset; - client->mqtt_state.message_length = mqtt_get_total_length(&client->mqtt_state.in_buffer[transport_message_offset], client->mqtt_state.message_length_read); - ESP_LOGD(TAG, "deliver_publish, message_length_read=%d, message_length=%d", read_len, client->mqtt_state.message_length); - deliver_publish(client, &client->mqtt_state.in_buffer[transport_message_offset], client->mqtt_state.message_length_read); - break; - case MQTT_MSG_TYPE_PUBACK: - if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_PUBLISH, msg_id)) { - ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBACK, finish QoS1 publish"); - client->event.event_id = MQTT_EVENT_PUBLISHED; - esp_mqtt_dispatch_event_with_msgid(client); - } + if (msg_qos == 1 || msg_qos == 2) { + ESP_LOGD(TAG, "Queue response QoS: %d", msg_qos); - break; - case MQTT_MSG_TYPE_PUBREC: - ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBREC"); - client->mqtt_state.outbound_message = mqtt_msg_pubrel(&client->mqtt_state.mqtt_connection, msg_id); - mqtt_write_data(client); - break; - case MQTT_MSG_TYPE_PUBREL: - ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBREL"); - client->mqtt_state.outbound_message = mqtt_msg_pubcomp(&client->mqtt_state.mqtt_connection, msg_id); - mqtt_write_data(client); + if (mqtt_write_data(client) != ESP_OK) { + ESP_LOGE(TAG, "Error write qos msg repsonse, qos = %d", msg_qos); + // TODO: Shoule reconnect? + // return ESP_FAIL; + } + } + // Deliver the publish message + ESP_LOGD(TAG, "deliver_publish, message_length_read=%d, message_length=%d", client->mqtt_state.message_length_read, client->mqtt_state.message_length); + deliver_publish(client, &client->mqtt_state.in_buffer[transport_message_offset], client->mqtt_state.message_length_read); + break; + case MQTT_MSG_TYPE_PUBACK: + if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_PUBLISH, msg_id)) { + ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBACK, finish QoS1 publish"); + client->event.event_id = MQTT_EVENT_PUBLISHED; + esp_mqtt_dispatch_event_with_msgid(client); + } - break; - case MQTT_MSG_TYPE_PUBCOMP: - ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBCOMP"); - if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_PUBLISH, msg_id)) { - ESP_LOGD(TAG, "Receive MQTT_MSG_TYPE_PUBCOMP, finish QoS2 publish"); - client->event.event_id = MQTT_EVENT_PUBLISHED; - esp_mqtt_dispatch_event_with_msgid(client); - } - break; - case MQTT_MSG_TYPE_PINGRESP: - ESP_LOGD(TAG, "MQTT_MSG_TYPE_PINGRESP"); - client->wait_for_ping_resp = false; - break; - } + break; + case MQTT_MSG_TYPE_PUBREC: + ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBREC"); + client->mqtt_state.outbound_message = mqtt_msg_pubrel(&client->mqtt_state.mqtt_connection, msg_id); + mqtt_write_data(client); + break; + case MQTT_MSG_TYPE_PUBREL: + ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBREL"); + client->mqtt_state.outbound_message = mqtt_msg_pubcomp(&client->mqtt_state.mqtt_connection, msg_id); + mqtt_write_data(client); - transport_message_offset += mqtt_get_total_length(&client->mqtt_state.in_buffer[transport_message_offset], read_len - transport_message_offset) ; + break; + case MQTT_MSG_TYPE_PUBCOMP: + ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBCOMP"); + if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_PUBLISH, msg_id)) { + ESP_LOGD(TAG, "Receive MQTT_MSG_TYPE_PUBCOMP, finish QoS2 publish"); + client->event.event_id = MQTT_EVENT_PUBLISHED; + esp_mqtt_dispatch_event_with_msgid(client); + } + break; + case MQTT_MSG_TYPE_PINGRESP: + ESP_LOGD(TAG, "MQTT_MSG_TYPE_PINGRESP"); + client->wait_for_ping_resp = false; + break; + } + + transport_message_offset += client->mqtt_state.message_length; } return ESP_OK; From 815623dfe5a0e41fa0e51ab4e336feb3eaa5ba15 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Sat, 2 Feb 2019 16:46:31 +0100 Subject: [PATCH 29/56] improvements on runtime configuration of uri closes https://github.com/espressif/esp-idf/issues/2870 --- mqtt_client.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/mqtt_client.c b/mqtt_client.c index 919189e..93b2219 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -365,11 +365,6 @@ esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *co } } - if (client->config->scheme == NULL) { - client->config->scheme = create_string("mqtt", 4); - ESP_MEM_CHECK(TAG, client->config->scheme, goto _mqtt_init_failed); - } - client->keepalive_tick = platform_tick_get_ms(); client->reconnect_tick = platform_tick_get_ms(); client->refresh_connection_tick = platform_tick_get_ms(); @@ -432,17 +427,15 @@ esp_err_t esp_mqtt_client_set_uri(esp_mqtt_client_handle_t client, const char *u return ESP_FAIL; } - if (client->config->scheme == NULL) { - client->config->scheme = create_string(uri + puri.field_data[UF_SCHEMA].off, puri.field_data[UF_SCHEMA].len); - } + // set uri overrides actual scheme, host, path if configured previously + free(client->config->scheme); + free(client->config->host); + free(client->config->path); - if (client->config->host == NULL) { - client->config->host = create_string(uri + puri.field_data[UF_HOST].off, puri.field_data[UF_HOST].len); - } + client->config->scheme = create_string(uri + puri.field_data[UF_SCHEMA].off, puri.field_data[UF_SCHEMA].len); + client->config->host = create_string(uri + puri.field_data[UF_HOST].off, puri.field_data[UF_HOST].len); + client->config->path = create_string(uri + puri.field_data[UF_PATH].off, puri.field_data[UF_PATH].len); - if (client->config->path == NULL) { - client->config->path = create_string(uri + puri.field_data[UF_PATH].off, puri.field_data[UF_PATH].len); - } if (client->config->path) { esp_transport_handle_t trans = esp_transport_list_get_transport(client->transport_list, "ws"); if (trans) { From 6a0d1e7bff1e3085669d41ae3412c649db20108e Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 20 Dec 2018 21:46:55 +0100 Subject: [PATCH 30/56] support for qos1 and qos2 message retrasmission on reconnect --- lib/include/mqtt_msg.h | 1 + lib/include/mqtt_outbox.h | 12 +++++-- lib/mqtt_outbox.c | 30 ++++++++++++---- mqtt_client.c | 74 ++++++++++++++++++++++++++++++++------- 4 files changed, 96 insertions(+), 21 deletions(-) diff --git a/lib/include/mqtt_msg.h b/lib/include/mqtt_msg.h index 931cbf9..1a07cae 100644 --- a/lib/include/mqtt_msg.h +++ b/lib/include/mqtt_msg.h @@ -106,6 +106,7 @@ static inline int mqtt_get_type(uint8_t* buffer) { return (buffer[0] & 0xf0) >> static inline int mqtt_get_connect_session_present(uint8_t* buffer) { return buffer[2] & 0x01; } static inline int mqtt_get_connect_return_code(uint8_t* buffer) { return buffer[3]; } static inline int mqtt_get_dup(uint8_t* buffer) { return (buffer[0] & 0x08) >> 3; } +static inline void mqtt_set_dup(uint8_t* buffer) { buffer[0] |= 0x08; } static inline int mqtt_get_qos(uint8_t* buffer) { return (buffer[0] & 0x06) >> 1; } static inline int mqtt_get_retain(uint8_t* buffer) { return (buffer[0] & 0x01); } diff --git a/lib/include/mqtt_outbox.h b/lib/include/mqtt_outbox.h index 31dd5b9..b4f1e4f 100644 --- a/lib/include/mqtt_outbox.h +++ b/lib/include/mqtt_outbox.h @@ -21,21 +21,29 @@ typedef struct outbox_message { uint8_t *data; int len; int msg_id; + int msg_qos; int msg_type; uint8_t *remaining_data; int remaining_len; } outbox_message_t; +typedef enum pending_state { + QUEUED, + TRANSMITTED, + CONFIRMED +} pending_state_t; + outbox_handle_t outbox_init(); outbox_item_handle_t outbox_enqueue(outbox_handle_t outbox, outbox_message_handle_t message, int tick); -outbox_item_handle_t outbox_dequeue(outbox_handle_t outbox); +outbox_item_handle_t outbox_dequeue(outbox_handle_t outbox, pending_state_t pending); outbox_item_handle_t outbox_get(outbox_handle_t outbox, int msg_id); +uint8_t* outbox_item_get_data(outbox_item_handle_t item, size_t *len, uint16_t *msg_id, int *msg_type, int *qos); esp_err_t outbox_delete(outbox_handle_t outbox, int msg_id, int msg_type); esp_err_t outbox_delete_msgid(outbox_handle_t outbox, int msg_id); esp_err_t outbox_delete_msgtype(outbox_handle_t outbox, int msg_type); esp_err_t outbox_delete_expired(outbox_handle_t outbox, int current_tick, int timeout); -esp_err_t outbox_set_pending(outbox_handle_t outbox, int msg_id); +esp_err_t outbox_set_pending(outbox_handle_t outbox, int msg_id, pending_state_t pending); int outbox_get_size(outbox_handle_t outbox); esp_err_t outbox_cleanup(outbox_handle_t outbox, int max_size); void outbox_destroy(outbox_handle_t outbox); diff --git a/lib/mqtt_outbox.c b/lib/mqtt_outbox.c index 6d6efc5..403fd9c 100644 --- a/lib/mqtt_outbox.c +++ b/lib/mqtt_outbox.c @@ -14,9 +14,10 @@ typedef struct outbox_item { int len; int msg_id; int msg_type; + int msg_qos; int tick; int retry_count; - bool pending; + pending_state_t pending; STAILQ_ENTRY(outbox_item) next; } outbox_item_t; @@ -37,8 +38,10 @@ outbox_item_handle_t outbox_enqueue(outbox_handle_t outbox, outbox_message_handl ESP_MEM_CHECK(TAG, item, return NULL); item->msg_id = message->msg_id; item->msg_type = message->msg_type; + item->msg_qos = message->msg_qos; item->tick = tick; item->len = message->len; + item->pending = QUEUED; item->buffer = malloc(message->len + message->remaining_len); ESP_MEM_CHECK(TAG, item->buffer, { free(item); @@ -64,21 +67,34 @@ outbox_item_handle_t outbox_get(outbox_handle_t outbox, int msg_id) return NULL; } -outbox_item_handle_t outbox_dequeue(outbox_handle_t outbox) +outbox_item_handle_t outbox_dequeue(outbox_handle_t outbox, pending_state_t pending) { outbox_item_handle_t item; STAILQ_FOREACH(item, outbox, next) { - if (!item->pending) { + if (item->pending == pending) { return item; } } return NULL; } + +uint8_t* outbox_item_get_data(outbox_item_handle_t item, size_t *len, uint16_t *msg_id, int *msg_type, int *qos) +{ + if (item) { + *len = item->len; + *msg_id = item->msg_id; + *msg_type = item->msg_type; + *qos = item->msg_qos; + return (uint8_t*)item->buffer; + } + return NULL; +} + esp_err_t outbox_delete(outbox_handle_t outbox, int msg_id, int msg_type) { outbox_item_handle_t item, tmp; STAILQ_FOREACH_SAFE(item, outbox, next, tmp) { - if (item->msg_id == msg_id && item->msg_type == msg_type) { + if (item->msg_id == msg_id && (0xFF&(item->msg_type)) == msg_type) { STAILQ_REMOVE(outbox, item, outbox_item, next); free(item->buffer); free(item); @@ -102,11 +118,11 @@ esp_err_t outbox_delete_msgid(outbox_handle_t outbox, int msg_id) } return ESP_OK; } -esp_err_t outbox_set_pending(outbox_handle_t outbox, int msg_id) +esp_err_t outbox_set_pending(outbox_handle_t outbox, int msg_id, pending_state_t pending) { outbox_item_handle_t item = outbox_get(outbox, msg_id); if (item) { - item->pending = true; + item->pending = pending; return ESP_OK; } return ESP_FAIL; @@ -153,7 +169,7 @@ int outbox_get_size(outbox_handle_t outbox) esp_err_t outbox_cleanup(outbox_handle_t outbox, int max_size) { while(outbox_get_size(outbox) > max_size) { - outbox_item_handle_t item = outbox_dequeue(outbox); + outbox_item_handle_t item = outbox_dequeue(outbox, CONFIRMED); if (item == NULL) { return ESP_FAIL; } diff --git a/mqtt_client.c b/mqtt_client.c index 93b2219..73d3624 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -200,7 +200,6 @@ esp_err_t esp_mqtt_set_config(esp_mqtt_client_handle_t client, const esp_mqtt_cl if (config->disable_auto_reconnect == cfg->auto_reconnect) { cfg->auto_reconnect = !config->disable_auto_reconnect; } - return ESP_OK; _mqtt_set_config_failed: esp_mqtt_destroy_config(client); @@ -305,7 +304,6 @@ esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *co ESP_MEM_CHECK(TAG, client, return NULL); esp_mqtt_set_config(client, config); - client->transport_list = esp_transport_list_init(); ESP_MEM_CHECK(TAG, client->transport_list, goto _mqtt_init_failed); @@ -605,6 +603,7 @@ static void mqtt_enqueue_oversized(esp_mqtt_client_handle_t client, uint8_t *rem msg.len = client->mqtt_state.outbound_message->length; msg.msg_id = client->mqtt_state.pending_msg_id; msg.msg_type = client->mqtt_state.pending_msg_type; + msg.msg_qos = client->mqtt_state.pending_publish_qos; msg.remaining_data = remaining_data; msg.remaining_len = remaining_len; //Copy to queue buffer @@ -624,6 +623,7 @@ static void mqtt_enqueue(esp_mqtt_client_handle_t client) msg.len = client->mqtt_state.outbound_message->length; msg.msg_id = client->mqtt_state.pending_msg_id; msg.msg_type = client->mqtt_state.pending_msg_type; + msg.msg_qos = client->mqtt_state.pending_publish_qos; //Copy to queue buffer outbox_enqueue(client->outbox, &msg, platform_tick_get_ms()); } @@ -700,21 +700,21 @@ static esp_err_t mqtt_process_receive(esp_mqtt_client_handle_t client) case MQTT_MSG_TYPE_PUBACK: if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_PUBLISH, msg_id)) { ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBACK, finish QoS1 publish"); + outbox_set_pending(client->outbox, msg_id, CONFIRMED); client->event.event_id = MQTT_EVENT_PUBLISHED; esp_mqtt_dispatch_event_with_msgid(client); } - break; case MQTT_MSG_TYPE_PUBREC: ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBREC"); client->mqtt_state.outbound_message = mqtt_msg_pubrel(&client->mqtt_state.mqtt_connection, msg_id); + outbox_set_pending(client->outbox, msg_id, CONFIRMED); mqtt_write_data(client); break; case MQTT_MSG_TYPE_PUBREL: ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBREL"); client->mqtt_state.outbound_message = mqtt_msg_pubcomp(&client->mqtt_state.mqtt_connection, msg_id); mqtt_write_data(client); - break; case MQTT_MSG_TYPE_PUBCOMP: ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBCOMP"); @@ -736,9 +736,29 @@ static esp_err_t mqtt_process_receive(esp_mqtt_client_handle_t client) return ESP_OK; } +static esp_err_t mqtt_resend_queued(esp_mqtt_client_handle_t client, outbox_item_handle_t item) +{ + // decode queued data + client->mqtt_state.outbound_message->data = outbox_item_get_data(item, &client->mqtt_state.outbound_message->length, &client->mqtt_state.pending_msg_id, + &client->mqtt_state.pending_msg_type, &client->mqtt_state.pending_publish_qos); + // set duplicate flag for QoS-2 message + if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH &&client->mqtt_state.pending_publish_qos==2) { + mqtt_set_dup(client->mqtt_state.outbound_message->data); + } + + // try to resend the data + if (mqtt_write_data(client) != ESP_OK) { + ESP_LOGE(TAG, "Error to public data "); + esp_mqtt_abort_connection(client); + return ESP_FAIL; + } + return ESP_OK; +} + static void esp_mqtt_task(void *pv) { esp_mqtt_client_handle_t client = (esp_mqtt_client_handle_t) pv; + uint32_t last_retransmit = 0; client->run = true; //get transport by scheme @@ -796,6 +816,21 @@ static void esp_mqtt_task(void *pv) break; } + // resend all non-transmitted messages first + outbox_item_handle_t item = outbox_dequeue(client->outbox, QUEUED); + if (item) { + if (mqtt_resend_queued(client, item) == ESP_OK) { + outbox_set_pending(client->outbox, client->mqtt_state.pending_msg_id, TRANSMITTED); + } + // resend other "transmitted" messages after 1s + } else if (platform_tick_get_ms() - last_retransmit > 1000) { + last_retransmit = platform_tick_get_ms(); + item = outbox_dequeue(client->outbox, TRANSMITTED); + if (item) { + mqtt_resend_queued(client, item); + } + } + if (platform_tick_get_ms() - client->keepalive_tick > client->connect_info.keepalive * 1000 / 2) { //No ping resp from last ping => Disconnected if(client->wait_for_ping_resp){ @@ -914,13 +949,13 @@ int esp_mqtt_client_subscribe(esp_mqtt_client_handle_t client, const char *topic ESP_LOGE(TAG, "Client has not connected"); return -1; } - mqtt_enqueue(client); //move pending msg to outbox (if have) client->mqtt_state.outbound_message = mqtt_msg_subscribe(&client->mqtt_state.mqtt_connection, topic, qos, &client->mqtt_state.pending_msg_id); client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data); client->mqtt_state.pending_msg_count ++; + mqtt_enqueue(client); //move pending msg to outbox (if have) if (mqtt_write_data(client) != ESP_OK) { ESP_LOGE(TAG, "Error to subscribe topic=%s, qos=%d", topic, qos); @@ -958,10 +993,7 @@ int esp_mqtt_client_unsubscribe(esp_mqtt_client_handle_t client, const char *top int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, const char *data, int len, int qos, int retain) { uint16_t pending_msg_id = 0; - if (client->state != MQTT_STATE_CONNECTED) { - ESP_LOGE(TAG, "Client has not connected"); - return -1; - } + if (len <= 0) { len = strlen(data); } @@ -973,15 +1005,23 @@ int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, /* We have to set as pending all the qos>0 messages) */ if (qos > 0) { - mqtt_enqueue(client); client->mqtt_state.outbound_message = publish_msg; client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data); client->mqtt_state.pending_msg_id = pending_msg_id; + client->mqtt_state.pending_publish_qos = qos; client->mqtt_state.pending_msg_count ++; + // by default store as QUEUED (not transmitted yet) + mqtt_enqueue(client); } else { client->mqtt_state.outbound_message = publish_msg; } + /* Skip sending if not connected (rely on resending) */ + if (client->state != MQTT_STATE_CONNECTED) { + ESP_LOGD(TAG, "Publish: client is not connected"); + goto cannot_publish; + } + /* Provide support for sending fragmented message if it doesn't fit buffer */ int remaining_len = len; const char *current_data = data; @@ -990,8 +1030,8 @@ int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, while (sending) { if (mqtt_write_data(client) != ESP_OK) { - ESP_LOGE(TAG, "Error to public data to topic=%s, qos=%d", topic, qos); - return -1; + esp_mqtt_abort_connection(client); + goto cannot_publish; } int data_sent = client->mqtt_state.outbound_message->length - client->mqtt_state.outbound_message->fragmented_msg_data_offset; @@ -1028,7 +1068,17 @@ int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, sending = false; } } + + if (qos > 0) { + outbox_set_pending(client->outbox, pending_msg_id, TRANSMITTED); + } return pending_msg_id; + +cannot_publish: + if (qos == 0) { + ESP_LOGW(TAG, "Publishing qos0 data while client not connecting"); + } + return 0; } From 752953dc3be007cca4255b66a35d3087e61f6a54 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Fri, 21 Dec 2018 13:52:48 +0100 Subject: [PATCH 31/56] added mqtt api locks, so methods can be executed from user context closes #67, closes #90, closes https://github.com/espressif/esp-idf/issues/2975 --- include/mqtt_config.h | 17 +++++++---- mqtt_client.c | 65 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 67 insertions(+), 15 deletions(-) diff --git a/include/mqtt_config.h b/include/mqtt_config.h index c0b4ab7..972f2a1 100644 --- a/include/mqtt_config.h +++ b/include/mqtt_config.h @@ -10,6 +10,7 @@ #define MQTT_PROTOCOL_311 CONFIG_MQTT_PROTOCOL_311 #define MQTT_RECONNECT_TIMEOUT_MS (10*1000) +#define MQTT_POLL_READ_TIMEOUT_MS (1000) #if CONFIG_MQTT_BUFFER_SIZE #define MQTT_BUFFER_SIZE_BYTE CONFIG_MQTT_BUFFER_SIZE @@ -61,14 +62,18 @@ #define MQTT_CORE_SELECTION_ENABLED CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED +#ifdef CONFIG_MQTT_DISABLE_API_LOCKS +#define MQTT_DISABLE_API_LOCKS CONFIG_MQTT_DISABLE_API_LOCKS +#endif + #ifdef CONFIG_MQTT_USE_CORE_0 - #define MQTT_TASK_CORE 0 + #define MQTT_TASK_CORE 0 #else - #ifdef CONFIG_MQTT_USE_CORE_1 - #define MQTT_TASK_CORE 1 - #else - #define MQTT_TASK_CORE 0 - #endif + #ifdef CONFIG_MQTT_USE_CORE_1 + #define MQTT_TASK_CORE 1 + #else + #define MQTT_TASK_CORE 0 + #endif #endif diff --git a/mqtt_client.c b/mqtt_client.c index 73d3624..8fe31cc 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -13,6 +13,18 @@ /* using uri parser */ #include "http_parser.h" +#ifdef MQTT_DISABLE_API_LOCKS +# define MQTT_API_LOCK(c) +# define MQTT_API_UNLOCK(c) +# define MQTT_API_LOCK_FROM_OTHER_TASK(c) +# define MQTT_API_UNLOCK_FROM_OTHER_TASK(c) +#else +# define MQTT_API_LOCK(c) xSemaphoreTake(c->api_lock, portMAX_DELAY) +# define MQTT_API_UNLOCK(c) xSemaphoreGive(c->api_lock) +# define MQTT_API_LOCK_FROM_OTHER_TASK(c) { if (c->task_handle != xTaskGetCurrentTaskHandle()) { xSemaphoreTake(c->api_lock, portMAX_DELAY); } } +# define MQTT_API_UNLOCK_FROM_OTHER_TASK(c) { if (c->task_handle != xTaskGetCurrentTaskHandle()) { xSemaphoreGive(c->api_lock); } } +#endif /* MQTT_USE_API_LOCKS */ + static const char *TAG = "MQTT_CLIENT"; typedef struct mqtt_state @@ -72,6 +84,8 @@ struct esp_mqtt_client { bool wait_for_ping_resp; outbox_handle_t outbox; EventGroupHandle_t status_bits; + SemaphoreHandle_t api_lock; + TaskHandle_t task_handle; }; const static int STOPPED_BIT = BIT0; @@ -87,6 +101,7 @@ static char *create_string(const char *ptr, int len); esp_err_t esp_mqtt_set_config(esp_mqtt_client_handle_t client, const esp_mqtt_client_config_t *config) { + MQTT_API_LOCK(client); //Copy user configurations to client context esp_err_t err = ESP_OK; mqtt_config_storage_t *cfg; @@ -94,7 +109,10 @@ esp_err_t esp_mqtt_set_config(esp_mqtt_client_handle_t client, const esp_mqtt_cl cfg = client->config; } else { cfg = calloc(1, sizeof(mqtt_config_storage_t)); - ESP_MEM_CHECK(TAG, cfg, return ESP_ERR_NO_MEM); + ESP_MEM_CHECK(TAG, cfg, { + MQTT_API_UNLOCK(client); + return ESP_ERR_NO_MEM; + }); client->config = cfg; } if (config->task_prio) { @@ -200,9 +218,11 @@ esp_err_t esp_mqtt_set_config(esp_mqtt_client_handle_t client, const esp_mqtt_cl if (config->disable_auto_reconnect == cfg->auto_reconnect) { cfg->auto_reconnect = !config->disable_auto_reconnect; } + MQTT_API_UNLOCK(client); return ESP_OK; _mqtt_set_config_failed: esp_mqtt_destroy_config(client); + MQTT_API_UNLOCK(client); return err; } @@ -302,8 +322,13 @@ 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->api_lock = xSemaphoreCreateMutex(); + if (!client->api_lock) { + free(client); + return NULL; + } esp_mqtt_set_config(client, config); + MQTT_API_LOCK(client); client->transport_list = esp_transport_list_init(); ESP_MEM_CHECK(TAG, client->transport_list, goto _mqtt_init_failed); @@ -384,9 +409,11 @@ esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *co ESP_MEM_CHECK(TAG, client->outbox, goto _mqtt_init_failed); client->status_bits = xEventGroupCreate(); ESP_MEM_CHECK(TAG, client->status_bits, goto _mqtt_init_failed); + MQTT_API_UNLOCK(client); return client; _mqtt_init_failed: esp_mqtt_client_destroy(client); + MQTT_API_UNLOCK(client); return NULL; } @@ -399,6 +426,7 @@ esp_err_t esp_mqtt_client_destroy(esp_mqtt_client_handle_t client) vEventGroupDelete(client->status_bits); free(client->mqtt_state.in_buffer); free(client->mqtt_state.out_buffer); + vSemaphoreDelete(client->api_lock); free(client); return ESP_OK; } @@ -638,7 +666,7 @@ static esp_err_t mqtt_process_receive(esp_mqtt_client_handle_t client) uint16_t msg_id; uint32_t transport_message_offset = 0 ; - read_len = esp_transport_read(client->transport, (char *)client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length, 1000); + read_len = esp_transport_read(client->transport, (char *)client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length, 0); if (read_len < 0) { ESP_LOGE(TAG, "Read error or end of stream"); @@ -776,7 +804,7 @@ static void esp_mqtt_task(void *pv) client->state = MQTT_STATE_INIT; xEventGroupClearBits(client->status_bits, STOPPED_BIT); while (client->run) { - + MQTT_API_LOCK(client); switch ((int)client->state) { case MQTT_STATE_INIT: xEventGroupClearBits(client->status_bits, RECONNECT_BIT); @@ -873,10 +901,20 @@ static void esp_mqtt_task(void *pv) ESP_LOGD(TAG, "Reconnecting..."); break; } + MQTT_API_UNLOCK(client); xEventGroupWaitBits(client->status_bits, RECONNECT_BIT, false, true, client->wait_timeout_ms / 2 / portTICK_RATE_MS); - break; + // continue the while loop insted of break, as the mutex is unlocked + continue; } + MQTT_API_UNLOCK(client); + if (MQTT_STATE_CONNECTED == client->state) { + if (esp_transport_poll_read(client->transport, MQTT_POLL_READ_TIMEOUT_MS) < 0) { + ESP_LOGE(TAG, "Poll read error: %d, aborting connection", errno); + esp_mqtt_abort_connection(client); + } + } + } esp_transport_close(client->transport); xEventGroupSetBits(client->status_bits, STOPPED_BIT); @@ -892,13 +930,13 @@ esp_err_t esp_mqtt_client_start(esp_mqtt_client_handle_t client) } #if MQTT_CORE_SELECTION_ENABLED ESP_LOGD(TAG, "Core selection enabled on %u", MQTT_TASK_CORE); - if (xTaskCreatePinnedToCore(esp_mqtt_task, "mqtt_task", client->config->task_stack, client, client->config->task_prio, NULL, MQTT_TASK_CORE) != pdTRUE) { + if (xTaskCreatePinnedToCore(esp_mqtt_task, "mqtt_task", client->config->task_stack, client, client->config->task_prio, &client->task_handle, MQTT_TASK_CORE) != pdTRUE) { ESP_LOGE(TAG, "Error create mqtt task"); return ESP_FAIL; } #else ESP_LOGD(TAG, "Core selection disabled"); - if (xTaskCreate(esp_mqtt_task, "mqtt_task", client->config->task_stack, client, client->config->task_prio, NULL) != pdTRUE) { + if (xTaskCreate(esp_mqtt_task, "mqtt_task", client->config->task_stack, client, client->config->task_prio, &client->task_handle) != pdTRUE) { ESP_LOGE(TAG, "Error create mqtt task"); return ESP_FAIL; } @@ -949,6 +987,7 @@ int esp_mqtt_client_subscribe(esp_mqtt_client_handle_t client, const char *topic ESP_LOGE(TAG, "Client has not connected"); return -1; } + MQTT_API_LOCK_FROM_OTHER_TASK(client); client->mqtt_state.outbound_message = mqtt_msg_subscribe(&client->mqtt_state.mqtt_connection, topic, qos, &client->mqtt_state.pending_msg_id); @@ -959,10 +998,12 @@ int esp_mqtt_client_subscribe(esp_mqtt_client_handle_t client, const char *topic if (mqtt_write_data(client) != ESP_OK) { ESP_LOGE(TAG, "Error to subscribe topic=%s, qos=%d", topic, qos); + MQTT_API_UNLOCK_FROM_OTHER_TASK(client); return -1; } ESP_LOGD(TAG, "Sent subscribe topic=%s, id: %d, type=%d successful", topic, client->mqtt_state.pending_msg_id, client->mqtt_state.pending_msg_type); + MQTT_API_UNLOCK_FROM_OTHER_TASK(client); return client->mqtt_state.pending_msg_id; } @@ -972,7 +1013,7 @@ int esp_mqtt_client_unsubscribe(esp_mqtt_client_handle_t client, const char *top ESP_LOGE(TAG, "Client has not connected"); return -1; } - mqtt_enqueue(client); + MQTT_API_LOCK_FROM_OTHER_TASK(client); client->mqtt_state.outbound_message = mqtt_msg_unsubscribe(&client->mqtt_state.mqtt_connection, topic, &client->mqtt_state.pending_msg_id); @@ -980,13 +1021,16 @@ int esp_mqtt_client_unsubscribe(esp_mqtt_client_handle_t client, const char *top client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data); client->mqtt_state.pending_msg_count ++; + mqtt_enqueue(client); if (mqtt_write_data(client) != ESP_OK) { ESP_LOGE(TAG, "Error to unsubscribe topic=%s", topic); + MQTT_API_UNLOCK_FROM_OTHER_TASK(client); return -1; } ESP_LOGD(TAG, "Sent Unsubscribe topic=%s, id: %d, successful", topic, client->mqtt_state.pending_msg_id); + MQTT_API_UNLOCK_FROM_OTHER_TASK(client); return client->mqtt_state.pending_msg_id; } @@ -998,6 +1042,7 @@ int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, len = strlen(data); } + MQTT_API_LOCK_FROM_OTHER_TASK(client); mqtt_message_t *publish_msg = mqtt_msg_publish(&client->mqtt_state.mqtt_connection, topic, data, len, qos, retain, @@ -1072,12 +1117,14 @@ int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, if (qos > 0) { outbox_set_pending(client->outbox, pending_msg_id, TRANSMITTED); } + MQTT_API_UNLOCK_FROM_OTHER_TASK(client); return pending_msg_id; cannot_publish: if (qos == 0) { - ESP_LOGW(TAG, "Publishing qos0 data while client not connecting"); + ESP_LOGW(TAG, "Publish: Loosing qos0 data when client not connected"); } + MQTT_API_UNLOCK_FROM_OTHER_TASK(client); return 0; } From 51089629f79051d55bf7780771f88d51c5e9c2dc Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 5 Feb 2019 17:01:54 +0100 Subject: [PATCH 32/56] corrected outbox for oversized messge and qos1, added errno to error messages --- lib/include/mqtt_outbox.h | 2 +- lib/mqtt_outbox.c | 9 ++++++--- mqtt_client.c | 22 +++++++++++----------- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/lib/include/mqtt_outbox.h b/lib/include/mqtt_outbox.h index b4f1e4f..c9422e9 100644 --- a/lib/include/mqtt_outbox.h +++ b/lib/include/mqtt_outbox.h @@ -35,7 +35,7 @@ typedef enum pending_state { outbox_handle_t outbox_init(); outbox_item_handle_t outbox_enqueue(outbox_handle_t outbox, outbox_message_handle_t message, int tick); -outbox_item_handle_t outbox_dequeue(outbox_handle_t outbox, pending_state_t pending); +outbox_item_handle_t outbox_dequeue(outbox_handle_t outbox, pending_state_t pending, int *tick); outbox_item_handle_t outbox_get(outbox_handle_t outbox, int msg_id); uint8_t* outbox_item_get_data(outbox_item_handle_t item, size_t *len, uint16_t *msg_id, int *msg_type, int *qos); esp_err_t outbox_delete(outbox_handle_t outbox, int msg_id, int msg_type); diff --git a/lib/mqtt_outbox.c b/lib/mqtt_outbox.c index 403fd9c..933d55a 100644 --- a/lib/mqtt_outbox.c +++ b/lib/mqtt_outbox.c @@ -40,7 +40,7 @@ outbox_item_handle_t outbox_enqueue(outbox_handle_t outbox, outbox_message_handl item->msg_type = message->msg_type; item->msg_qos = message->msg_qos; item->tick = tick; - item->len = message->len; + item->len = message->len + message->remaining_len; item->pending = QUEUED; item->buffer = malloc(message->len + message->remaining_len); ESP_MEM_CHECK(TAG, item->buffer, { @@ -67,11 +67,14 @@ outbox_item_handle_t outbox_get(outbox_handle_t outbox, int msg_id) return NULL; } -outbox_item_handle_t outbox_dequeue(outbox_handle_t outbox, pending_state_t pending) +outbox_item_handle_t outbox_dequeue(outbox_handle_t outbox, pending_state_t pending, int *tick) { outbox_item_handle_t item; STAILQ_FOREACH(item, outbox, next) { if (item->pending == pending) { + if (tick) { + *tick = item->tick; + } return item; } } @@ -169,7 +172,7 @@ int outbox_get_size(outbox_handle_t outbox) esp_err_t outbox_cleanup(outbox_handle_t outbox, int max_size) { while(outbox_get_size(outbox) > max_size) { - outbox_item_handle_t item = outbox_dequeue(outbox, CONFIRMED); + outbox_item_handle_t item = outbox_dequeue(outbox, CONFIRMED, NULL); if (item == NULL) { return ESP_FAIL; } diff --git a/mqtt_client.c b/mqtt_client.c index 8fe31cc..c409222 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -501,7 +501,7 @@ static esp_err_t mqtt_write_data(esp_mqtt_client_handle_t client) client->config->network_timeout_ms); // client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data); if (write_len <= 0) { - ESP_LOGE(TAG, "Error write data or timeout, written len = %d", write_len); + ESP_LOGE(TAG, "Error write data or timeout, written len = %d, errno=%d", write_len, errno); return ESP_FAIL; } /* we've just sent a mqtt control packet, update keepalive counter @@ -624,9 +624,6 @@ static void mqtt_enqueue_oversized(esp_mqtt_client_handle_t client, uint8_t *rem client->mqtt_state.pending_msg_id, client->mqtt_state.pending_msg_type); //lock mutex outbox_message_t msg = { 0 }; - if (client->mqtt_state.pending_msg_count > 0) { - client->mqtt_state.pending_msg_count --; - } msg.data = client->mqtt_state.outbound_message->data; msg.len = client->mqtt_state.outbound_message->length; msg.msg_id = client->mqtt_state.pending_msg_id; @@ -669,7 +666,7 @@ static esp_err_t mqtt_process_receive(esp_mqtt_client_handle_t client) read_len = esp_transport_read(client->transport, (char *)client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length, 0); if (read_len < 0) { - ESP_LOGE(TAG, "Read error or end of stream"); + ESP_LOGE(TAG, "Read error or end of stream, errno:%d", errno); return ESP_FAIL; } @@ -787,6 +784,7 @@ static void esp_mqtt_task(void *pv) { esp_mqtt_client_handle_t client = (esp_mqtt_client_handle_t) pv; uint32_t last_retransmit = 0; + int32_t msg_tick = 0; client->run = true; //get transport by scheme @@ -845,7 +843,7 @@ static void esp_mqtt_task(void *pv) } // resend all non-transmitted messages first - outbox_item_handle_t item = outbox_dequeue(client->outbox, QUEUED); + outbox_item_handle_t item = outbox_dequeue(client->outbox, QUEUED, NULL); if (item) { if (mqtt_resend_queued(client, item) == ESP_OK) { outbox_set_pending(client->outbox, client->mqtt_state.pending_msg_id, TRANSMITTED); @@ -853,8 +851,8 @@ static void esp_mqtt_task(void *pv) // resend other "transmitted" messages after 1s } else if (platform_tick_get_ms() - last_retransmit > 1000) { last_retransmit = platform_tick_get_ms(); - item = outbox_dequeue(client->outbox, TRANSMITTED); - if (item) { + item = outbox_dequeue(client->outbox, TRANSMITTED, &msg_tick); + if (item && (last_retransmit - msg_tick > 1000)) { mqtt_resend_queued(client, item); } } @@ -1048,15 +1046,17 @@ int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, qos, retain, &pending_msg_id); - /* We have to set as pending all the qos>0 messages) */ + /* We have to set as pending all the qos>0 messages */ if (qos > 0) { client->mqtt_state.outbound_message = publish_msg; client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data); client->mqtt_state.pending_msg_id = pending_msg_id; client->mqtt_state.pending_publish_qos = qos; client->mqtt_state.pending_msg_count ++; - // by default store as QUEUED (not transmitted yet) - mqtt_enqueue(client); + // by default store as QUEUED (not transmitted yet) only for messages which would fit outbound buffer + if (client->mqtt_state.mqtt_connection.message.fragmented_msg_total_length == 0) { + mqtt_enqueue(client); + } } else { client->mqtt_state.outbound_message = publish_msg; } From 3300338c854e79e4bb78b0f9f99e04d4cfcbf4b9 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Mon, 11 Feb 2019 14:51:39 +0100 Subject: [PATCH 33/56] tabs to spaces corrections --- mqtt_client.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mqtt_client.c b/mqtt_client.c index c409222..8503d78 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -859,20 +859,20 @@ static void esp_mqtt_task(void *pv) if (platform_tick_get_ms() - client->keepalive_tick > client->connect_info.keepalive * 1000 / 2) { //No ping resp from last ping => Disconnected - if(client->wait_for_ping_resp){ - ESP_LOGE(TAG, "No PING_RESP, disconnected"); - esp_mqtt_abort_connection(client); - client->wait_for_ping_resp = false; - break; + if(client->wait_for_ping_resp){ + ESP_LOGE(TAG, "No PING_RESP, disconnected"); + esp_mqtt_abort_connection(client); + client->wait_for_ping_resp = false; + break; } - if (esp_mqtt_client_ping(client) == ESP_FAIL) { + if (esp_mqtt_client_ping(client) == ESP_FAIL) { ESP_LOGE(TAG, "Can't send ping, disconnected"); esp_mqtt_abort_connection(client); break; } else { - client->wait_for_ping_resp = true; + client->wait_for_ping_resp = true; } - ESP_LOGD(TAG, "PING sent"); + ESP_LOGD(TAG, "PING sent"); } if (client->config->refresh_connection_after_ms && From 57d27744620ec7ab68ef77f853a943de0f446130 Mon Sep 17 00:00:00 2001 From: leewo0 <46703877+leewo0@users.noreply.github.com> Date: Tue, 15 Jan 2019 15:40:07 +0800 Subject: [PATCH 34/56] fix bug: client->state not set If auto_reconnect is disabled, client->state won't be setted in MQTT_STATE_WAIT_TIMEOUT statement, which results in an error if esp_mqtt_client_start() is called. --- mqtt_client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mqtt_client.c b/mqtt_client.c index 8503d78..159cefa 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -891,6 +891,7 @@ static void esp_mqtt_task(void *pv) if (!client->config->auto_reconnect) { client->run = false; + client->state = MQTT_STATE_UNKNOWN; break; } if (platform_tick_get_ms() - client->reconnect_tick > client->wait_timeout_ms) { From ca373e22cba75c24c2fc4ebfbece3d482a0c64b8 Mon Sep 17 00:00:00 2001 From: suda-morris <362953310@qq.com> Date: Thu, 14 Mar 2019 20:26:28 +0800 Subject: [PATCH 35/56] change rom/queue.h to sys/queue.h --- lib/include/platform_esp32_idf.h | 2 +- lib/mqtt_outbox.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/include/platform_esp32_idf.h b/lib/include/platform_esp32_idf.h index 553a57d..b25b5db 100644 --- a/lib/include/platform_esp32_idf.h +++ b/lib/include/platform_esp32_idf.h @@ -18,7 +18,7 @@ #include "lwip/netdb.h" #include "lwip/dns.h" -#include "rom/queue.h" +#include "sys/queue.h" #include "esp_err.h" #include "esp_log.h" #include "esp_system.h" diff --git a/lib/mqtt_outbox.c b/lib/mqtt_outbox.c index 933d55a..2ef3689 100644 --- a/lib/mqtt_outbox.c +++ b/lib/mqtt_outbox.c @@ -1,7 +1,7 @@ #include "mqtt_outbox.h" #include #include -#include "rom/queue.h" +#include "sys/queue.h" #include "esp_log.h" #ifndef CONFIG_MQTT_CUSTOM_OUTBOX @@ -189,4 +189,4 @@ void outbox_destroy(outbox_handle_t outbox) free(outbox); } -#endif /* CONFIG_MQTT_CUSTOM_OUTBOX */ \ No newline at end of file +#endif /* CONFIG_MQTT_CUSTOM_OUTBOX */ From caf5007b99df985b330683dfe2fa454c94633018 Mon Sep 17 00:00:00 2001 From: Gregory Eslinger Date: Fri, 22 Mar 2019 21:10:10 +0100 Subject: [PATCH 36/56] MQTT Client: Added disconnect message on client stop Closes https://github.com/espressif/esp-mqtt/issues/97 and closes https://github.com/espressif/esp-idf/issues/3215 --- mqtt_client.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mqtt_client.c b/mqtt_client.c index 159cefa..87c9541 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -958,6 +958,14 @@ esp_err_t esp_mqtt_client_reconnect(esp_mqtt_client_handle_t client) esp_err_t esp_mqtt_client_stop(esp_mqtt_client_handle_t client) { if (client->run) { + // Notify the broker we are disconnecting + MQTT_API_LOCK_FROM_OTHER_TASK(client); + client->mqtt_state.outbound_message = mqtt_msg_disconnect(&client->mqtt_state.mqtt_connection); + if (mqtt_write_data(client) != ESP_OK) { + ESP_LOGE(TAG, "Error sending disconnect message"); + } + MQTT_API_UNLOCK_FROM_OTHER_TASK(client); + client->run = false; xEventGroupWaitBits(client->status_bits, STOPPED_BIT, false, true, portMAX_DELAY); client->state = MQTT_STATE_UNKNOWN; From 9d70713b2e6422289b54240e59f77f85acdda1c5 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 2 Apr 2019 11:39:16 +0200 Subject: [PATCH 37/56] ci: fixed incorrect git checkout submodules causing build failures when switching between IDF releases --- .gitlab-ci.yml | 2 +- .travis.yml | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c628af5..aa8921e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -39,7 +39,7 @@ build_with_idf: - cd $IDF_PATH/components/mqtt/esp-mqtt - rm -rf .git - cp -r $CI_PROJECT_DIR/.git . - - git checkout $CI_COMMIT_SHA + - git reset --hard $CI_COMMIT_SHA # build one example and capture compile commands/flags for static analysis - cd $IDF_PATH/examples/protocols/mqtt/tcp - export PEDANTIC_CFLAGS="-Werror -Werror=deprecated-declarations -Werror=unused-variable -Werror=unused-but-set-variable -Werror=unused-function" diff --git a/.travis.yml b/.travis.yml index 521d293..5f1a823 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,8 +29,8 @@ install: # Download binary toolchain for the ESP32 - wget https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz - tar -xzf xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz - # Get ESP-IDF from github - - git clone --recursive https://github.com/espressif/esp-idf.git + # Get ESP-IDF from github (non-recursive to save time, later we update submodules for different versions) + - git clone https://github.com/espressif/esp-idf.git # Set the path to ESP-IDF directory - export IDF_PATH=~/esp/esp-idf - python -m pip install --user -r $IDF_PATH/requirements.txt @@ -39,18 +39,20 @@ install: script: # Legacy build with IDF < 3.2 - - cd $IDF_PATH && git checkout --recurse-submodules v3.1 + - cd $IDF_PATH + - git checkout v3.1 && git submodule update --init --recursive - cd $PROJECT_PATH - ./modify_for_legacy_idf.sh || true - cd $PROJECT_PATH/examples/tcp - make defconfig - make -j4 # Master build with latest IDF - - cd $IDF_PATH && git checkout --recurse-submodules master + - cd $IDF_PATH + - git checkout master && git submodule update --init --recursive - cd $IDF_PATH/components/mqtt/esp-mqtt - git remote add local $PROJECT_PATH/.git - git fetch local - - git checkout $CI_COMMIT_SHA + - git reset --hard $CI_COMMIT_SHA - cd $IDF_PATH/examples/protocols/mqtt/tcp - idf.py build - cd $IDF_PATH/examples/protocols/mqtt/ssl From 0450bd0093978b8e6a7bd78e5b278dea9bbe212b Mon Sep 17 00:00:00 2001 From: Gregory Eslinger Date: Mon, 1 Apr 2019 21:22:21 +0200 Subject: [PATCH 38/56] MQTT Client: Added support for receiving empty payload --- lib/include/mqtt_msg.h | 1 + lib/mqtt_msg.c | 33 ++++++++++++++++++++++++++++++ mqtt_client.c | 46 +++++++++++++++++++++++++++++++----------- 3 files changed, 68 insertions(+), 12 deletions(-) diff --git a/lib/include/mqtt_msg.h b/lib/include/mqtt_msg.h index 1a07cae..d57a5c5 100644 --- a/lib/include/mqtt_msg.h +++ b/lib/include/mqtt_msg.h @@ -111,6 +111,7 @@ static inline int mqtt_get_qos(uint8_t* buffer) { return (buffer[0] & 0x06) >> 1 static inline int mqtt_get_retain(uint8_t* buffer) { return (buffer[0] & 0x01); } void mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length); +bool mqtt_header_complete(uint8_t* buffer, uint16_t buffer_length); uint32_t mqtt_get_total_length(uint8_t* buffer, uint16_t length); const char* mqtt_get_publish_topic(uint8_t* buffer, uint32_t* length); const char* mqtt_get_publish_data(uint8_t* buffer, uint32_t* length); diff --git a/lib/mqtt_msg.c b/lib/mqtt_msg.c index 15eb93e..8ca68a1 100644 --- a/lib/mqtt_msg.c +++ b/lib/mqtt_msg.c @@ -29,6 +29,7 @@ * */ #include +#include #include #include "mqtt_msg.h" #include "mqtt_config.h" @@ -172,6 +173,38 @@ uint32_t mqtt_get_total_length(uint8_t* buffer, uint16_t length) return totlen; } +bool mqtt_header_complete(uint8_t* buffer, uint16_t buffer_length) +{ + uint16_t i; + uint16_t topiclen; + + for (i = 1; i < MQTT_MAX_FIXED_HEADER_SIZE; ++i) + { + if(i >= buffer_length) + return false; + if ((buffer[i] & 0x80) == 0) + { + ++i; + break; + } + } + // i is now the length of the fixed header + + if (i + 2 >= buffer_length) + return false; + topiclen = buffer[i++] << 8; + topiclen |= buffer[i++]; + + i += topiclen; + + if (mqtt_get_qos(buffer) > 0) + { + i += 2; + } + // i is now the length of the fixed + variable header + return buffer_length >= i; +} + const char* mqtt_get_publish_topic(uint8_t* buffer, uint32_t* length) { int i; diff --git a/mqtt_client.c b/mqtt_client.c index 87c9541..270e618 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -67,6 +67,12 @@ typedef enum { MQTT_STATE_WAIT_TIMEOUT, } mqtt_client_state_t; +/* State values for reading MQTT message header */ +typedef enum { + MQTT_HEADER_STATE_INCOMPLETE = -1, + MQTT_HEADER_STATE_COMPLETE = 0, +} mqtt_header_state_t; + struct esp_mqtt_client { esp_transport_list_handle_t transport_list; esp_transport_handle_t transport; @@ -530,9 +536,10 @@ static esp_err_t esp_mqtt_dispatch_event(esp_mqtt_client_handle_t client) static void deliver_publish(esp_mqtt_client_handle_t client, uint8_t *message, int length) { + mqtt_header_state_t mqtt_header_state = MQTT_HEADER_STATE_INCOMPLETE; const char *mqtt_topic = NULL, *mqtt_data = NULL; uint32_t mqtt_topic_length, mqtt_data_length; - uint32_t mqtt_len = 0, mqtt_offset = 0, total_mqtt_len = 0; + uint32_t mqtt_len = 0, mqtt_offset = 0; int len_read= length; int max_to_read = client->mqtt_state.in_buffer_length; int buffer_offset = 0; @@ -540,12 +547,10 @@ static void deliver_publish(esp_mqtt_client_handle_t client, uint8_t *message, i do { - if (total_mqtt_len == 0) { - /* any further reading only the underlying payload */ + if (mqtt_header_state == MQTT_HEADER_STATE_INCOMPLETE) { + // any further reading only the underlying payload transport = esp_transport_get_payload_transport_handle(transport); - mqtt_data_length = mqtt_topic_length = length; - if (NULL == (mqtt_topic = mqtt_get_publish_topic(message, &mqtt_topic_length)) || - NULL == (mqtt_data = mqtt_get_publish_data(message, &mqtt_data_length)) ) { + if (!mqtt_header_complete(message, length)) { // mqtt header is not complete, continue reading memmove(client->mqtt_state.in_buffer, message, length); buffer_offset = length; @@ -553,10 +558,27 @@ static void deliver_publish(esp_mqtt_client_handle_t client, uint8_t *message, i max_to_read = client->mqtt_state.in_buffer_length - length; mqtt_len = 0; } else { - total_mqtt_len = client->mqtt_state.message_length - client->mqtt_state.message_length_read + mqtt_data_length; - mqtt_len = mqtt_data_length; - mqtt_data_length = client->mqtt_state.message_length - ((uint8_t*)mqtt_data- message); - /* read msg id only once */ + // mqtt header was fully read + mqtt_header_state = MQTT_HEADER_STATE_COMPLETE; + mqtt_data_length = mqtt_topic_length = length; + // Read the topic + if(NULL == (mqtt_topic = mqtt_get_publish_topic(message, &mqtt_topic_length))) { + ESP_LOGE(TAG, "Unable to read topic from header"); + break; + } + // Read the payload + mqtt_data = mqtt_get_publish_data(message, &mqtt_data_length); + if(mqtt_data_length > 0 && mqtt_data == NULL) { + ESP_LOGE(TAG, "Unable to read data from message"); + break; + } else if(mqtt_data_length > 0) { + mqtt_len = mqtt_data_length; + mqtt_data_length = client->mqtt_state.message_length - ((uint8_t*)mqtt_data- message); + } else { + mqtt_len = 0; + } + + // read msg id only once client->event.msg_id = mqtt_get_id(message, length); } } else { @@ -566,10 +588,10 @@ static void deliver_publish(esp_mqtt_client_handle_t client, uint8_t *message, i mqtt_topic_length = 0; } - if (total_mqtt_len != 0) { + if (mqtt_header_state == MQTT_HEADER_STATE_COMPLETE) { ESP_LOGD(TAG, "Get data len= %d, topic len=%d", mqtt_len, mqtt_topic_length); client->event.event_id = MQTT_EVENT_DATA; - client->event.data = (char *)mqtt_data; + client->event.data = mqtt_len > 0 ? (char *)mqtt_data : NULL; client->event.data_len = mqtt_len; client->event.total_data_len = mqtt_data_length; client->event.current_data_offset = mqtt_offset; From fd564b1f173397217425288a375fe7e1afc8d20d Mon Sep 17 00:00:00 2001 From: David Cermak Date: Fri, 26 Apr 2019 16:38:09 +0200 Subject: [PATCH 39/56] client receive: refactor receive to read only one message to fragment only payload for longer messages Closes #113 --- lib/include/mqtt_msg.h | 3 +- lib/mqtt_msg.c | 44 +++- mqtt_client.c | 460 +++++++++++++++++++++++++---------------- 3 files changed, 328 insertions(+), 179 deletions(-) diff --git a/lib/include/mqtt_msg.h b/lib/include/mqtt_msg.h index d57a5c5..b94108e 100644 --- a/lib/include/mqtt_msg.h +++ b/lib/include/mqtt_msg.h @@ -112,10 +112,11 @@ static inline int mqtt_get_retain(uint8_t* buffer) { return (buffer[0] & 0x01); void mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length); bool mqtt_header_complete(uint8_t* buffer, uint16_t buffer_length); -uint32_t mqtt_get_total_length(uint8_t* buffer, uint16_t length); +uint32_t mqtt_get_total_length(uint8_t* buffer, uint16_t length, int* fixed_size_len); const char* mqtt_get_publish_topic(uint8_t* buffer, uint32_t* length); const char* mqtt_get_publish_data(uint8_t* buffer, uint32_t* length); uint16_t mqtt_get_id(uint8_t* buffer, uint16_t length); +int mqtt_has_valid_msg_hdr(uint8_t* buffer, uint16_t length); mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info); mqtt_message_t* mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id); diff --git a/lib/mqtt_msg.c b/lib/mqtt_msg.c index 8ca68a1..a9b76b4 100644 --- a/lib/mqtt_msg.c +++ b/lib/mqtt_msg.c @@ -154,7 +154,7 @@ void mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buff connection->buffer_length = buffer_length; } -uint32_t mqtt_get_total_length(uint8_t* buffer, uint16_t length) +uint32_t mqtt_get_total_length(uint8_t* buffer, uint16_t length, int* fixed_size_len) { int i; uint32_t totlen = 0; @@ -169,6 +169,7 @@ uint32_t mqtt_get_total_length(uint8_t* buffer, uint16_t length) } } totlen += i; + if (fixed_size_len) *fixed_size_len = i; return totlen; } @@ -529,3 +530,44 @@ mqtt_message_t* mqtt_msg_disconnect(mqtt_connection_t* connection) init_message(connection); return fini_message(connection, MQTT_MSG_TYPE_DISCONNECT, 0, 0, 0); } + +/* + * check flags: [MQTT-2.2.2-1], [MQTT-2.2.2-2] + * returns 0 if flags are invalid, otherwise returns 1 + */ +int mqtt_has_valid_msg_hdr(uint8_t* buffer, uint16_t length) +{ + int qos, dup; + + if (length < 1) { + return 0; + } + switch (mqtt_get_type(buffer)) + { + case MQTT_MSG_TYPE_CONNECT: + case MQTT_MSG_TYPE_CONNACK: + case MQTT_MSG_TYPE_PUBACK: + case MQTT_MSG_TYPE_PUBREC: + case MQTT_MSG_TYPE_PUBCOMP: + case MQTT_MSG_TYPE_SUBACK: + case MQTT_MSG_TYPE_UNSUBACK: + case MQTT_MSG_TYPE_PINGREQ: + case MQTT_MSG_TYPE_PINGRESP: + case MQTT_MSG_TYPE_DISCONNECT: + return (buffer[0] & 0x0f) == 0; /* all flag bits are 0 */ + case MQTT_MSG_TYPE_PUBREL: + case MQTT_MSG_TYPE_SUBSCRIBE: + case MQTT_MSG_TYPE_UNSUBSCRIBE: + return (buffer[0] & 0x0f) == 0x02; /* only bit 1 is set */ + case MQTT_MSG_TYPE_PUBLISH: + qos = mqtt_get_qos(buffer); + dup = mqtt_get_dup(buffer); + /* + * there is no qos=3 [MQTT-3.3.1-4] + * dup flag must be set to 0 for all qos=0 messages [MQTT-3.3.1-2] + */ + return (qos < 3) && ((qos > 0) || (dup == 0)); + default: + return 0; + } +} \ No newline at end of file diff --git a/mqtt_client.c b/mqtt_client.c index 270e618..1aa7011 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -35,7 +35,7 @@ typedef struct mqtt_state int in_buffer_length; int out_buffer_length; uint32_t message_length; - uint32_t message_length_read; + uint32_t in_buffer_read_len; mqtt_message_t *outbound_message; mqtt_connection_t mqtt_connection; uint16_t pending_msg_id; @@ -104,6 +104,7 @@ static esp_err_t esp_mqtt_connect(esp_mqtt_client_handle_t client, int timeout_m static esp_err_t esp_mqtt_abort_connection(esp_mqtt_client_handle_t client); static esp_err_t esp_mqtt_client_ping(esp_mqtt_client_handle_t client); static char *create_string(const char *ptr, int len); +static int mqtt_message_receive(esp_mqtt_client_handle_t client, int read_poll_timeout_ms); esp_err_t esp_mqtt_set_config(esp_mqtt_client_handle_t client, const esp_mqtt_client_config_t *config) { @@ -274,13 +275,15 @@ static esp_err_t esp_mqtt_connect(esp_mqtt_client_handle_t client, int timeout_m ESP_LOGE(TAG, "Writing failed, errno= %d", errno); return ESP_FAIL; } - read_len = esp_transport_read(client->transport, - (char *)client->mqtt_state.in_buffer, - client->mqtt_state.in_buffer_length, - client->config->network_timeout_ms); - if (read_len < 0) { - ESP_LOGE(TAG, "Error network response"); - return ESP_FAIL; + + client->mqtt_state.in_buffer_read_len = 0; + client->mqtt_state.message_length = 0; + + /* wait configured network timeout for broker connection response */ + read_len = mqtt_message_receive(client, client->config->network_timeout_ms); + if (read_len <= 0) { + ESP_LOGE(TAG, "%s: mqtt_message_receive() returned %d", __func__, read_len); + return ESP_FAIL; } if (mqtt_get_type(client->mqtt_state.in_buffer) != MQTT_MSG_TYPE_CONNACK) { @@ -534,92 +537,65 @@ static esp_err_t esp_mqtt_dispatch_event(esp_mqtt_client_handle_t client) return ESP_FAIL; } -static void deliver_publish(esp_mqtt_client_handle_t client, uint8_t *message, int length) +static esp_err_t deliver_publish(esp_mqtt_client_handle_t client) { - mqtt_header_state_t mqtt_header_state = MQTT_HEADER_STATE_INCOMPLETE; - const char *mqtt_topic = NULL, *mqtt_data = NULL; - uint32_t mqtt_topic_length, mqtt_data_length; - uint32_t mqtt_len = 0, mqtt_offset = 0; - int len_read= length; - int max_to_read = client->mqtt_state.in_buffer_length; - int buffer_offset = 0; - esp_transport_handle_t transport = client->transport; + uint8_t *msg_buf = client->mqtt_state.in_buffer; + size_t msg_read_len = client->mqtt_state.in_buffer_read_len; + size_t msg_total_len = client->mqtt_state.message_length; + size_t msg_topic_len = msg_read_len, msg_data_len = msg_read_len; + size_t msg_data_offset = 0; + const char *msg_topic = NULL, *msg_data = NULL; - do - { - if (mqtt_header_state == MQTT_HEADER_STATE_INCOMPLETE) { - // any further reading only the underlying payload - transport = esp_transport_get_payload_transport_handle(transport); - if (!mqtt_header_complete(message, length)) { - // mqtt header is not complete, continue reading - memmove(client->mqtt_state.in_buffer, message, length); - buffer_offset = length; - message = client->mqtt_state.in_buffer; - max_to_read = client->mqtt_state.in_buffer_length - length; - mqtt_len = 0; - } else { - // mqtt header was fully read - mqtt_header_state = MQTT_HEADER_STATE_COMPLETE; - mqtt_data_length = mqtt_topic_length = length; - // Read the topic - if(NULL == (mqtt_topic = mqtt_get_publish_topic(message, &mqtt_topic_length))) { - ESP_LOGE(TAG, "Unable to read topic from header"); - break; - } - // Read the payload - mqtt_data = mqtt_get_publish_data(message, &mqtt_data_length); - if(mqtt_data_length > 0 && mqtt_data == NULL) { - ESP_LOGE(TAG, "Unable to read data from message"); - break; - } else if(mqtt_data_length > 0) { - mqtt_len = mqtt_data_length; - mqtt_data_length = client->mqtt_state.message_length - ((uint8_t*)mqtt_data- message); - } else { - mqtt_len = 0; - } - - // read msg id only once - client->event.msg_id = mqtt_get_id(message, length); - } - } else { - mqtt_len = len_read; - mqtt_data = (const char*)client->mqtt_state.in_buffer; - mqtt_topic = NULL; - mqtt_topic_length = 0; + // get topic + msg_topic = mqtt_get_publish_topic(msg_buf, &msg_topic_len); + if (msg_topic == NULL) { + ESP_LOGE(TAG, "%s: mqtt_get_publish_topic() failed", __func__); + return ESP_FAIL; + } + ESP_LOGD(TAG, "%s: msg_topic_len=%u", __func__, msg_topic_len); + + // get payload + msg_data = mqtt_get_publish_data(msg_buf, &msg_data_len); + if(msg_data_len > 0 && msg_data == NULL) { + ESP_LOGE(TAG, "%s: mqtt_get_publish_data() failed", __func__); + return ESP_FAIL; + } + + // post data event + client->event.msg_id = mqtt_get_id(msg_buf, msg_data_len); + client->event.total_data_len = msg_data_len + msg_total_len - msg_read_len; + +post_data_event: + ESP_LOGD(TAG, "Get data len= %d, topic len=%d, total_data: %d offset: %d", msg_data_len, msg_topic_len, + client->event.total_data_len, msg_data_offset); + client->event.event_id = MQTT_EVENT_DATA; + client->event.data = msg_data_len > 0 ? (char *)msg_data : NULL; + client->event.data_len = msg_data_len; + client->event.current_data_offset = msg_data_offset; + client->event.topic = (char *)msg_topic; + client->event.topic_len = msg_topic_len; + esp_mqtt_dispatch_event(client); + + if (msg_read_len < msg_total_len) { + // if total data is longer then actual -> read payload only + size_t buf_len = client->mqtt_state.in_buffer_length; + esp_transport_handle_t transport = esp_transport_get_payload_transport_handle(client->transport); + + msg_data = (const char*)client->mqtt_state.in_buffer; + msg_topic = NULL; + msg_topic_len = 0; + msg_data_offset += msg_data_len; + msg_data_len = esp_transport_read(transport, (char *)client->mqtt_state.in_buffer, + msg_total_len - msg_read_len > buf_len ? buf_len : msg_total_len - msg_read_len, + client->config->network_timeout_ms); + if (msg_data_len <= 0) { + ESP_LOGE(TAG, "Read error or timeout: len_read=%d, errno=%d", msg_data_len, errno); + return ESP_FAIL; } - - if (mqtt_header_state == MQTT_HEADER_STATE_COMPLETE) { - ESP_LOGD(TAG, "Get data len= %d, topic len=%d", mqtt_len, mqtt_topic_length); - client->event.event_id = MQTT_EVENT_DATA; - client->event.data = mqtt_len > 0 ? (char *)mqtt_data : NULL; - client->event.data_len = mqtt_len; - client->event.total_data_len = mqtt_data_length; - client->event.current_data_offset = mqtt_offset; - client->event.topic = (char *)mqtt_topic; - client->event.topic_len = mqtt_topic_length; - esp_mqtt_dispatch_event(client); - } - - mqtt_offset += mqtt_len; - if (client->mqtt_state.message_length_read >= client->mqtt_state.message_length) { - break; - } - - len_read = esp_transport_read(transport, - (char *)client->mqtt_state.in_buffer + buffer_offset, - client->mqtt_state.message_length - client->mqtt_state.message_length_read > max_to_read ? - max_to_read : client->mqtt_state.message_length - client->mqtt_state.message_length_read, - client->config->network_timeout_ms); - length = len_read + buffer_offset; - buffer_offset = 0; - max_to_read = client->mqtt_state.in_buffer_length; - if (len_read <= 0) { - ESP_LOGE(TAG, "Read error or timeout: len_read=%d, errno=%d", len_read, errno); - break; - } - client->mqtt_state.message_length_read += len_read; - } while (1); - + msg_read_len += msg_data_len; + goto post_data_event; + } + return ESP_OK; } static bool is_valid_mqtt_msg(esp_mqtt_client_handle_t client, int msg_type, int msg_id) @@ -677,109 +653,239 @@ static void mqtt_enqueue(esp_mqtt_client_handle_t client) //unlock } + +/* + * Returns: + * -1 in case of failure + * 0 if no message has been received + * 1 if a message has been received and placed to client->mqtt_state: + * message length: client->mqtt_state.message_length + * message content: client->mqtt_state.in_buffer + */ +static int mqtt_message_receive(esp_mqtt_client_handle_t client, int read_poll_timeout_ms) +{ + int read_len, total_len, fixed_header_len; + uint8_t *buf = client->mqtt_state.in_buffer + client->mqtt_state.in_buffer_read_len; + esp_transport_handle_t t = client->transport; + + client->mqtt_state.message_length = 0; + if (client->mqtt_state.in_buffer_read_len == 0) { + /* + * Read first byte of the mqtt packet fixed header, it contains packet + * type and flags. + */ + read_len = esp_transport_read(t, (char *)buf, 1, read_poll_timeout_ms); + if (read_len < 0) { + ESP_LOGE(TAG, "%s: transport_read() error: errno=%d", __func__, errno); + goto err; + } + if (read_len == 0) { + ESP_LOGV(TAG, "%s: transport_read(): no data or EOF", __func__); + return 0; + } + ESP_LOGD(TAG, "%s: first byte: 0x%x", __func__, *buf); + /* + * Verify the flags and act according to MQTT protocol: close connection + * if the flags are set incorrectly. + */ + if (!mqtt_has_valid_msg_hdr(buf, read_len)) { + ESP_LOGE(TAG, "%s: received a message with an invalid header=0x%x", __func__, *buf); + goto err; + } + buf++; + client->mqtt_state.in_buffer_read_len++; + } + /* any further reading only the underlying payload */ + t = esp_transport_get_payload_transport_handle(t); + if ((client->mqtt_state.in_buffer_read_len == 1) || + ((client->mqtt_state.in_buffer_read_len < 6) && (*(buf - 1) & 0x80))) { + do { + /* + * Read the "remaining length" part of mqtt packet fixed header. It + * starts at second byte and spans up to 4 bytes, but we accept here + * only up to 2 bytes of remaining length, i.e. messages with + * maximal remaining length value = 16383 (maximal total message + * size of 16386 bytes). + */ + read_len = esp_transport_read(t, (char *)buf, 1, read_poll_timeout_ms); + if (read_len < 0) { + ESP_LOGE(TAG, "%s: transport_read() error: errno=%d", __func__, errno); + goto err; + } + if (read_len == 0) { + ESP_LOGD(TAG, "%s: transport_read(): no data or EOF", __func__); + return 0; + } + ESP_LOGD(TAG, "%s: read \"remaining length\" byte: 0x%x", __func__, *buf); + buf++; + client->mqtt_state.in_buffer_read_len++; + } while ((client->mqtt_state.in_buffer_read_len < 6) && (*(buf - 1) & 0x80)); + } + total_len = mqtt_get_total_length(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_read_len, &fixed_header_len); + ESP_LOGD(TAG, "%s: total message length: %d (already read: %u)", __func__, total_len, client->mqtt_state.in_buffer_read_len); + client->mqtt_state.message_length = total_len; + if (client->mqtt_state.in_buffer_length < total_len) { + if (mqtt_get_type(client->mqtt_state.in_buffer) == MQTT_MSG_TYPE_PUBLISH) { + /* + * In case larger publish messages, we only need to read full topic, data can be split to multiple data event. + * Evaluate and correct total_len to read only publish message header, so data can be read separately + */ + if (client->mqtt_state.in_buffer_read_len < fixed_header_len + 2) { + /* read next 2 bytes - topic length to get minimum portion of publish packet */ + read_len = esp_transport_read(t, (char *)buf, client->mqtt_state.in_buffer_read_len - fixed_header_len + 2, read_poll_timeout_ms); + ESP_LOGD(TAG, "%s: read_len=%d", __func__, read_len); + if (read_len < 0) { + ESP_LOGE(TAG, "%s: transport_read() error: errno=%d", __func__, errno); + goto err; + } else if (read_len == 0) { + ESP_LOGD(TAG, "%s: transport_read(): no data or EOF", __func__); + return 0; + } + client->mqtt_state.in_buffer_read_len += read_len; + buf += read_len; + if (client->mqtt_state.in_buffer_read_len < fixed_header_len + 2) { + ESP_LOGD(TAG, "%s: transport_read(): message reading left in progress :: total message length: %d (already read: %u)", + __func__, total_len, client->mqtt_state.in_buffer_read_len); + return 0; + } + } + int topic_len = client->mqtt_state.in_buffer[fixed_header_len] << 8; + topic_len |= client->mqtt_state.in_buffer[fixed_header_len+1]; + total_len = fixed_header_len + topic_len + (mqtt_get_qos(client->mqtt_state.in_buffer)>0?2:0); + ESP_LOGD(TAG, "%s: total len modified to %d as message longer than input buffer", __func__, total_len); + if (client->mqtt_state.in_buffer_length < total_len) { + ESP_LOGE(TAG, "%s: message is too big, insufficient buffer size", __func__); + goto err; + } else { + total_len = client->mqtt_state.in_buffer_length; + } + /* free to continue with reading */ + } else { + ESP_LOGE(TAG, "%s: message is too big, insufficient buffer size", __func__); + goto err; + } + } + if (client->mqtt_state.in_buffer_read_len < total_len) { + /* read the rest of the mqtt message */ + read_len = esp_transport_read(t, (char *)buf, total_len - client->mqtt_state.in_buffer_read_len, read_poll_timeout_ms); + ESP_LOGD(TAG, "%s: read_len=%d", __func__, read_len); + if (read_len < 0) { + ESP_LOGE(TAG, "%s: transport_read() error: errno=%d", __func__, errno); + goto err; + } + if (read_len == 0) { + ESP_LOGD(TAG, "%s: transport_read(): no data or EOF", __func__); + return 0; + } + client->mqtt_state.in_buffer_read_len += read_len; + if (client->mqtt_state.in_buffer_read_len < total_len) { + ESP_LOGD(TAG, "%s: transport_read(): message reading left in progress :: total message length: %d (already read: %u)", + __func__, total_len, client->mqtt_state.in_buffer_read_len); + return 0; + } + } + ESP_LOGD(TAG, "%s: transport_read():%d %d", __func__, client->mqtt_state.in_buffer_read_len, client->mqtt_state.message_length); + return 1; +err: + return -1; +} + static esp_err_t mqtt_process_receive(esp_mqtt_client_handle_t client) { - int read_len; - uint8_t msg_type; - uint8_t msg_qos; + uint8_t msg_type; + uint8_t msg_qos; uint16_t msg_id; - uint32_t transport_message_offset = 0 ; - read_len = esp_transport_read(client->transport, (char *)client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length, 0); - - if (read_len < 0) { - ESP_LOGE(TAG, "Read error or end of stream, errno:%d", errno); + /* non-blocking receive in order not to block other tasks */ + int recv = mqtt_message_receive(client, 0); + if (recv < 0) { + ESP_LOGE(TAG, "%s: mqtt_message_receive() returned %d", __func__, recv); return ESP_FAIL; } - - if (read_len == 0) { + if (recv == 0) { return ESP_OK; } + int read_len = client->mqtt_state.message_length; - // In case of fragmented packet (when receiving a large publish message), the deliver_publish function will read the rest of the message with more transport read, which means the MQTT message length will be greater than the initial transport read length. That explains that the stopping condition is not the equality here - while ( transport_message_offset < read_len ) { - // If the message was valid, get the type, quality of service and id of the message - msg_type = mqtt_get_type(&client->mqtt_state.in_buffer[transport_message_offset]); - msg_qos = mqtt_get_qos(&client->mqtt_state.in_buffer[transport_message_offset]); - msg_id = mqtt_get_id(&client->mqtt_state.in_buffer[transport_message_offset], read_len - transport_message_offset); - client->mqtt_state.message_length_read = read_len - transport_message_offset; - client->mqtt_state.message_length = mqtt_get_total_length(&client->mqtt_state.in_buffer[transport_message_offset], client->mqtt_state.message_length_read); + // If the message was valid, get the type, quality of service and id of the message + msg_type = mqtt_get_type(client->mqtt_state.in_buffer); + msg_qos = mqtt_get_qos(client->mqtt_state.in_buffer); + msg_id = mqtt_get_id(client->mqtt_state.in_buffer, read_len); - ESP_LOGD(TAG, "msg_type=%d, msg_id=%d", msg_type, msg_id); + ESP_LOGD(TAG, "msg_type=%d, msg_id=%d", msg_type, msg_id); - switch (msg_type) - { - case MQTT_MSG_TYPE_SUBACK: - if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_SUBSCRIBE, msg_id)) { - ESP_LOGD(TAG, "Subscribe successful"); - client->event.event_id = MQTT_EVENT_SUBSCRIBED; - esp_mqtt_dispatch_event_with_msgid(client); - } - break; - case MQTT_MSG_TYPE_UNSUBACK: - if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_UNSUBSCRIBE, msg_id)) { - ESP_LOGD(TAG, "UnSubscribe successful"); - client->event.event_id = MQTT_EVENT_UNSUBSCRIBED; - esp_mqtt_dispatch_event_with_msgid(client); - } - break; - case MQTT_MSG_TYPE_PUBLISH: - if (msg_qos == 1) { - client->mqtt_state.outbound_message = mqtt_msg_puback(&client->mqtt_state.mqtt_connection, msg_id); - } - else if (msg_qos == 2) { - client->mqtt_state.outbound_message = mqtt_msg_pubrec(&client->mqtt_state.mqtt_connection, msg_id); - } + switch (msg_type) + { + case MQTT_MSG_TYPE_SUBACK: + if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_SUBSCRIBE, msg_id)) { + ESP_LOGD(TAG, "Subscribe successful"); + client->event.event_id = MQTT_EVENT_SUBSCRIBED; + esp_mqtt_dispatch_event_with_msgid(client); + } + break; + case MQTT_MSG_TYPE_UNSUBACK: + if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_UNSUBSCRIBE, msg_id)) { + ESP_LOGD(TAG, "UnSubscribe successful"); + client->event.event_id = MQTT_EVENT_UNSUBSCRIBED; + esp_mqtt_dispatch_event_with_msgid(client); + } + break; + case MQTT_MSG_TYPE_PUBLISH: + ESP_LOGD(TAG, "deliver_publish, message_length_read=%d, message_length=%d", client->mqtt_state.in_buffer_read_len, client->mqtt_state.message_length); + if (deliver_publish(client) != ESP_OK) { + ESP_LOGE(TAG, "Failed to deliver publish message id=%d", msg_id); + return ESP_FAIL; + } + if (msg_qos == 1) { + client->mqtt_state.outbound_message = mqtt_msg_puback(&client->mqtt_state.mqtt_connection, msg_id); + } + else if (msg_qos == 2) { + client->mqtt_state.outbound_message = mqtt_msg_pubrec(&client->mqtt_state.mqtt_connection, msg_id); + } - if (msg_qos == 1 || msg_qos == 2) { - ESP_LOGD(TAG, "Queue response QoS: %d", msg_qos); + if (msg_qos == 1 || msg_qos == 2) { + ESP_LOGD(TAG, "Queue response QoS: %d", msg_qos); - if (mqtt_write_data(client) != ESP_OK) { - ESP_LOGE(TAG, "Error write qos msg repsonse, qos = %d", msg_qos); - // TODO: Shoule reconnect? - // return ESP_FAIL; - } + if (mqtt_write_data(client) != ESP_OK) { + ESP_LOGE(TAG, "Error write qos msg repsonse, qos = %d", msg_qos); + return ESP_FAIL; } - // Deliver the publish message - ESP_LOGD(TAG, "deliver_publish, message_length_read=%d, message_length=%d", client->mqtt_state.message_length_read, client->mqtt_state.message_length); - deliver_publish(client, &client->mqtt_state.in_buffer[transport_message_offset], client->mqtt_state.message_length_read); - break; - case MQTT_MSG_TYPE_PUBACK: - if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_PUBLISH, msg_id)) { - ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBACK, finish QoS1 publish"); - outbox_set_pending(client->outbox, msg_id, CONFIRMED); - client->event.event_id = MQTT_EVENT_PUBLISHED; - esp_mqtt_dispatch_event_with_msgid(client); - } - break; - case MQTT_MSG_TYPE_PUBREC: - ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBREC"); - client->mqtt_state.outbound_message = mqtt_msg_pubrel(&client->mqtt_state.mqtt_connection, msg_id); + } + break; + case MQTT_MSG_TYPE_PUBACK: + if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_PUBLISH, msg_id)) { + ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBACK, finish QoS1 publish"); outbox_set_pending(client->outbox, msg_id, CONFIRMED); - mqtt_write_data(client); - break; - case MQTT_MSG_TYPE_PUBREL: - ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBREL"); - client->mqtt_state.outbound_message = mqtt_msg_pubcomp(&client->mqtt_state.mqtt_connection, msg_id); - mqtt_write_data(client); - break; - case MQTT_MSG_TYPE_PUBCOMP: - ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBCOMP"); - if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_PUBLISH, msg_id)) { - ESP_LOGD(TAG, "Receive MQTT_MSG_TYPE_PUBCOMP, finish QoS2 publish"); - client->event.event_id = MQTT_EVENT_PUBLISHED; - esp_mqtt_dispatch_event_with_msgid(client); - } - break; - case MQTT_MSG_TYPE_PINGRESP: - ESP_LOGD(TAG, "MQTT_MSG_TYPE_PINGRESP"); - client->wait_for_ping_resp = false; - break; - } - - transport_message_offset += client->mqtt_state.message_length; + client->event.event_id = MQTT_EVENT_PUBLISHED; + esp_mqtt_dispatch_event_with_msgid(client); + } + break; + case MQTT_MSG_TYPE_PUBREC: + ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBREC"); + client->mqtt_state.outbound_message = mqtt_msg_pubrel(&client->mqtt_state.mqtt_connection, msg_id); + outbox_set_pending(client->outbox, msg_id, CONFIRMED); + mqtt_write_data(client); + break; + case MQTT_MSG_TYPE_PUBREL: + ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBREL"); + client->mqtt_state.outbound_message = mqtt_msg_pubcomp(&client->mqtt_state.mqtt_connection, msg_id); + mqtt_write_data(client); + break; + case MQTT_MSG_TYPE_PUBCOMP: + ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBCOMP"); + if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_PUBLISH, msg_id)) { + ESP_LOGD(TAG, "Receive MQTT_MSG_TYPE_PUBCOMP, finish QoS2 publish"); + client->event.event_id = MQTT_EVENT_PUBLISHED; + esp_mqtt_dispatch_event_with_msgid(client); + } + break; + case MQTT_MSG_TYPE_PINGRESP: + ESP_LOGD(TAG, "MQTT_MSG_TYPE_PINGRESP"); + client->wait_for_ping_resp = false; + break; } + client->mqtt_state.in_buffer_read_len = 0; return ESP_OK; } From 7d22ab5fe697f1598755dddf35adc5eec614a0b2 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Sun, 5 May 2019 22:30:46 +0200 Subject: [PATCH 40/56] pending_msg_count update on delete expired from outbox Closes #111 --- lib/include/mqtt_outbox.h | 2 +- lib/mqtt_outbox.c | 7 +++++-- mqtt_client.c | 6 +++++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/include/mqtt_outbox.h b/lib/include/mqtt_outbox.h index c9422e9..3939d7c 100644 --- a/lib/include/mqtt_outbox.h +++ b/lib/include/mqtt_outbox.h @@ -41,7 +41,7 @@ uint8_t* outbox_item_get_data(outbox_item_handle_t item, size_t *len, uint16_t esp_err_t outbox_delete(outbox_handle_t outbox, int msg_id, int msg_type); esp_err_t outbox_delete_msgid(outbox_handle_t outbox, int msg_id); esp_err_t outbox_delete_msgtype(outbox_handle_t outbox, int msg_type); -esp_err_t outbox_delete_expired(outbox_handle_t outbox, int current_tick, int timeout); +int outbox_delete_expired(outbox_handle_t outbox, int current_tick, int timeout); esp_err_t outbox_set_pending(outbox_handle_t outbox, int msg_id, pending_state_t pending); int outbox_get_size(outbox_handle_t outbox); diff --git a/lib/mqtt_outbox.c b/lib/mqtt_outbox.c index 2ef3689..04bbce6 100644 --- a/lib/mqtt_outbox.c +++ b/lib/mqtt_outbox.c @@ -145,18 +145,21 @@ esp_err_t outbox_delete_msgtype(outbox_handle_t outbox, int msg_type) return ESP_OK; } -esp_err_t outbox_delete_expired(outbox_handle_t outbox, int current_tick, int timeout) +int outbox_delete_expired(outbox_handle_t outbox, int current_tick, int timeout) { + int deleted_items = 0; outbox_item_handle_t item, tmp; STAILQ_FOREACH_SAFE(item, outbox, next, tmp) { if (current_tick - item->tick > timeout) { STAILQ_REMOVE(outbox, item, outbox_item, next); + printf("free message\n"); free(item->buffer); free(item); + deleted_items ++; } } - return ESP_OK; + return deleted_items; } int outbox_get_size(outbox_handle_t outbox) diff --git a/mqtt_client.c b/mqtt_client.c index 1aa7011..6face26 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -1011,7 +1011,11 @@ static void esp_mqtt_task(void *pv) } //Delete mesaage after 30 senconds - outbox_delete_expired(client->outbox, platform_tick_get_ms(), OUTBOX_EXPIRED_TIMEOUT_MS); + 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) { + client->mqtt_state.pending_msg_count = 0; + } // outbox_cleanup(client->outbox, OUTBOX_MAX_SIZE); break; From 35fc42d2b9399c935d9b3e1846017a898613c065 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Sun, 5 May 2019 22:37:06 +0200 Subject: [PATCH 41/56] mqtt_msg: added missing message type for unsubscribe msg type Closes #109 --- lib/mqtt_msg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/mqtt_msg.c b/lib/mqtt_msg.c index a9b76b4..1ee803c 100644 --- a/lib/mqtt_msg.c +++ b/lib/mqtt_msg.c @@ -329,6 +329,7 @@ uint16_t mqtt_get_id(uint8_t* buffer, uint16_t length) case MQTT_MSG_TYPE_SUBACK: case MQTT_MSG_TYPE_UNSUBACK: case MQTT_MSG_TYPE_SUBSCRIBE: + case MQTT_MSG_TYPE_UNSUBSCRIBE: { // This requires the remaining length to be encoded in 1 byte, // which it should be. From 891646681eb7596b021800485fd0a2b780a6f9ed Mon Sep 17 00:00:00 2001 From: David Cermak Date: Mon, 6 May 2019 08:49:38 +0200 Subject: [PATCH 42/56] client_init: fix crashing client upon wrong parameters, init or deinit Closes https://github.com/espressif/esp-idf/issues/3191 --- mqtt_client.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/mqtt_client.c b/mqtt_client.c index 6face26..c643897 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -422,17 +422,25 @@ esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *co return client; _mqtt_init_failed: esp_mqtt_client_destroy(client); - MQTT_API_UNLOCK(client); return NULL; } esp_err_t esp_mqtt_client_destroy(esp_mqtt_client_handle_t client) { + if (client == NULL) { + return ESP_ERR_INVALID_ARG; + } esp_mqtt_client_stop(client); esp_mqtt_destroy_config(client); - esp_transport_list_destroy(client->transport_list); - outbox_destroy(client->outbox); - vEventGroupDelete(client->status_bits); + if (client->transport_list) { + esp_transport_list_destroy(client->transport_list); + } + if (client->outbox) { + outbox_destroy(client->outbox); + } + if (client->status_bits) { + vEventGroupDelete(client->status_bits); + } free(client->mqtt_state.in_buffer); free(client->mqtt_state.out_buffer); vSemaphoreDelete(client->api_lock); @@ -1055,6 +1063,10 @@ static void esp_mqtt_task(void *pv) esp_err_t esp_mqtt_client_start(esp_mqtt_client_handle_t client) { + if (!client) { + ESP_LOGE(TAG, "Client was not initialized"); + return ESP_ERR_INVALID_ARG; + } if (client->state >= MQTT_STATE_INIT) { ESP_LOGE(TAG, "Client has started"); return ESP_FAIL; @@ -1187,6 +1199,11 @@ int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, qos, retain, &pending_msg_id); + if (publish_msg == NULL) { + ESP_LOGE(TAG, "Publish message cannot be created"); + MQTT_API_UNLOCK_FROM_OTHER_TASK(client); + return 0; + } /* We have to set as pending all the qos>0 messages */ if (qos > 0) { client->mqtt_state.outbound_message = publish_msg; From d159bf45754a2138649b1838323bf8317a4b9af8 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Fri, 26 Apr 2019 09:30:53 +0200 Subject: [PATCH 43/56] support for publishing message with empty data --- mqtt_client.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mqtt_client.c b/mqtt_client.c index c643897..1da323a 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -1189,7 +1189,12 @@ int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, { uint16_t pending_msg_id = 0; - if (len <= 0) { + /* Acceptable publish messages: + data == NULL, len == 0: publish null message + data valid, len == 0: publish all data, payload len is determined from string length + data valid, len > 0: publish data with defined length + */ + if (len <= 0 && data != NULL) { len = strlen(data); } From db71c753aad7de09af1a667d1db0d5017c048f6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Cabral?= Date: Thu, 18 Apr 2019 14:32:01 +0100 Subject: [PATCH 44/56] FIX: mqtt_get_id wrong logic on msg size checks. This error was preventing the function from returning the right msg ID, returning always 0. --- lib/mqtt_msg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mqtt_msg.c b/lib/mqtt_msg.c index 1ee803c..bf40aa4 100644 --- a/lib/mqtt_msg.c +++ b/lib/mqtt_msg.c @@ -307,13 +307,13 @@ uint16_t mqtt_get_id(uint8_t* buffer, uint16_t length) topiclen = buffer[i++] << 8; topiclen |= buffer[i++]; - if (i + topiclen >= length) + if (i + topiclen > length) return 0; i += topiclen; if (mqtt_get_qos(buffer) > 0) { - if (i + 2 >= length) + if (i + 2 > length) return 0; //i += 2; } else { From 60cdb79a6706e02c80c814e375cb93c217e658e4 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Mon, 6 May 2019 09:37:50 +0200 Subject: [PATCH 45/56] mqtt_msg: avoid uncasting const to mqtt topic and data pointers --- lib/include/mqtt_msg.h | 4 ++-- lib/mqtt_msg.c | 8 ++++---- mqtt_client.c | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/include/mqtt_msg.h b/lib/include/mqtt_msg.h index b94108e..c65e0d4 100644 --- a/lib/include/mqtt_msg.h +++ b/lib/include/mqtt_msg.h @@ -113,8 +113,8 @@ static inline int mqtt_get_retain(uint8_t* buffer) { return (buffer[0] & 0x01); void mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length); bool mqtt_header_complete(uint8_t* buffer, uint16_t buffer_length); uint32_t mqtt_get_total_length(uint8_t* buffer, uint16_t length, int* fixed_size_len); -const char* mqtt_get_publish_topic(uint8_t* buffer, uint32_t* length); -const char* mqtt_get_publish_data(uint8_t* buffer, uint32_t* length); +char* mqtt_get_publish_topic(uint8_t* buffer, uint32_t* length); +char* mqtt_get_publish_data(uint8_t* buffer, uint32_t* length); uint16_t mqtt_get_id(uint8_t* buffer, uint16_t length); int mqtt_has_valid_msg_hdr(uint8_t* buffer, uint16_t length); diff --git a/lib/mqtt_msg.c b/lib/mqtt_msg.c index bf40aa4..c7b1fe1 100644 --- a/lib/mqtt_msg.c +++ b/lib/mqtt_msg.c @@ -206,7 +206,7 @@ bool mqtt_header_complete(uint8_t* buffer, uint16_t buffer_length) return buffer_length >= i; } -const char* mqtt_get_publish_topic(uint8_t* buffer, uint32_t* length) +char* mqtt_get_publish_topic(uint8_t* buffer, uint32_t* length) { int i; int totlen = 0; @@ -232,10 +232,10 @@ const char* mqtt_get_publish_topic(uint8_t* buffer, uint32_t* length) return NULL; *length = topiclen; - return (const char*)(buffer + i); + return (char*)(buffer + i); } -const char* mqtt_get_publish_data(uint8_t* buffer, uint32_t* length) +char* mqtt_get_publish_data(uint8_t* buffer, uint32_t* length) { int i; int totlen = 0; @@ -278,7 +278,7 @@ const char* mqtt_get_publish_data(uint8_t* buffer, uint32_t* length) *length = totlen - i; else *length = blength - i; - return (const char*)(buffer + i); + return (char*)(buffer + i); } uint16_t mqtt_get_id(uint8_t* buffer, uint16_t length) diff --git a/mqtt_client.c b/mqtt_client.c index 1da323a..0036703 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -552,7 +552,7 @@ static esp_err_t deliver_publish(esp_mqtt_client_handle_t client) size_t msg_total_len = client->mqtt_state.message_length; size_t msg_topic_len = msg_read_len, msg_data_len = msg_read_len; size_t msg_data_offset = 0; - const char *msg_topic = NULL, *msg_data = NULL; + char *msg_topic = NULL, *msg_data = NULL; // get topic msg_topic = mqtt_get_publish_topic(msg_buf, &msg_topic_len); @@ -577,10 +577,10 @@ post_data_event: ESP_LOGD(TAG, "Get data len= %d, topic len=%d, total_data: %d offset: %d", msg_data_len, msg_topic_len, client->event.total_data_len, msg_data_offset); client->event.event_id = MQTT_EVENT_DATA; - client->event.data = msg_data_len > 0 ? (char *)msg_data : NULL; + client->event.data = msg_data_len > 0 ? msg_data : NULL; client->event.data_len = msg_data_len; client->event.current_data_offset = msg_data_offset; - client->event.topic = (char *)msg_topic; + client->event.topic = msg_topic; client->event.topic_len = msg_topic_len; esp_mqtt_dispatch_event(client); @@ -589,7 +589,7 @@ post_data_event: size_t buf_len = client->mqtt_state.in_buffer_length; esp_transport_handle_t transport = esp_transport_get_payload_transport_handle(client->transport); - msg_data = (const char*)client->mqtt_state.in_buffer; + msg_data = (char*)client->mqtt_state.in_buffer; msg_topic = NULL; msg_topic_len = 0; msg_data_offset += msg_data_len; From 1d294f7606d4b70f33adcd9316eca32c28b66aa2 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Mon, 6 May 2019 09:42:55 +0200 Subject: [PATCH 46/56] ci: github build esp-mqtt with more stable IDF (latest release version rather then master) fixed also internal ci: use the same git command for buld and static analysis (reset --hard instead of checkout) --- .gitlab-ci.yml | 2 +- .travis.yml | 8 +++++--- modify_for_legacy_idf.sh | 8 +++++++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index aa8921e..3461a4c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -79,7 +79,7 @@ clang_tidy_check: - cd $IDF_PATH/components/mqtt/esp-mqtt - rm -rf .git - cp -r $CI_PROJECT_DIR/.git . - - git checkout $CI_COMMIT_SHA + - git reset --hard $CI_COMMIT_SHA - mv $CI_PROJECT_DIR/tidybuild $IDF_PATH/examples/protocols/mqtt/tcp/tidybuild - cd $IDF_PATH/examples/protocols/mqtt/tcp/tidybuild - git clone "${CI_REPORT_TOOLS}" diff --git a/.travis.yml b/.travis.yml index 5f1a823..b900e93 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,8 @@ before_install: # Have to checkout a temp branch for later in tree reference - git checkout -b temporary_ref_branch - CI_COMMIT_SHA=$(git rev-parse HEAD) + # Test building with latest (stable == v3.3 for now) IDF + - LATEST_IDF=release/v3.3 install: # Install ESP32 toochain following steps as desribed @@ -42,13 +44,13 @@ script: - cd $IDF_PATH - git checkout v3.1 && git submodule update --init --recursive - cd $PROJECT_PATH - - ./modify_for_legacy_idf.sh || true + - ./modify_for_legacy_idf.sh ${LATEST_IDF} || true - cd $PROJECT_PATH/examples/tcp - make defconfig - make -j4 - # Master build with latest IDF + # Build with latest IDF - cd $IDF_PATH - - git checkout master && git submodule update --init --recursive + - git checkout ${LATEST_IDF} && git submodule update --init --recursive - cd $IDF_PATH/components/mqtt/esp-mqtt - git remote add local $PROJECT_PATH/.git - git fetch local diff --git a/modify_for_legacy_idf.sh b/modify_for_legacy_idf.sh index 6c43074..8ea7e2b 100755 --- a/modify_for_legacy_idf.sh +++ b/modify_for_legacy_idf.sh @@ -1,5 +1,11 @@ #!/usr/bin/env bash +if [[ -z $1 ]]; then + LATEST_IDF=master +else + LATEST_IDF=$1 +fi + # This snipped prepares environment for using esp-mqtt repository separately from idf -- legacy use before IDFv3.2 # esp_mqtt_path=`pwd` @@ -7,7 +13,7 @@ mkdir -p ${esp_mqtt_path}/examples pushd cd $IDF_PATH former_commit_id=`git rev-parse HEAD` -git checkout master +git checkout ${LATEST_IDF} for example in tcp; do cp -r $IDF_PATH/examples/protocols/mqtt/${example} ${esp_mqtt_path}/examples From e442c19f4e25cf778118e448e8fb0b7b747ee856 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Mon, 6 May 2019 12:15:37 +0200 Subject: [PATCH 47/56] Added API documentaton to public headers --- include/mqtt_client.h | 123 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 121 insertions(+), 2 deletions(-) diff --git a/include/mqtt_client.h b/include/mqtt_client.h index e4e11d4..dd1d7ef 100755 --- a/include/mqtt_client.h +++ b/include/mqtt_client.h @@ -44,6 +44,10 @@ typedef enum { - data_len length of the data for this event - current_data_offset offset of the current data for this event - total_data_len total length of the data received + Note: Multiple MQTT_EVENT_DATA could be fired for one message, if it is + longer than internal buffer. In that case only first event contains topic + pointer and length, other contain data only with current data length + and current data offset updating. */ MQTT_EVENT_BEFORE_CONNECT, /*!< The event occurs before connecting */ } esp_mqtt_event_id_t; @@ -107,15 +111,130 @@ typedef struct { int refresh_connection_after_ms; /*!< Refresh connection after this value (in milliseconds) */ } esp_mqtt_client_config_t; +/** + * @brief Creates mqtt client handle based on the configuration + * + * @param config mqtt configuration structure + * + * @return mqtt_client_handle if successfully created, NULL on error + */ esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *config); + +/** + * @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 uri + * + * @return ESP_FAIL if URI parse error, ESP_OK on success + */ esp_err_t esp_mqtt_client_set_uri(esp_mqtt_client_handle_t client, const char *uri); + +/** + * @brief Starts mqtt client with already created client handle + * + * @param client mqtt client handle + * + * @return ESP_OK on success + * ESP_ERR_INVALID_ARG on wrong initialization + * ESP_FAIL on other error + */ esp_err_t esp_mqtt_client_start(esp_mqtt_client_handle_t client); + +/** + * @brief This api is typically used to force reconnection upon a specific event + * + * @param client mqtt client handle + * + * @return ESP_OK on success + * ESP_FAIL if client is in invalid state + */ esp_err_t esp_mqtt_client_reconnect(esp_mqtt_client_handle_t client); + +/** + * @brief Stops mqtt client tasks + * + * @param client mqtt client handle + * + * @return ESP_OK on success + * ESP_FAIL if client is in invalid state + */ esp_err_t esp_mqtt_client_stop(esp_mqtt_client_handle_t client); -esp_err_t esp_mqtt_client_subscribe(esp_mqtt_client_handle_t client, const char *topic, int qos); -esp_err_t esp_mqtt_client_unsubscribe(esp_mqtt_client_handle_t client, const char *topic); + +/** + * @brief Subscribe the client to defined topic with defined qos + * + * Notes: + * - Client must be connected to send subscribe message + * - This API is could be executed from a user task or + * from a mqtt event callback i.e. internal mqtt task + * (API is protected by internal mutex, so it might block + * if a longer data receive operation is in progress. + * + * @param client mqtt client handle + * @param topic + * @param qos + * + * @return message_id of the subscribe message on success + * -1 on failure + */ +int esp_mqtt_client_subscribe(esp_mqtt_client_handle_t client, const char *topic, int qos); + +/** + * @brief Unsubscribe the client from defined topic + * + * Notes: + * - Client must be connected to send unsubscribe message + * - It is thread safe, please refer to `esp_mqtt_client_subscribe` for details + * + * @param client mqtt client handle + * @param topic + * + * @return message_id of the subscribe message on success + * -1 on failure + */ +int esp_mqtt_client_unsubscribe(esp_mqtt_client_handle_t client, const char *topic); + +/** + * @brief Client to send a publish message to the broker + * + * Notes: + * - Client doesn't have to be connected to send publish message + * (although it would drop all qos=0 messages, qos>1 messages would be enqueued) + * - It is thread safe, please refer to `esp_mqtt_client_subscribe` for details + * + * @param client mqtt client handle + * @param topic topic string + * @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 + * + * @return message_id of the subscribe message on success + * 0 if cannot publish + */ int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, const char *data, int len, int qos, int retain); + +/** + * @brief Destroys the client handle + * + * @param client mqtt client handle + * + * @return ESP_OK + */ esp_err_t esp_mqtt_client_destroy(esp_mqtt_client_handle_t client); + +/** + * @brief Set configuration structure, typically used when updating the config (i.e. on "before_connect" event + * + * @param client mqtt client handle + * + * @param config mqtt configuration structure + * + * @return ESP_ERR_NO_MEM if failed to allocate + * ESP_OK on success + */ esp_err_t esp_mqtt_set_config(esp_mqtt_client_handle_t client, const esp_mqtt_client_config_t *config); #ifdef __cplusplus From 18b6f2c58231728805ff813d46021d07ed023dcb Mon Sep 17 00:00:00 2001 From: David Cermak Date: Mon, 6 May 2019 13:45:33 +0200 Subject: [PATCH 48/56] Fixed formatting for all files to comply with idf style formats --- include/mqtt_client.h | 4 +- include/mqtt_config.h | 12 +- lib/include/mqtt_msg.h | 100 ++++++---- lib/include/mqtt_outbox.h | 22 +- lib/mqtt_msg.c | 388 +++++++++++++++++++----------------- lib/mqtt_outbox.c | 10 +- lib/platform_esp32_idf.c | 4 +- mqtt_client.c | 409 +++++++++++++++++++------------------- 8 files changed, 489 insertions(+), 460 deletions(-) mode change 100755 => 100644 include/mqtt_client.h diff --git a/include/mqtt_client.h b/include/mqtt_client.h old mode 100755 new mode 100644 index dd1d7ef..cb06132 --- a/include/mqtt_client.h +++ b/include/mqtt_client.h @@ -18,7 +18,7 @@ extern "C" { #endif -typedef struct esp_mqtt_client* esp_mqtt_client_handle_t; +typedef struct esp_mqtt_client *esp_mqtt_client_handle_t; /** * @brief MQTT event types. @@ -77,7 +77,7 @@ typedef struct { int session_present; /*!< MQTT session_present flag for connection event */ } esp_mqtt_event_t; -typedef esp_mqtt_event_t* esp_mqtt_event_handle_t; +typedef esp_mqtt_event_t *esp_mqtt_event_handle_t; typedef esp_err_t (* mqtt_event_callback_t)(esp_mqtt_event_handle_t event); diff --git a/include/mqtt_config.h b/include/mqtt_config.h index 972f2a1..033fc0a 100644 --- a/include/mqtt_config.h +++ b/include/mqtt_config.h @@ -67,13 +67,13 @@ #endif #ifdef CONFIG_MQTT_USE_CORE_0 - #define MQTT_TASK_CORE 0 +#define MQTT_TASK_CORE 0 #else - #ifdef CONFIG_MQTT_USE_CORE_1 - #define MQTT_TASK_CORE 1 - #else - #define MQTT_TASK_CORE 0 - #endif +#ifdef CONFIG_MQTT_USE_CORE_1 +#define MQTT_TASK_CORE 1 +#else +#define MQTT_TASK_CORE 0 +#endif #endif diff --git a/lib/include/mqtt_msg.h b/lib/include/mqtt_msg.h index c65e0d4..80ab72f 100644 --- a/lib/include/mqtt_msg.h +++ b/lib/include/mqtt_msg.h @@ -40,8 +40,7 @@ extern "C" { /* Remaining Length */ -enum mqtt_message_type -{ +enum mqtt_message_type { MQTT_MSG_TYPE_CONNECT = 1, MQTT_MSG_TYPE_CONNACK = 2, MQTT_MSG_TYPE_PUBLISH = 3, @@ -58,8 +57,7 @@ enum mqtt_message_type MQTT_MSG_TYPE_DISCONNECT = 14 }; -enum mqtt_connect_return_code -{ +enum mqtt_connect_return_code { CONNECTION_ACCEPTED = 0, CONNECTION_REFUSE_PROTOCOL, CONNECTION_REFUSE_ID_REJECTED, @@ -68,31 +66,28 @@ enum mqtt_connect_return_code CONNECTION_REFUSE_NOT_AUTHORIZED }; -typedef struct mqtt_message -{ - uint8_t* data; +typedef struct mqtt_message { + uint8_t *data; uint32_t length; uint32_t fragmented_msg_total_length; /*!< total len of fragmented messages (zero for all other messages) */ uint32_t fragmented_msg_data_offset; /*!< data offset of fragmented messages (zero for all other messages) */ } mqtt_message_t; -typedef struct mqtt_connection -{ +typedef struct mqtt_connection { mqtt_message_t message; uint16_t message_id; - uint8_t* buffer; + uint8_t *buffer; uint16_t buffer_length; } mqtt_connection_t; -typedef struct mqtt_connect_info -{ - char* client_id; - char* username; - char* password; - char* will_topic; - char* will_message; +typedef struct mqtt_connect_info { + char *client_id; + char *username; + char *password; + char *will_topic; + char *will_message; int keepalive; int will_length; int will_qos; @@ -102,33 +97,54 @@ typedef struct mqtt_connect_info } mqtt_connect_info_t; -static inline int mqtt_get_type(uint8_t* buffer) { return (buffer[0] & 0xf0) >> 4; } -static inline int mqtt_get_connect_session_present(uint8_t* buffer) { return buffer[2] & 0x01; } -static inline int mqtt_get_connect_return_code(uint8_t* buffer) { return buffer[3]; } -static inline int mqtt_get_dup(uint8_t* buffer) { return (buffer[0] & 0x08) >> 3; } -static inline void mqtt_set_dup(uint8_t* buffer) { buffer[0] |= 0x08; } -static inline int mqtt_get_qos(uint8_t* buffer) { return (buffer[0] & 0x06) >> 1; } -static inline int mqtt_get_retain(uint8_t* buffer) { return (buffer[0] & 0x01); } +static inline int mqtt_get_type(uint8_t *buffer) +{ + return (buffer[0] & 0xf0) >> 4; +} +static inline int mqtt_get_connect_session_present(uint8_t *buffer) +{ + return buffer[2] & 0x01; +} +static inline int mqtt_get_connect_return_code(uint8_t *buffer) +{ + return buffer[3]; +} +static inline int mqtt_get_dup(uint8_t *buffer) +{ + return (buffer[0] & 0x08) >> 3; +} +static inline void mqtt_set_dup(uint8_t *buffer) +{ + buffer[0] |= 0x08; +} +static inline int mqtt_get_qos(uint8_t *buffer) +{ + return (buffer[0] & 0x06) >> 1; +} +static inline int mqtt_get_retain(uint8_t *buffer) +{ + return (buffer[0] & 0x01); +} -void mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length); -bool mqtt_header_complete(uint8_t* buffer, uint16_t buffer_length); -uint32_t mqtt_get_total_length(uint8_t* buffer, uint16_t length, int* fixed_size_len); -char* mqtt_get_publish_topic(uint8_t* buffer, uint32_t* length); -char* mqtt_get_publish_data(uint8_t* buffer, uint32_t* length); -uint16_t mqtt_get_id(uint8_t* buffer, uint16_t length); -int mqtt_has_valid_msg_hdr(uint8_t* buffer, uint16_t length); +void mqtt_msg_init(mqtt_connection_t *connection, uint8_t *buffer, uint16_t buffer_length); +bool mqtt_header_complete(uint8_t *buffer, uint16_t buffer_length); +uint32_t mqtt_get_total_length(uint8_t *buffer, uint16_t length, int *fixed_size_len); +char *mqtt_get_publish_topic(uint8_t *buffer, uint32_t *length); +char *mqtt_get_publish_data(uint8_t *buffer, uint32_t *length); +uint16_t mqtt_get_id(uint8_t *buffer, uint16_t length); +int mqtt_has_valid_msg_hdr(uint8_t *buffer, uint16_t length); -mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info); -mqtt_message_t* mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id); -mqtt_message_t* mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id); -mqtt_message_t* mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id); -mqtt_message_t* mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id); -mqtt_message_t* mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id); -mqtt_message_t* mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id); -mqtt_message_t* mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id); -mqtt_message_t* mqtt_msg_pingreq(mqtt_connection_t* connection); -mqtt_message_t* mqtt_msg_pingresp(mqtt_connection_t* connection); -mqtt_message_t* mqtt_msg_disconnect(mqtt_connection_t* connection); +mqtt_message_t *mqtt_msg_connect(mqtt_connection_t *connection, mqtt_connect_info_t *info); +mqtt_message_t *mqtt_msg_publish(mqtt_connection_t *connection, const char *topic, const char *data, int data_length, int qos, int retain, uint16_t *message_id); +mqtt_message_t *mqtt_msg_puback(mqtt_connection_t *connection, uint16_t message_id); +mqtt_message_t *mqtt_msg_pubrec(mqtt_connection_t *connection, uint16_t message_id); +mqtt_message_t *mqtt_msg_pubrel(mqtt_connection_t *connection, uint16_t message_id); +mqtt_message_t *mqtt_msg_pubcomp(mqtt_connection_t *connection, uint16_t message_id); +mqtt_message_t *mqtt_msg_subscribe(mqtt_connection_t *connection, const char *topic, int qos, uint16_t *message_id); +mqtt_message_t *mqtt_msg_unsubscribe(mqtt_connection_t *connection, const char *topic, uint16_t *message_id); +mqtt_message_t *mqtt_msg_pingreq(mqtt_connection_t *connection); +mqtt_message_t *mqtt_msg_pingresp(mqtt_connection_t *connection); +mqtt_message_t *mqtt_msg_disconnect(mqtt_connection_t *connection); #ifdef __cplusplus diff --git a/lib/include/mqtt_outbox.h b/lib/include/mqtt_outbox.h index 3939d7c..e3a5ba7 100644 --- a/lib/include/mqtt_outbox.h +++ b/lib/include/mqtt_outbox.h @@ -13,18 +13,18 @@ extern "C" { struct outbox_item; -typedef struct outbox_list_t * outbox_handle_t; -typedef struct outbox_item * outbox_item_handle_t; -typedef struct outbox_message * outbox_message_handle_t; +typedef struct outbox_list_t *outbox_handle_t; +typedef struct outbox_item *outbox_item_handle_t; +typedef struct outbox_message *outbox_message_handle_t; typedef struct outbox_message { - uint8_t *data; - int len; - int msg_id; - int msg_qos; - int msg_type; - uint8_t *remaining_data; - int remaining_len; + uint8_t *data; + int len; + int msg_id; + int msg_qos; + int msg_type; + uint8_t *remaining_data; + int remaining_len; } outbox_message_t; typedef enum pending_state { @@ -37,7 +37,7 @@ outbox_handle_t outbox_init(); outbox_item_handle_t outbox_enqueue(outbox_handle_t outbox, outbox_message_handle_t message, int tick); outbox_item_handle_t outbox_dequeue(outbox_handle_t outbox, pending_state_t pending, int *tick); outbox_item_handle_t outbox_get(outbox_handle_t outbox, int msg_id); -uint8_t* outbox_item_get_data(outbox_item_handle_t item, size_t *len, uint16_t *msg_id, int *msg_type, int *qos); +uint8_t *outbox_item_get_data(outbox_item_handle_t item, size_t *len, uint16_t *msg_id, int *msg_type, int *qos); esp_err_t outbox_delete(outbox_handle_t outbox, int msg_id, int msg_type); esp_err_t outbox_delete_msgid(outbox_handle_t outbox, int msg_id); esp_err_t outbox_delete_msgtype(outbox_handle_t outbox, int msg_type); diff --git a/lib/mqtt_msg.c b/lib/mqtt_msg.c index c7b1fe1..05ffa19 100644 --- a/lib/mqtt_msg.c +++ b/lib/mqtt_msg.c @@ -37,8 +37,7 @@ #define MQTT_MAX_FIXED_HEADER_SIZE 5 -enum mqtt_connect_flag -{ +enum mqtt_connect_flag { MQTT_CONNECT_FLAG_USERNAME = 1 << 7, MQTT_CONNECT_FLAG_PASSWORD = 1 << 6, MQTT_CONNECT_FLAG_WILL_RETAIN = 1 << 5, @@ -46,8 +45,7 @@ enum mqtt_connect_flag MQTT_CONNECT_FLAG_CLEAN_SESSION = 1 << 1 }; -struct __attribute((__packed__)) mqtt_connect_variable_header -{ +struct __attribute((__packed__)) mqtt_connect_variable_header { uint8_t lengthMsb; uint8_t lengthLsb; #if defined(MQTT_PROTOCOL_311) @@ -61,10 +59,11 @@ struct __attribute((__packed__)) mqtt_connect_variable_header uint8_t keepaliveLsb; }; -static int append_string(mqtt_connection_t* connection, const char* string, int len) +static int append_string(mqtt_connection_t *connection, const char *string, int len) { - if (connection->message.length + len + 2 > connection->buffer_length) + if (connection->message.length + len + 2 > connection->buffer_length) { return -1; + } connection->buffer[connection->message.length++] = len >> 8; connection->buffer[connection->message.length++] = len & 0xff; @@ -74,7 +73,7 @@ static int append_string(mqtt_connection_t* connection, const char* string, int return len + 2; } -static uint16_t append_message_id(mqtt_connection_t* connection, uint16_t message_id) +static uint16_t append_message_id(mqtt_connection_t *connection, uint16_t message_id) { // If message_id is zero then we should assign one, otherwise // we'll use the one supplied by the caller @@ -82,8 +81,9 @@ static uint16_t append_message_id(mqtt_connection_t* connection, uint16_t messag message_id = platform_random(65535); } - if (connection->message.length + 2 > connection->buffer_length) + if (connection->message.length + 2 > connection->buffer_length) { return 0; + } connection->buffer[connection->message.length++] = message_id >> 8; connection->buffer[connection->message.length++] = message_id & 0xff; @@ -91,20 +91,20 @@ static uint16_t append_message_id(mqtt_connection_t* connection, uint16_t messag return message_id; } -static int init_message(mqtt_connection_t* connection) +static int init_message(mqtt_connection_t *connection) { connection->message.length = MQTT_MAX_FIXED_HEADER_SIZE; return MQTT_MAX_FIXED_HEADER_SIZE; } -static mqtt_message_t* fail_message(mqtt_connection_t* connection) +static mqtt_message_t *fail_message(mqtt_connection_t *connection) { connection->message.data = connection->buffer; connection->message.length = 0; return &connection->message; } -static mqtt_message_t* fini_message(mqtt_connection_t* connection, int type, int dup, int qos, int retain) +static mqtt_message_t *fini_message(mqtt_connection_t *connection, int type, int dup, int qos, int retain) { int message_length = connection->message.length - MQTT_MAX_FIXED_HEADER_SIZE; int total_length = message_length; @@ -140,102 +140,101 @@ static mqtt_message_t* fini_message(mqtt_connection_t* connection, int type, int // type byte connection->buffer[offs++] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1); // length bytes - for (int j = 0; jbuffer[offs++] = encoded_lens[j]; } return &connection->message; } -void mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length) +void mqtt_msg_init(mqtt_connection_t *connection, uint8_t *buffer, uint16_t buffer_length) { memset(connection, 0, sizeof(mqtt_connection_t)); connection->buffer = buffer; connection->buffer_length = buffer_length; } -uint32_t mqtt_get_total_length(uint8_t* buffer, uint16_t length, int* fixed_size_len) +uint32_t mqtt_get_total_length(uint8_t *buffer, uint16_t length, int *fixed_size_len) { int i; uint32_t totlen = 0; - for (i = 1; i < length; ++i) - { + for (i = 1; i < length; ++i) { totlen += (buffer[i] & 0x7f) << (7 * (i - 1)); - if ((buffer[i] & 0x80) == 0) - { + if ((buffer[i] & 0x80) == 0) { ++i; break; } } totlen += i; - if (fixed_size_len) *fixed_size_len = i; - + if (fixed_size_len) { + *fixed_size_len = i; + } + return totlen; } -bool mqtt_header_complete(uint8_t* buffer, uint16_t buffer_length) +bool mqtt_header_complete(uint8_t *buffer, uint16_t buffer_length) { uint16_t i; uint16_t topiclen; - for (i = 1; i < MQTT_MAX_FIXED_HEADER_SIZE; ++i) - { - if(i >= buffer_length) + for (i = 1; i < MQTT_MAX_FIXED_HEADER_SIZE; ++i) { + if (i >= buffer_length) { return false; - if ((buffer[i] & 0x80) == 0) - { + } + if ((buffer[i] & 0x80) == 0) { ++i; break; } } // i is now the length of the fixed header - if (i + 2 >= buffer_length) + if (i + 2 >= buffer_length) { return false; + } topiclen = buffer[i++] << 8; topiclen |= buffer[i++]; i += topiclen; - if (mqtt_get_qos(buffer) > 0) - { + if (mqtt_get_qos(buffer) > 0) { i += 2; } // i is now the length of the fixed + variable header return buffer_length >= i; } -char* mqtt_get_publish_topic(uint8_t* buffer, uint32_t* length) +char *mqtt_get_publish_topic(uint8_t *buffer, uint32_t *length) { int i; int totlen = 0; int topiclen; - for (i = 1; i < *length; ++i) - { + for (i = 1; i < *length; ++i) { totlen += (buffer[i] & 0x7f) << (7 * (i - 1)); - if ((buffer[i] & 0x80) == 0) - { + if ((buffer[i] & 0x80) == 0) { ++i; break; } } totlen += i; - if (i + 2 >= *length) + if (i + 2 >= *length) { return NULL; + } topiclen = buffer[i++] << 8; topiclen |= buffer[i++]; - if (i + topiclen > *length) + if (i + topiclen > *length) { return NULL; + } *length = topiclen; - return (char*)(buffer + i); -} + return (char *)(buffer + i); +} -char* mqtt_get_publish_data(uint8_t* buffer, uint32_t* length) +char *mqtt_get_publish_data(uint8_t *buffer, uint32_t *length) { int i; int totlen = 0; @@ -243,116 +242,118 @@ char* mqtt_get_publish_data(uint8_t* buffer, uint32_t* length) int blength = *length; *length = 0; - for (i = 1; i < blength; ++i) - { + for (i = 1; i < blength; ++i) { totlen += (buffer[i] & 0x7f) << (7 * (i - 1)); - if ((buffer[i] & 0x80) == 0) - { + if ((buffer[i] & 0x80) == 0) { ++i; break; } } totlen += i; - if (i + 2 >= blength) + if (i + 2 >= blength) { return NULL; + } topiclen = buffer[i++] << 8; topiclen |= buffer[i++]; - if (i + topiclen >= blength) + if (i + topiclen >= blength) { return NULL; + } i += topiclen; - if (mqtt_get_qos(buffer) > 0) - { - if (i + 2 >= blength) + if (mqtt_get_qos(buffer) > 0) { + if (i + 2 >= blength) { return NULL; + } i += 2; } - if (totlen < i) + if (totlen < i) { return NULL; + } - if (totlen <= blength) + if (totlen <= blength) { *length = totlen - i; - else + } else { *length = blength - i; - return (char*)(buffer + i); + } + return (char *)(buffer + i); } -uint16_t mqtt_get_id(uint8_t* buffer, uint16_t length) +uint16_t mqtt_get_id(uint8_t *buffer, uint16_t length) { - if (length < 1) + if (length < 1) { return 0; + } - switch (mqtt_get_type(buffer)) - { - case MQTT_MSG_TYPE_PUBLISH: - { - int i; - int topiclen; + switch (mqtt_get_type(buffer)) { + case MQTT_MSG_TYPE_PUBLISH: { + int i; + int topiclen; - for (i = 1; i < length; ++i) - { - if ((buffer[i] & 0x80) == 0) - { - ++i; - break; - } - } - - if (i + 2 >= length) - return 0; - topiclen = buffer[i++] << 8; - topiclen |= buffer[i++]; - - if (i + topiclen > length) - return 0; - i += topiclen; - - if (mqtt_get_qos(buffer) > 0) - { - if (i + 2 > length) - return 0; - //i += 2; - } else { - return 0; - } - - return (buffer[i] << 8) | buffer[i + 1]; - } - case MQTT_MSG_TYPE_PUBACK: - case MQTT_MSG_TYPE_PUBREC: - case MQTT_MSG_TYPE_PUBREL: - case MQTT_MSG_TYPE_PUBCOMP: - case MQTT_MSG_TYPE_SUBACK: - case MQTT_MSG_TYPE_UNSUBACK: - case MQTT_MSG_TYPE_SUBSCRIBE: - case MQTT_MSG_TYPE_UNSUBSCRIBE: - { - // This requires the remaining length to be encoded in 1 byte, - // which it should be. - if (length >= 4 && (buffer[1] & 0x80) == 0) - return (buffer[2] << 8) | buffer[3]; - else - return 0; + for (i = 1; i < length; ++i) { + if ((buffer[i] & 0x80) == 0) { + ++i; + break; } + } - default: + if (i + 2 >= length) { return 0; + } + topiclen = buffer[i++] << 8; + topiclen |= buffer[i++]; + + if (i + topiclen > length) { + return 0; + } + i += topiclen; + + if (mqtt_get_qos(buffer) > 0) { + if (i + 2 > length) { + return 0; + } + //i += 2; + } else { + return 0; + } + + return (buffer[i] << 8) | buffer[i + 1]; + } + case MQTT_MSG_TYPE_PUBACK: + case MQTT_MSG_TYPE_PUBREC: + case MQTT_MSG_TYPE_PUBREL: + case MQTT_MSG_TYPE_PUBCOMP: + case MQTT_MSG_TYPE_SUBACK: + case MQTT_MSG_TYPE_UNSUBACK: + case MQTT_MSG_TYPE_SUBSCRIBE: + case MQTT_MSG_TYPE_UNSUBSCRIBE: { + // This requires the remaining length to be encoded in 1 byte, + // which it should be. + if (length >= 4 && (buffer[1] & 0x80) == 0) { + return (buffer[2] << 8) | buffer[3]; + } else { + return 0; + } + } + + default: + return 0; } } -mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info) +mqtt_message_t *mqtt_msg_connect(mqtt_connection_t *connection, mqtt_connect_info_t *info) { - struct mqtt_connect_variable_header* variable_header; + struct mqtt_connect_variable_header *variable_header; init_message(connection); - if (connection->message.length + sizeof(*variable_header) > connection->buffer_length) + if (connection->message.length + sizeof(*variable_header) > connection->buffer_length) { return fail_message(connection); - variable_header = (void*)(connection->buffer + connection->message.length); + } + variable_header = (void *)(connection->buffer + connection->message.length); connection->message.length += sizeof(*variable_header); variable_header->lengthMsb = 0; @@ -370,43 +371,46 @@ mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_inf variable_header->keepaliveMsb = info->keepalive >> 8; variable_header->keepaliveLsb = info->keepalive & 0xff; - if (info->clean_session) + if (info->clean_session) { variable_header->flags |= MQTT_CONNECT_FLAG_CLEAN_SESSION; - - if (info->client_id != NULL && info->client_id[0] != '\0') - { - if (append_string(connection, info->client_id, strlen(info->client_id)) < 0) - return fail_message(connection); } - else + + if (info->client_id != NULL && info->client_id[0] != '\0') { + if (append_string(connection, info->client_id, strlen(info->client_id)) < 0) { + return fail_message(connection); + } + } else { return fail_message(connection); + } - if (info->will_topic != NULL && info->will_topic[0] != '\0') - { - if (append_string(connection, info->will_topic, strlen(info->will_topic)) < 0) + if (info->will_topic != NULL && info->will_topic[0] != '\0') { + if (append_string(connection, info->will_topic, strlen(info->will_topic)) < 0) { return fail_message(connection); + } - if (append_string(connection, info->will_message, info->will_length) < 0) + if (append_string(connection, info->will_message, info->will_length) < 0) { return fail_message(connection); + } variable_header->flags |= MQTT_CONNECT_FLAG_WILL; - if (info->will_retain) + if (info->will_retain) { variable_header->flags |= MQTT_CONNECT_FLAG_WILL_RETAIN; + } variable_header->flags |= (info->will_qos & 3) << 3; } - if (info->username != NULL && info->username[0] != '\0') - { - if (append_string(connection, info->username, strlen(info->username)) < 0) + if (info->username != NULL && info->username[0] != '\0') { + if (append_string(connection, info->username, strlen(info->username)) < 0) { return fail_message(connection); + } variable_header->flags |= MQTT_CONNECT_FLAG_USERNAME; } - if (info->password != NULL && info->password[0] != '\0') - { - if (append_string(connection, info->password, strlen(info->password)) < 0) + if (info->password != NULL && info->password[0] != '\0') { + if (append_string(connection, info->password, strlen(info->password)) < 0) { return fail_message(connection); + } variable_header->flags |= MQTT_CONNECT_FLAG_PASSWORD; } @@ -414,23 +418,25 @@ mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_inf return fini_message(connection, MQTT_MSG_TYPE_CONNECT, 0, 0, 0); } -mqtt_message_t* mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id) +mqtt_message_t *mqtt_msg_publish(mqtt_connection_t *connection, const char *topic, const char *data, int data_length, int qos, int retain, uint16_t *message_id) { init_message(connection); - if (topic == NULL || topic[0] == '\0') + if (topic == NULL || topic[0] == '\0') { return fail_message(connection); - - if (append_string(connection, topic, strlen(topic)) < 0) - return fail_message(connection); - - if (qos > 0) - { - if ((*message_id = append_message_id(connection, 0)) == 0) - return fail_message(connection); } - else + + if (append_string(connection, topic, strlen(topic)) < 0) { + return fail_message(connection); + } + + if (qos > 0) { + if ((*message_id = append_message_id(connection, 0)) == 0) { + return fail_message(connection); + } + } else { *message_id = 0; + } if (connection->message.length + data_length > connection->buffer_length) { // Not enough size in buffer -> fragment this message @@ -446,87 +452,98 @@ mqtt_message_t* mqtt_msg_publish(mqtt_connection_t* connection, const char* topi return fini_message(connection, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain); } -mqtt_message_t* mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id) +mqtt_message_t *mqtt_msg_puback(mqtt_connection_t *connection, uint16_t message_id) { init_message(connection); - if (append_message_id(connection, message_id) == 0) + if (append_message_id(connection, message_id) == 0) { return fail_message(connection); + } return fini_message(connection, MQTT_MSG_TYPE_PUBACK, 0, 0, 0); } -mqtt_message_t* mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id) +mqtt_message_t *mqtt_msg_pubrec(mqtt_connection_t *connection, uint16_t message_id) { init_message(connection); - if (append_message_id(connection, message_id) == 0) + if (append_message_id(connection, message_id) == 0) { return fail_message(connection); + } return fini_message(connection, MQTT_MSG_TYPE_PUBREC, 0, 0, 0); } -mqtt_message_t* mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id) +mqtt_message_t *mqtt_msg_pubrel(mqtt_connection_t *connection, uint16_t message_id) { init_message(connection); - if (append_message_id(connection, message_id) == 0) + if (append_message_id(connection, message_id) == 0) { return fail_message(connection); + } return fini_message(connection, MQTT_MSG_TYPE_PUBREL, 0, 1, 0); } -mqtt_message_t* mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id) +mqtt_message_t *mqtt_msg_pubcomp(mqtt_connection_t *connection, uint16_t message_id) { init_message(connection); - if (append_message_id(connection, message_id) == 0) + if (append_message_id(connection, message_id) == 0) { return fail_message(connection); + } return fini_message(connection, MQTT_MSG_TYPE_PUBCOMP, 0, 0, 0); } -mqtt_message_t* mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id) +mqtt_message_t *mqtt_msg_subscribe(mqtt_connection_t *connection, const char *topic, int qos, uint16_t *message_id) { init_message(connection); - if (topic == NULL || topic[0] == '\0') + if (topic == NULL || topic[0] == '\0') { return fail_message(connection); + } - if ((*message_id = append_message_id(connection, 0)) == 0) + if ((*message_id = append_message_id(connection, 0)) == 0) { return fail_message(connection); + } - if (append_string(connection, topic, strlen(topic)) < 0) + if (append_string(connection, topic, strlen(topic)) < 0) { return fail_message(connection); + } - if (connection->message.length + 1 > connection->buffer_length) + if (connection->message.length + 1 > connection->buffer_length) { return fail_message(connection); + } connection->buffer[connection->message.length++] = qos; return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0); } -mqtt_message_t* mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id) +mqtt_message_t *mqtt_msg_unsubscribe(mqtt_connection_t *connection, const char *topic, uint16_t *message_id) { init_message(connection); - if (topic == NULL || topic[0] == '\0') + if (topic == NULL || topic[0] == '\0') { return fail_message(connection); + } - if ((*message_id = append_message_id(connection, 0)) == 0) + if ((*message_id = append_message_id(connection, 0)) == 0) { return fail_message(connection); + } - if (append_string(connection, topic, strlen(topic)) < 0) + if (append_string(connection, topic, strlen(topic)) < 0) { return fail_message(connection); + } return fini_message(connection, MQTT_MSG_TYPE_UNSUBSCRIBE, 0, 1, 0); } -mqtt_message_t* mqtt_msg_pingreq(mqtt_connection_t* connection) +mqtt_message_t *mqtt_msg_pingreq(mqtt_connection_t *connection) { init_message(connection); return fini_message(connection, MQTT_MSG_TYPE_PINGREQ, 0, 0, 0); } -mqtt_message_t* mqtt_msg_pingresp(mqtt_connection_t* connection) +mqtt_message_t *mqtt_msg_pingresp(mqtt_connection_t *connection) { init_message(connection); return fini_message(connection, MQTT_MSG_TYPE_PINGRESP, 0, 0, 0); } -mqtt_message_t* mqtt_msg_disconnect(mqtt_connection_t* connection) +mqtt_message_t *mqtt_msg_disconnect(mqtt_connection_t *connection) { init_message(connection); return fini_message(connection, MQTT_MSG_TYPE_DISCONNECT, 0, 0, 0); @@ -536,39 +553,38 @@ mqtt_message_t* mqtt_msg_disconnect(mqtt_connection_t* connection) * check flags: [MQTT-2.2.2-1], [MQTT-2.2.2-2] * returns 0 if flags are invalid, otherwise returns 1 */ -int mqtt_has_valid_msg_hdr(uint8_t* buffer, uint16_t length) +int mqtt_has_valid_msg_hdr(uint8_t *buffer, uint16_t length) { int qos, dup; if (length < 1) { return 0; } - switch (mqtt_get_type(buffer)) - { - case MQTT_MSG_TYPE_CONNECT: - case MQTT_MSG_TYPE_CONNACK: - case MQTT_MSG_TYPE_PUBACK: - case MQTT_MSG_TYPE_PUBREC: - case MQTT_MSG_TYPE_PUBCOMP: - case MQTT_MSG_TYPE_SUBACK: - case MQTT_MSG_TYPE_UNSUBACK: - case MQTT_MSG_TYPE_PINGREQ: - case MQTT_MSG_TYPE_PINGRESP: - case MQTT_MSG_TYPE_DISCONNECT: - return (buffer[0] & 0x0f) == 0; /* all flag bits are 0 */ - case MQTT_MSG_TYPE_PUBREL: - case MQTT_MSG_TYPE_SUBSCRIBE: - case MQTT_MSG_TYPE_UNSUBSCRIBE: - return (buffer[0] & 0x0f) == 0x02; /* only bit 1 is set */ - case MQTT_MSG_TYPE_PUBLISH: - qos = mqtt_get_qos(buffer); - dup = mqtt_get_dup(buffer); - /* - * there is no qos=3 [MQTT-3.3.1-4] - * dup flag must be set to 0 for all qos=0 messages [MQTT-3.3.1-2] - */ - return (qos < 3) && ((qos > 0) || (dup == 0)); - default: - return 0; + switch (mqtt_get_type(buffer)) { + case MQTT_MSG_TYPE_CONNECT: + case MQTT_MSG_TYPE_CONNACK: + case MQTT_MSG_TYPE_PUBACK: + case MQTT_MSG_TYPE_PUBREC: + case MQTT_MSG_TYPE_PUBCOMP: + case MQTT_MSG_TYPE_SUBACK: + case MQTT_MSG_TYPE_UNSUBACK: + case MQTT_MSG_TYPE_PINGREQ: + case MQTT_MSG_TYPE_PINGRESP: + case MQTT_MSG_TYPE_DISCONNECT: + return (buffer[0] & 0x0f) == 0; /* all flag bits are 0 */ + case MQTT_MSG_TYPE_PUBREL: + case MQTT_MSG_TYPE_SUBSCRIBE: + case MQTT_MSG_TYPE_UNSUBSCRIBE: + return (buffer[0] & 0x0f) == 0x02; /* only bit 1 is set */ + case MQTT_MSG_TYPE_PUBLISH: + qos = mqtt_get_qos(buffer); + dup = mqtt_get_dup(buffer); + /* + * there is no qos=3 [MQTT-3.3.1-4] + * dup flag must be set to 0 for all qos=0 messages [MQTT-3.3.1-2] + */ + return (qos < 3) && ((qos > 0) || (dup == 0)); + default: + return 0; } } \ No newline at end of file diff --git a/lib/mqtt_outbox.c b/lib/mqtt_outbox.c index 04bbce6..ac7359a 100644 --- a/lib/mqtt_outbox.c +++ b/lib/mqtt_outbox.c @@ -49,7 +49,7 @@ outbox_item_handle_t outbox_enqueue(outbox_handle_t outbox, outbox_message_handl }); memcpy(item->buffer, message->data, message->len); if (message->remaining_data) { - memcpy(item->buffer+message->len, message->remaining_data, message->remaining_len); + memcpy(item->buffer + message->len, message->remaining_data, message->remaining_len); } STAILQ_INSERT_TAIL(outbox, item, next); ESP_LOGD(TAG, "ENQUEUE msgid=%d, msg_type=%d, len=%d, size=%d", message->msg_id, message->msg_type, message->len + message->remaining_len, outbox_get_size(outbox)); @@ -81,14 +81,14 @@ outbox_item_handle_t outbox_dequeue(outbox_handle_t outbox, pending_state_t pend return NULL; } -uint8_t* outbox_item_get_data(outbox_item_handle_t item, size_t *len, uint16_t *msg_id, int *msg_type, int *qos) +uint8_t *outbox_item_get_data(outbox_item_handle_t item, size_t *len, uint16_t *msg_id, int *msg_type, int *qos) { if (item) { *len = item->len; *msg_id = item->msg_id; *msg_type = item->msg_type; *qos = item->msg_qos; - return (uint8_t*)item->buffer; + return (uint8_t *)item->buffer; } return NULL; } @@ -97,7 +97,7 @@ esp_err_t outbox_delete(outbox_handle_t outbox, int msg_id, int msg_type) { outbox_item_handle_t item, tmp; STAILQ_FOREACH_SAFE(item, outbox, next, tmp) { - if (item->msg_id == msg_id && (0xFF&(item->msg_type)) == msg_type) { + if (item->msg_id == msg_id && (0xFF & (item->msg_type)) == msg_type) { STAILQ_REMOVE(outbox, item, outbox_item, next); free(item->buffer); free(item); @@ -174,7 +174,7 @@ int outbox_get_size(outbox_handle_t outbox) esp_err_t outbox_cleanup(outbox_handle_t outbox, int max_size) { - while(outbox_get_size(outbox) > max_size) { + while (outbox_get_size(outbox) > max_size) { outbox_item_handle_t item = outbox_dequeue(outbox, CONFIRMED, NULL); if (item == NULL) { return ESP_FAIL; diff --git a/lib/platform_esp32_idf.c b/lib/platform_esp32_idf.c index d640e02..bbe0199 100644 --- a/lib/platform_esp32_idf.c +++ b/lib/platform_esp32_idf.c @@ -21,14 +21,14 @@ char *platform_create_id_string() int platform_random(int max) { - return esp_random()%max; + return esp_random() % max; } long long platform_tick_get_ms() { struct timeval te; gettimeofday(&te, NULL); // get current time - long long milliseconds = te.tv_sec*1000LL + te.tv_usec/1000; // calculate milliseconds + long long milliseconds = te.tv_sec * 1000LL + te.tv_usec / 1000; // calculate milliseconds // printf("milliseconds: %lld\n", milliseconds); return milliseconds; } diff --git a/mqtt_client.c b/mqtt_client.c index 0036703..6afae73 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -27,8 +27,7 @@ static const char *TAG = "MQTT_CLIENT"; -typedef struct mqtt_state -{ +typedef struct mqtt_state { mqtt_connect_info_t *connect_info; uint8_t *in_buffer; uint8_t *out_buffer; @@ -268,9 +267,9 @@ static esp_err_t esp_mqtt_connect(esp_mqtt_client_handle_t client, int timeout_m client->mqtt_state.pending_msg_id); write_len = esp_transport_write(client->transport, - (char *)client->mqtt_state.outbound_message->data, - client->mqtt_state.outbound_message->length, - client->config->network_timeout_ms); + (char *)client->mqtt_state.outbound_message->data, + client->mqtt_state.outbound_message->length, + client->config->network_timeout_ms); if (write_len < 0) { ESP_LOGE(TAG, "Writing failed, errno= %d", errno); return ESP_FAIL; @@ -283,7 +282,7 @@ static esp_err_t esp_mqtt_connect(esp_mqtt_client_handle_t client, int timeout_m read_len = mqtt_message_receive(client, client->config->network_timeout_ms); if (read_len <= 0) { ESP_LOGE(TAG, "%s: mqtt_message_receive() returned %d", __func__, read_len); - return ESP_FAIL; + return ESP_FAIL; } if (mqtt_get_type(client->mqtt_state.in_buffer) != MQTT_MSG_TYPE_CONNACK) { @@ -292,24 +291,24 @@ static esp_err_t esp_mqtt_connect(esp_mqtt_client_handle_t client, int timeout_m } connect_rsp_code = mqtt_get_connect_return_code(client->mqtt_state.in_buffer); switch (connect_rsp_code) { - case CONNECTION_ACCEPTED: - ESP_LOGD(TAG, "Connected"); - return ESP_OK; - case CONNECTION_REFUSE_PROTOCOL: - ESP_LOGW(TAG, "Connection refused, bad protocol"); - return ESP_FAIL; - case CONNECTION_REFUSE_SERVER_UNAVAILABLE: - ESP_LOGW(TAG, "Connection refused, server unavailable"); - return ESP_FAIL; - case CONNECTION_REFUSE_BAD_USERNAME: - ESP_LOGW(TAG, "Connection refused, bad username or password"); - return ESP_FAIL; - case CONNECTION_REFUSE_NOT_AUTHORIZED: - ESP_LOGW(TAG, "Connection refused, not authorized"); - return ESP_FAIL; - default: - ESP_LOGW(TAG, "Connection refused, Unknow reason"); - return ESP_FAIL; + case CONNECTION_ACCEPTED: + ESP_LOGD(TAG, "Connected"); + return ESP_OK; + case CONNECTION_REFUSE_PROTOCOL: + ESP_LOGW(TAG, "Connection refused, bad protocol"); + return ESP_FAIL; + case CONNECTION_REFUSE_SERVER_UNAVAILABLE: + ESP_LOGW(TAG, "Connection refused, server unavailable"); + return ESP_FAIL; + case CONNECTION_REFUSE_BAD_USERNAME: + ESP_LOGW(TAG, "Connection refused, bad username or password"); + return ESP_FAIL; + case CONNECTION_REFUSE_NOT_AUTHORIZED: + ESP_LOGW(TAG, "Connection refused, not authorized"); + return ESP_FAIL; + default: + ESP_LOGW(TAG, "Connection refused, Unknow reason"); + return ESP_FAIL; } return ESP_OK; } @@ -491,7 +490,7 @@ esp_err_t esp_mqtt_client_set_uri(esp_mqtt_client_handle_t client, const char *u } if (puri.field_data[UF_PORT].len) { - client->config->port = strtol((const char*)(uri + puri.field_data[UF_PORT].off), NULL, 10); + client->config->port = strtol((const char *)(uri + puri.field_data[UF_PORT].off), NULL, 10); } char *user_info = create_string(uri + puri.field_data[UF_USERINFO].off, puri.field_data[UF_USERINFO].len); @@ -513,9 +512,9 @@ esp_err_t esp_mqtt_client_set_uri(esp_mqtt_client_handle_t client, const char *u static esp_err_t mqtt_write_data(esp_mqtt_client_handle_t client) { int write_len = esp_transport_write(client->transport, - (char *)client->mqtt_state.outbound_message->data, - client->mqtt_state.outbound_message->length, - client->config->network_timeout_ms); + (char *)client->mqtt_state.outbound_message->data, + client->mqtt_state.outbound_message->length, + client->config->network_timeout_ms); // client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data); if (write_len <= 0) { ESP_LOGE(TAG, "Error write data or timeout, written len = %d, errno=%d", write_len, errno); @@ -564,7 +563,7 @@ static esp_err_t deliver_publish(esp_mqtt_client_handle_t client) // get payload msg_data = mqtt_get_publish_data(msg_buf, &msg_data_len); - if(msg_data_len > 0 && msg_data == NULL) { + if (msg_data_len > 0 && msg_data == NULL) { ESP_LOGE(TAG, "%s: mqtt_get_publish_data() failed", __func__); return ESP_FAIL; } @@ -575,7 +574,7 @@ static esp_err_t deliver_publish(esp_mqtt_client_handle_t client) post_data_event: ESP_LOGD(TAG, "Get data len= %d, topic len=%d, total_data: %d offset: %d", msg_data_len, msg_topic_len, - client->event.total_data_len, msg_data_offset); + client->event.total_data_len, msg_data_offset); client->event.event_id = MQTT_EVENT_DATA; client->event.data = msg_data_len > 0 ? msg_data : NULL; client->event.data_len = msg_data_len; @@ -589,7 +588,7 @@ post_data_event: size_t buf_len = client->mqtt_state.in_buffer_length; esp_transport_handle_t transport = esp_transport_get_payload_transport_handle(client->transport); - msg_data = (char*)client->mqtt_state.in_buffer; + msg_data = (char *)client->mqtt_state.in_buffer; msg_topic = NULL; msg_topic_len = 0; msg_data_offset += msg_data_len; @@ -706,7 +705,7 @@ static int mqtt_message_receive(esp_mqtt_client_handle_t client, int read_poll_t /* any further reading only the underlying payload */ t = esp_transport_get_payload_transport_handle(t); if ((client->mqtt_state.in_buffer_read_len == 1) || - ((client->mqtt_state.in_buffer_read_len < 6) && (*(buf - 1) & 0x80))) { + ((client->mqtt_state.in_buffer_read_len < 6) && (*(buf - 1) & 0x80))) { do { /* * Read the "remaining length" part of mqtt packet fixed header. It @@ -758,8 +757,8 @@ static int mqtt_message_receive(esp_mqtt_client_handle_t client, int read_poll_t } } int topic_len = client->mqtt_state.in_buffer[fixed_header_len] << 8; - topic_len |= client->mqtt_state.in_buffer[fixed_header_len+1]; - total_len = fixed_header_len + topic_len + (mqtt_get_qos(client->mqtt_state.in_buffer)>0?2:0); + topic_len |= client->mqtt_state.in_buffer[fixed_header_len + 1]; + total_len = fixed_header_len + topic_len + (mqtt_get_qos(client->mqtt_state.in_buffer) > 0 ? 2 : 0); ESP_LOGD(TAG, "%s: total len modified to %d as message longer than input buffer", __func__, total_len); if (client->mqtt_state.in_buffer_length < total_len) { ESP_LOGE(TAG, "%s: message is too big, insufficient buffer size", __func__); @@ -822,75 +821,73 @@ static esp_err_t mqtt_process_receive(esp_mqtt_client_handle_t client) ESP_LOGD(TAG, "msg_type=%d, msg_id=%d", msg_type, msg_id); - switch (msg_type) - { - case MQTT_MSG_TYPE_SUBACK: - if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_SUBSCRIBE, msg_id)) { - ESP_LOGD(TAG, "Subscribe successful"); - client->event.event_id = MQTT_EVENT_SUBSCRIBED; - esp_mqtt_dispatch_event_with_msgid(client); - } - break; - case MQTT_MSG_TYPE_UNSUBACK: - if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_UNSUBSCRIBE, msg_id)) { - ESP_LOGD(TAG, "UnSubscribe successful"); - client->event.event_id = MQTT_EVENT_UNSUBSCRIBED; - esp_mqtt_dispatch_event_with_msgid(client); - } - break; - case MQTT_MSG_TYPE_PUBLISH: - ESP_LOGD(TAG, "deliver_publish, message_length_read=%d, message_length=%d", client->mqtt_state.in_buffer_read_len, client->mqtt_state.message_length); - if (deliver_publish(client) != ESP_OK) { - ESP_LOGE(TAG, "Failed to deliver publish message id=%d", msg_id); + switch (msg_type) { + case MQTT_MSG_TYPE_SUBACK: + if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_SUBSCRIBE, msg_id)) { + ESP_LOGD(TAG, "Subscribe successful"); + client->event.event_id = MQTT_EVENT_SUBSCRIBED; + esp_mqtt_dispatch_event_with_msgid(client); + } + break; + case MQTT_MSG_TYPE_UNSUBACK: + if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_UNSUBSCRIBE, msg_id)) { + ESP_LOGD(TAG, "UnSubscribe successful"); + client->event.event_id = MQTT_EVENT_UNSUBSCRIBED; + esp_mqtt_dispatch_event_with_msgid(client); + } + break; + case MQTT_MSG_TYPE_PUBLISH: + ESP_LOGD(TAG, "deliver_publish, message_length_read=%d, message_length=%d", client->mqtt_state.in_buffer_read_len, client->mqtt_state.message_length); + if (deliver_publish(client) != ESP_OK) { + ESP_LOGE(TAG, "Failed to deliver publish message id=%d", msg_id); + return ESP_FAIL; + } + if (msg_qos == 1) { + client->mqtt_state.outbound_message = mqtt_msg_puback(&client->mqtt_state.mqtt_connection, msg_id); + } else if (msg_qos == 2) { + client->mqtt_state.outbound_message = mqtt_msg_pubrec(&client->mqtt_state.mqtt_connection, msg_id); + } + + if (msg_qos == 1 || msg_qos == 2) { + ESP_LOGD(TAG, "Queue response QoS: %d", msg_qos); + + if (mqtt_write_data(client) != ESP_OK) { + ESP_LOGE(TAG, "Error write qos msg repsonse, qos = %d", msg_qos); return ESP_FAIL; } - if (msg_qos == 1) { - client->mqtt_state.outbound_message = mqtt_msg_puback(&client->mqtt_state.mqtt_connection, msg_id); - } - else if (msg_qos == 2) { - client->mqtt_state.outbound_message = mqtt_msg_pubrec(&client->mqtt_state.mqtt_connection, msg_id); - } - - if (msg_qos == 1 || msg_qos == 2) { - ESP_LOGD(TAG, "Queue response QoS: %d", msg_qos); - - if (mqtt_write_data(client) != ESP_OK) { - ESP_LOGE(TAG, "Error write qos msg repsonse, qos = %d", msg_qos); - return ESP_FAIL; - } - } - break; - case MQTT_MSG_TYPE_PUBACK: - if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_PUBLISH, msg_id)) { - ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBACK, finish QoS1 publish"); - outbox_set_pending(client->outbox, msg_id, CONFIRMED); - client->event.event_id = MQTT_EVENT_PUBLISHED; - esp_mqtt_dispatch_event_with_msgid(client); - } - break; - case MQTT_MSG_TYPE_PUBREC: - ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBREC"); - client->mqtt_state.outbound_message = mqtt_msg_pubrel(&client->mqtt_state.mqtt_connection, msg_id); + } + break; + case MQTT_MSG_TYPE_PUBACK: + if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_PUBLISH, msg_id)) { + ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBACK, finish QoS1 publish"); outbox_set_pending(client->outbox, msg_id, CONFIRMED); - mqtt_write_data(client); - break; - case MQTT_MSG_TYPE_PUBREL: - ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBREL"); - client->mqtt_state.outbound_message = mqtt_msg_pubcomp(&client->mqtt_state.mqtt_connection, msg_id); - mqtt_write_data(client); - break; - case MQTT_MSG_TYPE_PUBCOMP: - ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBCOMP"); - if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_PUBLISH, msg_id)) { - ESP_LOGD(TAG, "Receive MQTT_MSG_TYPE_PUBCOMP, finish QoS2 publish"); - client->event.event_id = MQTT_EVENT_PUBLISHED; - esp_mqtt_dispatch_event_with_msgid(client); - } - break; - case MQTT_MSG_TYPE_PINGRESP: - ESP_LOGD(TAG, "MQTT_MSG_TYPE_PINGRESP"); - client->wait_for_ping_resp = false; - break; + client->event.event_id = MQTT_EVENT_PUBLISHED; + esp_mqtt_dispatch_event_with_msgid(client); + } + break; + case MQTT_MSG_TYPE_PUBREC: + ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBREC"); + client->mqtt_state.outbound_message = mqtt_msg_pubrel(&client->mqtt_state.mqtt_connection, msg_id); + outbox_set_pending(client->outbox, msg_id, CONFIRMED); + mqtt_write_data(client); + break; + case MQTT_MSG_TYPE_PUBREL: + ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBREL"); + client->mqtt_state.outbound_message = mqtt_msg_pubcomp(&client->mqtt_state.mqtt_connection, msg_id); + mqtt_write_data(client); + break; + case MQTT_MSG_TYPE_PUBCOMP: + ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBCOMP"); + if (is_valid_mqtt_msg(client, MQTT_MSG_TYPE_PUBLISH, msg_id)) { + ESP_LOGD(TAG, "Receive MQTT_MSG_TYPE_PUBCOMP, finish QoS2 publish"); + client->event.event_id = MQTT_EVENT_PUBLISHED; + esp_mqtt_dispatch_event_with_msgid(client); + } + break; + case MQTT_MSG_TYPE_PINGRESP: + ESP_LOGD(TAG, "MQTT_MSG_TYPE_PINGRESP"); + client->wait_for_ping_resp = false; + break; } client->mqtt_state.in_buffer_read_len = 0; @@ -901,9 +898,9 @@ static esp_err_t mqtt_resend_queued(esp_mqtt_client_handle_t client, outbox_item { // decode queued data client->mqtt_state.outbound_message->data = outbox_item_get_data(item, &client->mqtt_state.outbound_message->length, &client->mqtt_state.pending_msg_id, - &client->mqtt_state.pending_msg_type, &client->mqtt_state.pending_publish_qos); + &client->mqtt_state.pending_msg_type, &client->mqtt_state.pending_publish_qos); // set duplicate flag for QoS-2 message - if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH &&client->mqtt_state.pending_publish_qos==2) { + if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && client->mqtt_state.pending_publish_qos == 2) { mqtt_set_dup(client->mqtt_state.outbound_message->data); } @@ -940,111 +937,111 @@ static void esp_mqtt_task(void *pv) while (client->run) { MQTT_API_LOCK(client); switch ((int)client->state) { - case MQTT_STATE_INIT: - xEventGroupClearBits(client->status_bits, RECONNECT_BIT); - client->event.event_id = MQTT_EVENT_BEFORE_CONNECT; - esp_mqtt_dispatch_event_with_msgid(client); + case MQTT_STATE_INIT: + xEventGroupClearBits(client->status_bits, RECONNECT_BIT); + client->event.event_id = MQTT_EVENT_BEFORE_CONNECT; + esp_mqtt_dispatch_event_with_msgid(client); - if (client->transport == NULL) { - ESP_LOGE(TAG, "There are no transport"); - client->run = false; - } + if (client->transport == NULL) { + ESP_LOGE(TAG, "There are no transport"); + client->run = false; + } - if (esp_transport_connect(client->transport, + if (esp_transport_connect(client->transport, client->config->host, client->config->port, client->config->network_timeout_ms) < 0) { - ESP_LOGE(TAG, "Error transport connect"); - esp_mqtt_abort_connection(client); - break; - } - ESP_LOGD(TAG, "Transport connected to %s://%s:%d", client->config->scheme, client->config->host, client->config->port); - if (esp_mqtt_connect(client, client->config->network_timeout_ms) != ESP_OK) { - ESP_LOGI(TAG, "Error MQTT Connected"); - esp_mqtt_abort_connection(client); - break; - } - client->event.event_id = MQTT_EVENT_CONNECTED; - client->event.session_present = mqtt_get_connect_session_present(client->mqtt_state.in_buffer); - client->state = MQTT_STATE_CONNECTED; - esp_mqtt_dispatch_event_with_msgid(client); - client->refresh_connection_tick = platform_tick_get_ms(); - + ESP_LOGE(TAG, "Error transport connect"); + esp_mqtt_abort_connection(client); break; - case MQTT_STATE_CONNECTED: - // receive and process data - if (mqtt_process_receive(client) == ESP_FAIL) { - esp_mqtt_abort_connection(client); - break; - } + } + ESP_LOGD(TAG, "Transport connected to %s://%s:%d", client->config->scheme, client->config->host, client->config->port); + if (esp_mqtt_connect(client, client->config->network_timeout_ms) != ESP_OK) { + ESP_LOGI(TAG, "Error MQTT Connected"); + esp_mqtt_abort_connection(client); + break; + } + client->event.event_id = MQTT_EVENT_CONNECTED; + client->event.session_present = mqtt_get_connect_session_present(client->mqtt_state.in_buffer); + client->state = MQTT_STATE_CONNECTED; + esp_mqtt_dispatch_event_with_msgid(client); + client->refresh_connection_tick = platform_tick_get_ms(); - // resend all non-transmitted messages first - outbox_item_handle_t item = outbox_dequeue(client->outbox, QUEUED, NULL); - if (item) { - if (mqtt_resend_queued(client, item) == ESP_OK) { - outbox_set_pending(client->outbox, client->mqtt_state.pending_msg_id, TRANSMITTED); - } + break; + case MQTT_STATE_CONNECTED: + // receive and process data + if (mqtt_process_receive(client) == ESP_FAIL) { + esp_mqtt_abort_connection(client); + break; + } + + // resend all non-transmitted messages first + outbox_item_handle_t item = outbox_dequeue(client->outbox, QUEUED, NULL); + if (item) { + if (mqtt_resend_queued(client, item) == ESP_OK) { + outbox_set_pending(client->outbox, client->mqtt_state.pending_msg_id, TRANSMITTED); + } // resend other "transmitted" messages after 1s - } else if (platform_tick_get_ms() - last_retransmit > 1000) { - last_retransmit = platform_tick_get_ms(); - item = outbox_dequeue(client->outbox, TRANSMITTED, &msg_tick); - if (item && (last_retransmit - msg_tick > 1000)) { - mqtt_resend_queued(client, item); - } + } else if (platform_tick_get_ms() - last_retransmit > 1000) { + last_retransmit = platform_tick_get_ms(); + item = outbox_dequeue(client->outbox, TRANSMITTED, &msg_tick); + if (item && (last_retransmit - msg_tick > 1000)) { + mqtt_resend_queued(client, item); } + } - if (platform_tick_get_ms() - client->keepalive_tick > client->connect_info.keepalive * 1000 / 2) { - //No ping resp from last ping => Disconnected - if(client->wait_for_ping_resp){ - ESP_LOGE(TAG, "No PING_RESP, disconnected"); - esp_mqtt_abort_connection(client); - client->wait_for_ping_resp = false; - break; - } - if (esp_mqtt_client_ping(client) == ESP_FAIL) { - ESP_LOGE(TAG, "Can't send ping, disconnected"); - esp_mqtt_abort_connection(client); - break; - } else { - client->wait_for_ping_resp = true; - } - ESP_LOGD(TAG, "PING sent"); - } - - if (client->config->refresh_connection_after_ms && - platform_tick_get_ms() - client->refresh_connection_tick > client->config->refresh_connection_after_ms) { - ESP_LOGD(TAG, "Refreshing the connection..."); + if (platform_tick_get_ms() - client->keepalive_tick > client->connect_info.keepalive * 1000 / 2) { + //No ping resp from last ping => Disconnected + if (client->wait_for_ping_resp) { + ESP_LOGE(TAG, "No PING_RESP, disconnected"); esp_mqtt_abort_connection(client); - client->state = MQTT_STATE_INIT; + client->wait_for_ping_resp = false; + break; } + if (esp_mqtt_client_ping(client) == ESP_FAIL) { + ESP_LOGE(TAG, "Can't send ping, disconnected"); + esp_mqtt_abort_connection(client); + break; + } else { + client->wait_for_ping_resp = true; + } + ESP_LOGD(TAG, "PING sent"); + } - //Delete mesaage after 30 senconds - 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) { - client->mqtt_state.pending_msg_count = 0; - } - // - outbox_cleanup(client->outbox, OUTBOX_MAX_SIZE); + if (client->config->refresh_connection_after_ms && + platform_tick_get_ms() - client->refresh_connection_tick > client->config->refresh_connection_after_ms) { + ESP_LOGD(TAG, "Refreshing the connection..."); + esp_mqtt_abort_connection(client); + client->state = MQTT_STATE_INIT; + } + + //Delete mesaage after 30 senconds + 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) { + client->mqtt_state.pending_msg_count = 0; + } + // + outbox_cleanup(client->outbox, OUTBOX_MAX_SIZE); + break; + case MQTT_STATE_WAIT_TIMEOUT: + + if (!client->config->auto_reconnect) { + client->run = false; + client->state = MQTT_STATE_UNKNOWN; break; - case MQTT_STATE_WAIT_TIMEOUT: - - if (!client->config->auto_reconnect) { - client->run = false; - client->state = MQTT_STATE_UNKNOWN; - break; - } - if (platform_tick_get_ms() - client->reconnect_tick > client->wait_timeout_ms) { - client->state = MQTT_STATE_INIT; - client->reconnect_tick = platform_tick_get_ms(); - ESP_LOGD(TAG, "Reconnecting..."); - break; - } - 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; + } + if (platform_tick_get_ms() - client->reconnect_tick > client->wait_timeout_ms) { + client->state = MQTT_STATE_INIT; + client->reconnect_tick = platform_tick_get_ms(); + ESP_LOGD(TAG, "Reconnecting..."); + break; + } + 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; } MQTT_API_UNLOCK(client); if (MQTT_STATE_CONNECTED == client->state) { @@ -1072,17 +1069,17 @@ esp_err_t esp_mqtt_client_start(esp_mqtt_client_handle_t client) return ESP_FAIL; } #if MQTT_CORE_SELECTION_ENABLED - ESP_LOGD(TAG, "Core selection enabled on %u", MQTT_TASK_CORE); - if (xTaskCreatePinnedToCore(esp_mqtt_task, "mqtt_task", client->config->task_stack, client, client->config->task_prio, &client->task_handle, MQTT_TASK_CORE) != pdTRUE) { - ESP_LOGE(TAG, "Error create mqtt task"); - return ESP_FAIL; - } + ESP_LOGD(TAG, "Core selection enabled on %u", MQTT_TASK_CORE); + if (xTaskCreatePinnedToCore(esp_mqtt_task, "mqtt_task", client->config->task_stack, client, client->config->task_prio, &client->task_handle, MQTT_TASK_CORE) != pdTRUE) { + ESP_LOGE(TAG, "Error create mqtt task"); + return ESP_FAIL; + } #else - ESP_LOGD(TAG, "Core selection disabled"); - if (xTaskCreate(esp_mqtt_task, "mqtt_task", client->config->task_stack, client, client->config->task_prio, &client->task_handle) != pdTRUE) { - ESP_LOGE(TAG, "Error create mqtt task"); - return ESP_FAIL; - } + ESP_LOGD(TAG, "Core selection disabled"); + if (xTaskCreate(esp_mqtt_task, "mqtt_task", client->config->task_stack, client, client->config->task_prio, &client->task_handle) != pdTRUE) { + ESP_LOGE(TAG, "Error create mqtt task"); + return ESP_FAIL; + } #endif return ESP_OK; } @@ -1109,7 +1106,7 @@ esp_err_t esp_mqtt_client_stop(esp_mqtt_client_handle_t client) ESP_LOGE(TAG, "Error sending disconnect message"); } MQTT_API_UNLOCK_FROM_OTHER_TASK(client); - + client->run = false; xEventGroupWaitBits(client->status_bits, STOPPED_BIT, false, true, portMAX_DELAY); client->state = MQTT_STATE_UNKNOWN; @@ -1247,7 +1244,7 @@ int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, current_data += data_sent; if (remaining_len > 0) { - mqtt_connection_t* connection = &client->mqtt_state.mqtt_connection; + mqtt_connection_t *connection = &client->mqtt_state.mqtt_connection; ESP_LOGD(TAG, "Sending fragmented message, remains to send %d bytes of %d", remaining_len, len); if (connection->message.fragmented_msg_data_offset) { // asked to enqueue oversized message (first time only) @@ -1255,7 +1252,7 @@ int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, connection->message.fragmented_msg_total_length = 0; if (qos > 0) { // internally enqueue all big messages, as they dont fit 'pending msg' structure - mqtt_enqueue_oversized(client, (uint8_t*)current_data, remaining_len); + mqtt_enqueue_oversized(client, (uint8_t *)current_data, remaining_len); } } From eeebd0215c3a93c403bed71e615cf0570144b110 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 18 Dec 2018 16:43:08 +0100 Subject: [PATCH 49/56] support for esp event loop library while keeping backward compatible mode if callback configured --- README.md | 14 +++++++++++++- include/mqtt_client.h | 17 ++++++++++++++++- mqtt_client.c | 33 +++++++++++++++++++++++++++++++-- 3 files changed, 60 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index abe4822..6a6fe3e 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,21 @@ Please refer to instructions in [ESP-IDF](https://github.com/espressif/esp-idf) ## Documentation -Please refer to the standard [ESP-IDF](https://github.com/espressif/esp-idf) documentation here https://github.com/espressif/esp-idf/blob/master/docs/en/api-reference/protocols/mqtt.rst + +* Please refer to the standard [ESP-IDF](https://github.com/espressif/esp-idf), documentation for the latest version: https://docs.espressif.com/projects/esp-idf/ + +* Documentation of ESP-MQTT API: https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/protocols/mqtt.html ## License + - MQTT Package - [Stephen Robinson - contiki-mqtt](https://github.com/esar/contiki-mqtt) - Others [@tuanpmt](https://twitter.com/tuanpmt) Apache License + +## Older IDF verisons + +For [ESP-IDF](https://github.com/espressif/esp-idf) versions prior to IDFv3.2, please clone as a component of [ESP-IDF](https://github.com/espressif/esp-idf): +``` +git submodule add https://github.com/espressif/esp-mqtt.git components/espmqtt +``` +and checkout the [ESP-MQTT_FOR_IDF_3.1](https://github.com/espressif/esp-mqtt/tree/ESP-MQTT_FOR_IDF_3.1) tag diff --git a/include/mqtt_client.h b/include/mqtt_client.h index cb06132..8b05d0b 100644 --- a/include/mqtt_client.h +++ b/include/mqtt_client.h @@ -13,6 +13,7 @@ #include "esp_err.h" #include "mqtt_config.h" +#include "esp_event.h" #ifdef __cplusplus extern "C" { @@ -85,7 +86,8 @@ typedef esp_err_t (* mqtt_event_callback_t)(esp_mqtt_event_handle_t event); * MQTT client configuration structure */ typedef struct { - mqtt_event_callback_t event_handle; /*!< handle for MQTT events */ + mqtt_event_callback_t event_handle; /*!< handle for MQTT events as a callback in legacy mode */ + esp_event_loop_handle_t event_loop_handle; /*!< handle for MQTT event loop library */ const char *host; /*!< MQTT server domain (ipv4 as string) */ const char *uri; /*!< Complete MQTT broker URI */ uint32_t port; /*!< MQTT server port */ @@ -237,6 +239,19 @@ esp_err_t esp_mqtt_client_destroy(esp_mqtt_client_handle_t client); */ esp_err_t esp_mqtt_set_config(esp_mqtt_client_handle_t client, const esp_mqtt_client_config_t *config); +/** + * @brief Registers mqtt event + * + * @param client mqtt client handle + * @param event event type + * @param event_handler hanlder callback + * @param event_handler_arg handlers context + * + * @return ESP_ERR_NO_MEM if failed to allocate + * ESP_OK on success + */ +esp_err_t esp_mqtt_client_register_event(esp_mqtt_client_handle_t client, esp_mqtt_event_id_t event, esp_event_handler_t event_handler, void* event_handler_arg); + #ifdef __cplusplus } #endif //__cplusplus diff --git a/mqtt_client.c b/mqtt_client.c index 6afae73..db86724 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -12,6 +12,7 @@ /* using uri parser */ #include "http_parser.h" +#include "esp_event_loop.h" #ifdef MQTT_DISABLE_API_LOCKS # define MQTT_API_LOCK(c) @@ -27,7 +28,14 @@ static const char *TAG = "MQTT_CLIENT"; -typedef struct mqtt_state { +/** + * @brief Define of MQTT Event base + * + */ +ESP_EVENT_DEFINE_BASE(MQTT_EVENTS); + +typedef struct mqtt_state +{ mqtt_connect_info_t *connect_info; uint8_t *in_buffer; uint8_t *out_buffer; @@ -45,6 +53,7 @@ typedef struct mqtt_state { typedef struct { mqtt_event_callback_t event_handle; + esp_event_loop_handle_t event_loop_handle; int task_stack; int task_prio; char *uri; @@ -214,6 +223,12 @@ esp_err_t esp_mqtt_set_config(esp_mqtt_client_handle_t client, const esp_mqtt_cl if (config->event_handle) { cfg->event_handle = config->event_handle; + } else { + esp_event_loop_args_t no_task_loop = { + .queue_size = 1, + .task_name = NULL, + }; + esp_event_loop_create(&no_task_loop, &cfg->event_loop_handle); } if (config->refresh_connection_after_ms) { @@ -540,8 +555,10 @@ static esp_err_t esp_mqtt_dispatch_event(esp_mqtt_client_handle_t client) if (client->config->event_handle) { return client->config->event_handle(&client->event); + } else { + esp_event_post_to(client->config->event_loop_handle, MQTT_EVENTS, client->event.event_id, &client->event, sizeof(client->event), portMAX_DELAY); + return esp_event_loop_run(client->config->event_loop_handle, 0); } - return ESP_FAIL; } static esp_err_t deliver_publish(esp_mqtt_client_handle_t client) @@ -1289,3 +1306,15 @@ cannot_publish: } +esp_err_t esp_mqtt_client_register_event(esp_mqtt_client_handle_t client, esp_mqtt_event_id_t event, esp_event_handler_t event_handler, void* event_handler_arg) +{ + if (client == NULL) { + return ESP_ERR_INVALID_ARG; + } + if (client->config->event_handle) { + ESP_LOGW(TAG, "Registering event loop while event callback is not null, clearing callback"); + client->config->event_handle = NULL; + } + + return esp_event_handler_register_with(client->config->event_loop_handle, MQTT_EVENTS, event, event_handler, event_handler_arg); +} From 2ef78857e96be9577f534299653e5a5f34e9e80c Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 19 Mar 2019 15:06:20 +0800 Subject: [PATCH 50/56] fix -Wstrict-prototypes issues --- lib/include/mqtt_outbox.h | 2 +- lib/include/platform_esp32_idf.h | 4 ++-- lib/mqtt_outbox.c | 2 +- lib/platform_esp32_idf.c | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/include/mqtt_outbox.h b/lib/include/mqtt_outbox.h index e3a5ba7..36981e5 100644 --- a/lib/include/mqtt_outbox.h +++ b/lib/include/mqtt_outbox.h @@ -33,7 +33,7 @@ typedef enum pending_state { CONFIRMED } pending_state_t; -outbox_handle_t outbox_init(); +outbox_handle_t outbox_init(void); outbox_item_handle_t outbox_enqueue(outbox_handle_t outbox, outbox_message_handle_t message, int tick); outbox_item_handle_t outbox_dequeue(outbox_handle_t outbox, pending_state_t pending, int *tick); outbox_item_handle_t outbox_get(outbox_handle_t outbox, int msg_id); diff --git a/lib/include/platform_esp32_idf.h b/lib/include/platform_esp32_idf.h index b25b5db..1054a18 100644 --- a/lib/include/platform_esp32_idf.h +++ b/lib/include/platform_esp32_idf.h @@ -23,9 +23,9 @@ #include "esp_log.h" #include "esp_system.h" -char *platform_create_id_string(); +char *platform_create_id_string(void); int platform_random(int max); -long long platform_tick_get_ms(); +long long platform_tick_get_ms(void); void ms_to_timeval(int timeout_ms, struct timeval *tv); #define ESP_MEM_CHECK(TAG, a, action) if (!(a)) { \ diff --git a/lib/mqtt_outbox.c b/lib/mqtt_outbox.c index ac7359a..d92bfb6 100644 --- a/lib/mqtt_outbox.c +++ b/lib/mqtt_outbox.c @@ -24,7 +24,7 @@ typedef struct outbox_item { STAILQ_HEAD(outbox_list_t, outbox_item); -outbox_handle_t outbox_init() +outbox_handle_t outbox_init(void) { outbox_handle_t outbox = calloc(1, sizeof(struct outbox_list_t)); ESP_MEM_CHECK(TAG, outbox, return NULL); diff --git a/lib/platform_esp32_idf.c b/lib/platform_esp32_idf.c index bbe0199..4e2b5a8 100644 --- a/lib/platform_esp32_idf.c +++ b/lib/platform_esp32_idf.c @@ -9,7 +9,7 @@ static const char *TAG = "PLATFORM"; #define MAX_ID_STRING (32) -char *platform_create_id_string() +char *platform_create_id_string(void) { uint8_t mac[6]; char *id_string = calloc(1, MAX_ID_STRING); @@ -24,7 +24,7 @@ int platform_random(int max) return esp_random() % max; } -long long platform_tick_get_ms() +long long platform_tick_get_ms(void) { struct timeval te; gettimeofday(&te, NULL); // get current time From a6f8716fffd78f10f22b78ad4b7a826602439d3b Mon Sep 17 00:00:00 2001 From: Tuan Date: Tue, 2 Apr 2019 14:54:50 +0700 Subject: [PATCH 51/56] Add mqtt sub protocol for websocket --- mqtt_client.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mqtt_client.c b/mqtt_client.c index db86724..a28aca9 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -368,6 +368,7 @@ esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *co esp_transport_handle_t ws = esp_transport_ws_init(tcp); ESP_MEM_CHECK(TAG, ws, goto _mqtt_init_failed); esp_transport_set_default_port(ws, MQTT_WS_DEFAULT_PORT); + esp_transport_ws_set_subprotocol(ws, "mqtt"); esp_transport_list_add(client->transport_list, ws, "ws"); if (config->transport == MQTT_TRANSPORT_OVER_WS) { client->config->scheme = create_string("ws", 2); @@ -398,6 +399,7 @@ esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *co #if MQTT_ENABLE_WSS esp_transport_handle_t wss = esp_transport_ws_init(ssl); ESP_MEM_CHECK(TAG, wss, goto _mqtt_init_failed); + esp_transport_ws_set_subprotocol(wss, "mqtt"); esp_transport_set_default_port(wss, MQTT_WSS_DEFAULT_PORT); esp_transport_list_add(client->transport_list, wss, "wss"); if (config->transport == MQTT_TRANSPORT_OVER_WSS) { From 48cd04baf14ad61e9496206aeba8f7ef96d0c283 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Fri, 24 May 2019 11:04:42 +0200 Subject: [PATCH 52/56] defined macros for supported features in esp-idf based on idf version --- include/mqtt_supported_features.h | 38 +++++++++++++++++++++++++++++++ mqtt_client.c | 6 +++++ 2 files changed, 44 insertions(+) create mode 100644 include/mqtt_supported_features.h diff --git a/include/mqtt_supported_features.h b/include/mqtt_supported_features.h new file mode 100644 index 0000000..9a3ab04 --- /dev/null +++ b/include/mqtt_supported_features.h @@ -0,0 +1,38 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + +#ifndef _MQTT_SUPPORTED_FEATURES_H_ +#define _MQTT_SUPPORTED_FEATURES_H_ + +#if __has_include("esp_idf_version.h") +#include "esp_idf_version.h" +#endif + +/** + * @brief This header defines supported features of IDF which mqtt module + * could use depending on specific version of ESP-IDF. + * In case "esp_idf_version.h" were not found, all additional + * features would be disabled + */ + +#ifdef ESP_IDF_VERSION +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) + +#define MQTT_SUPPORTED_FEATURE_WS_SUBPROTOCOL + +#endif +#endif + + +#endif // _MQTT_SUPPORTED_FEATURES_H_ \ No newline at end of file diff --git a/mqtt_client.c b/mqtt_client.c index a28aca9..a3e2fce 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -9,6 +9,7 @@ #include "esp_transport_ws.h" #include "platform.h" #include "mqtt_outbox.h" +#include "mqtt_supported_features.h" /* using uri parser */ #include "http_parser.h" @@ -26,6 +27,7 @@ # define MQTT_API_UNLOCK_FROM_OTHER_TASK(c) { if (c->task_handle != xTaskGetCurrentTaskHandle()) { xSemaphoreGive(c->api_lock); } } #endif /* MQTT_USE_API_LOCKS */ + static const char *TAG = "MQTT_CLIENT"; /** @@ -368,7 +370,9 @@ esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *co esp_transport_handle_t ws = esp_transport_ws_init(tcp); ESP_MEM_CHECK(TAG, ws, goto _mqtt_init_failed); esp_transport_set_default_port(ws, MQTT_WS_DEFAULT_PORT); +#ifdef MQTT_SUPPORTED_FEATURE_WS_SUBPROTOCOL esp_transport_ws_set_subprotocol(ws, "mqtt"); +#endif esp_transport_list_add(client->transport_list, ws, "ws"); if (config->transport == MQTT_TRANSPORT_OVER_WS) { client->config->scheme = create_string("ws", 2); @@ -399,7 +403,9 @@ esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *co #if MQTT_ENABLE_WSS esp_transport_handle_t wss = esp_transport_ws_init(ssl); ESP_MEM_CHECK(TAG, wss, goto _mqtt_init_failed); +#ifdef MQTT_SUPPORTED_FEATURE_WS_SUBPROTOCOL esp_transport_ws_set_subprotocol(wss, "mqtt"); +#endif esp_transport_set_default_port(wss, MQTT_WSS_DEFAULT_PORT); esp_transport_list_add(client->transport_list, wss, "wss"); if (config->transport == MQTT_TRANSPORT_OVER_WSS) { From 5afe3e6b24f2c18b5c484e1f36e329643928b322 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 4 Jun 2019 13:22:56 +0200 Subject: [PATCH 53/56] ci: internal ci step for building with legacy idf to avoid travis failures --- .gitlab-ci.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3461a4c..393b499 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,6 +7,8 @@ stages: variables: IDF_REPO: ${GITLAB_SSH_SERVER}/idf/esp-idf.git + OLDER_IDF: release/v3.1 + RECENT_IDF: release/v3.3 .add_gh_key_remote: &add_gh_key_remote | cit_add_ssh_key "${GH_PUSH_KEY}" @@ -19,6 +21,23 @@ before_script: - source citools/import_functions - PATH=$CI_PROJECT_DIR/esp-idf/tools:$PATH +build_with_older_idf: + stage: build + image: ${CI_DOCKER_REGISTRY}/esp32-ci-env + tags: + - build + dependencies: [] + script: + - cit_add_ssh_key "${GITLAB_KEY}" + - git clone "${IDF_REPO}" && cd esp-idf && git checkout ${OLDER_IDF} + - ./tools/ci/mirror-submodule-update.sh + - export IDF_PATH=$(pwd) + - cd $CI_PROJECT_DIR + - ./modify_for_legacy_idf.sh ${RECENT_IDF} || true + - cd $CI_PROJECT_DIR/examples/tcp + - make defconfig + - make + build_with_idf: stage: build image: ${CI_DOCKER_REGISTRY}/esp32-ci-env From edd67e1c8c837ebb43364301784c8d2b2742a1c8 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 29 May 2019 15:12:25 +0200 Subject: [PATCH 54/56] used event loop only if defined in supported features (enabled by macros) for backward compatibily with older IDFs --- include/mqtt_client.h | 6 ++++++ include/mqtt_supported_features.h | 9 +++++++-- mqtt_client.c | 15 +++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/include/mqtt_client.h b/include/mqtt_client.h index 8b05d0b..a347f08 100644 --- a/include/mqtt_client.h +++ b/include/mqtt_client.h @@ -19,6 +19,12 @@ extern "C" { #endif +#ifndef ESP_EVENT_DECLARE_BASE +// Define event loop types if macros not available +typedef void * esp_event_loop_handle_t; +typedef void * esp_event_handler_t; +#endif + typedef struct esp_mqtt_client *esp_mqtt_client_handle_t; /** diff --git a/include/mqtt_supported_features.h b/include/mqtt_supported_features.h index 9a3ab04..3e9fac0 100644 --- a/include/mqtt_supported_features.h +++ b/include/mqtt_supported_features.h @@ -27,10 +27,15 @@ */ #ifdef ESP_IDF_VERSION + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(3, 3, 0) +// Features supported from 3.3 +#define MQTT_SUPPORTED_FEATURE_EVENT_LOOP +#endif + #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) - +// Features supported in 4.0 #define MQTT_SUPPORTED_FEATURE_WS_SUBPROTOCOL - #endif #endif diff --git a/mqtt_client.c b/mqtt_client.c index a3e2fce..a95f4b3 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -30,11 +30,13 @@ static const char *TAG = "MQTT_CLIENT"; +#ifdef MQTT_SUPPORTED_FEATURE_EVENT_LOOP /** * @brief Define of MQTT Event base * */ ESP_EVENT_DEFINE_BASE(MQTT_EVENTS); +#endif typedef struct mqtt_state { @@ -55,7 +57,9 @@ typedef struct mqtt_state typedef struct { mqtt_event_callback_t event_handle; +#ifdef MQTT_SUPPORTED_FEATURE_EVENT_LOOP esp_event_loop_handle_t event_loop_handle; +#endif int task_stack; int task_prio; char *uri; @@ -226,11 +230,13 @@ esp_err_t esp_mqtt_set_config(esp_mqtt_client_handle_t client, const esp_mqtt_cl if (config->event_handle) { cfg->event_handle = config->event_handle; } else { +#ifdef MQTT_SUPPORTED_FEATURE_EVENT_LOOP esp_event_loop_args_t no_task_loop = { .queue_size = 1, .task_name = NULL, }; esp_event_loop_create(&no_task_loop, &cfg->event_loop_handle); +#endif } if (config->refresh_connection_after_ms) { @@ -564,8 +570,12 @@ static esp_err_t esp_mqtt_dispatch_event(esp_mqtt_client_handle_t client) if (client->config->event_handle) { return client->config->event_handle(&client->event); } else { +#ifdef MQTT_SUPPORTED_FEATURE_EVENT_LOOP esp_event_post_to(client->config->event_loop_handle, MQTT_EVENTS, client->event.event_id, &client->event, sizeof(client->event), portMAX_DELAY); return esp_event_loop_run(client->config->event_loop_handle, 0); +#else + return ESP_FAIL; +#endif } } @@ -1319,10 +1329,15 @@ esp_err_t esp_mqtt_client_register_event(esp_mqtt_client_handle_t client, esp_mq if (client == NULL) { return ESP_ERR_INVALID_ARG; } +#ifdef MQTT_SUPPORTED_FEATURE_EVENT_LOOP if (client->config->event_handle) { ESP_LOGW(TAG, "Registering event loop while event callback is not null, clearing callback"); client->config->event_handle = NULL; } return esp_event_handler_register_with(client->config->event_loop_handle, MQTT_EVENTS, event, event_handler, event_handler_arg); +#else + ESP_LOGE(TAG, "Registering event handler while event loop not available in IDF version %s", IDF_VER); + return ESP_FAIL; +#endif } From a4d1ef8d790247fdd9941ea67af16524b7b0793d Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 29 May 2019 16:11:14 +0200 Subject: [PATCH 55/56] ci: employ new static analysis utilities --- .clang-tidy-limits.yml | 32 -------------------------------- .gitlab-ci.yml | 19 +++++++++---------- static-analysis-rules.yml | 9 +++++++++ 3 files changed, 18 insertions(+), 42 deletions(-) delete mode 100644 .clang-tidy-limits.yml create mode 100644 static-analysis-rules.yml diff --git a/.clang-tidy-limits.yml b/.clang-tidy-limits.yml deleted file mode 100644 index f0b5377..0000000 --- a/.clang-tidy-limits.yml +++ /dev/null @@ -1,32 +0,0 @@ -limits: - "google-readability-braces-around-statements" : 30 - "readability-braces-around-statements" : 30 - "clang-diagnostic-error" : 10 - "readability-non-const-parameter" : 10 - "misc-misplaced-const" : 10 - "clang-diagnostic-typedef-redefinition" : 10 - "hicpp-braces-around-statements" : 10 - "clang-diagnostic-int-to-pointer-cast" : 10 - "hicpp-no-assembler" : 10 - "readability-else-after-return" : 10 - "readability-redundant-declaration" : 10 - "clang-diagnostic-unknown-attributes" : 10 - "misc-unused-parameters" : 10 - "readability-inconsistent-declaration-parameter-name" : 10 - "google-readability-todo" : 10 - "clang-diagnostic-macro-redefined" : 10 - "google-readability-casting" : 10 - "readability-inconsistent-declaration-parameter-name": 10 - "readability-named-parameter": 10 - "readability-container-size-empty": 10 - "modernize-use-using": 10 - "modernize-use-override": 10 - "readability-implicit-bool-cast": 10 - "modernize-use-default-member-init": 10 - "performance-unnecessary-value-param": 10 - "modernize-use-equals-default": 10 - "modernize-use-nullptr": 10 - -ignore: - - diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 393b499..aa87863 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -59,17 +59,16 @@ build_with_idf: - rm -rf .git - cp -r $CI_PROJECT_DIR/.git . - git reset --hard $CI_COMMIT_SHA - # build one example and capture compile commands/flags for static analysis + # capture compile commands/flags for static analysis - cd $IDF_PATH/examples/protocols/mqtt/tcp + - mkdir -p tidybuild && cd tidybuild + - cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .. + - mv $IDF_PATH/examples/protocols/mqtt/tcp/tidybuild $CI_PROJECT_DIR/tidybuild + # enable pedantic flags for compilation - export PEDANTIC_CFLAGS="-Werror -Werror=deprecated-declarations -Werror=unused-variable -Werror=unused-but-set-variable -Werror=unused-function" - export EXTRA_CFLAGS=${PEDANTIC_CFLAGS} && export EXTRA_CXXFLAGS=${EXTRA_CFLAGS} - - idf.py build - - mkdir -p tidybuild - - cd tidybuild - - cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .. - - cd $CI_PROJECT_DIR - - mv $IDF_PATH/examples/protocols/mqtt/tcp/tidybuild $CI_PROJECT_DIR/tidybuild # build other examples + - cd $IDF_PATH/examples/protocols/mqtt/tcp && idf.py build - cd $IDF_PATH/examples/protocols/mqtt/ssl && idf.py build - cd $IDF_PATH/examples/protocols/mqtt/ssl_mutual_auth && idf.py build - cd $IDF_PATH/examples/protocols/mqtt/ws && idf.py build @@ -101,9 +100,8 @@ clang_tidy_check: - git reset --hard $CI_COMMIT_SHA - mv $CI_PROJECT_DIR/tidybuild $IDF_PATH/examples/protocols/mqtt/tcp/tidybuild - cd $IDF_PATH/examples/protocols/mqtt/tcp/tidybuild - - git clone "${CI_REPORT_TOOLS}" - - cd static-analysis-utils - - ./generate_report.sh $CI_PROJECT_DIR/.clang-tidy-limits.yml $IDF_PATH/examples/protocols/mqtt/tcp/tidybuild/report $IDF_PATH/examples/protocols/mqtt/tcp/tidybuild/output.xml + - git clone $IDF_ANALYSIS_UTILS static_analysis_utils && cd static_analysis_utils + - ./generate_report.sh $CI_PROJECT_DIR/static-analysis-rules.yml $IDF_PATH/examples/protocols/mqtt/tcp/tidybuild/report $IDF_PATH/examples/protocols/mqtt/tcp/tidybuild/output.xml deploy_report: stage: deploy_report @@ -124,6 +122,7 @@ deploy_report: - ssh $DOCS_SERVER -x "cd $DOCS_PATH/clang-tidy && tar xzvf $GIT_VER.tar.gz && rm -f latest && ln -s $GIT_VER latest" # add link to view the report - echo "[static analysis][clang tidy] $CI_DOCKER_REGISTRY/static_analysis/esp-idf/clang-tidy/${GIT_VER}/index.html" + - test ! -e ${GIT_VER}/FAILED_RULES || { echo 'Failed static analysis rules!'; cat ${GIT_VER}/FAILED_RULES; exit 1; } push_master_to_github: stage: deploy diff --git a/static-analysis-rules.yml b/static-analysis-rules.yml new file mode 100644 index 0000000..bd36de8 --- /dev/null +++ b/static-analysis-rules.yml @@ -0,0 +1,9 @@ +limits: + "clang-analyzer-core.NullDereference" : 0 + "clang-analyzer-unix.Malloc" : 0 + +ignore: + - "llvm-header-guard" + - "llvm-include-order" + +skip: From 971bf47e14b86c78634f78cde9387a9a0f96d177 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Fri, 31 May 2019 15:33:12 +0200 Subject: [PATCH 56/56] outbox: suppress clang-tidy warning of using ptr after free (no possible for STAILQ structure), removed unnecessary print --- lib/mqtt_outbox.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/mqtt_outbox.c b/lib/mqtt_outbox.c index d92bfb6..8b1ff8d 100644 --- a/lib/mqtt_outbox.c +++ b/lib/mqtt_outbox.c @@ -152,7 +152,6 @@ int outbox_delete_expired(outbox_handle_t outbox, int current_tick, int timeout) STAILQ_FOREACH_SAFE(item, outbox, next, tmp) { if (current_tick - item->tick > timeout) { STAILQ_REMOVE(outbox, item, outbox_item, next); - printf("free message\n"); free(item->buffer); free(item); deleted_items ++; @@ -167,7 +166,9 @@ int outbox_get_size(outbox_handle_t outbox) int siz = 0; outbox_item_handle_t item; STAILQ_FOREACH(item, outbox, next) { - siz += item->len; + // Suppressing "use after free" warning as this could happen only if queue is in inconsistent state + // which never happens if STAILQ interface used + siz += item->len; // NOLINT(clang-analyzer-unix.Malloc) } return siz; }