From 324ed6be76d465782a27fddc577b9af03eea0e59 Mon Sep 17 00:00:00 2001 From: Christian von Arnim Date: Wed, 1 May 2019 09:56:55 +0200 Subject: [PATCH 01/25] Fix password input when MAX_BUFFER_LEN is not 1024 in mosquitto_passwd.c Signed-off-by: Christian von Arnim --- src/mosquitto_passwd.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/mosquitto_passwd.c b/src/mosquitto_passwd.c index afe3e199..00e048fb 100644 --- a/src/mosquitto_passwd.c +++ b/src/mosquitto_passwd.c @@ -339,13 +339,15 @@ int gets_quiet(char *s, int len) #endif } -int get_password(char *password, int len) +int get_password(char *password, size_t len) { char pw1[MAX_BUFFER_LEN], pw2[MAX_BUFFER_LEN]; + size_t minLen; + minLen = len < MAX_BUFFER_LEN ? len : MAX_BUFFER_LEN; printf("Password: "); fflush(stdout); - if(gets_quiet(pw1, MAX_BUFFER_LEN)){ + if(gets_quiet(pw1, minLen)){ fprintf(stderr, "Error: Empty password.\n"); return 1; } @@ -353,7 +355,7 @@ int get_password(char *password, int len) printf("Reenter password: "); fflush(stdout); - if(gets_quiet(pw2, MAX_BUFFER_LEN)){ + if(gets_quiet(pw2, minLen)){ fprintf(stderr, "Error: Empty password.\n"); return 1; } @@ -364,7 +366,7 @@ int get_password(char *password, int len) return 1; } - strncpy(password, pw1, len); + strncpy(password, pw1, minLen); return 0; } @@ -526,7 +528,7 @@ int main(int argc, char *argv[]) #endif if(create_new){ - rc = get_password(password, 1024); + rc = get_password(password, MAX_BUFFER_LEN); if(rc){ free(password_file); return rc; @@ -581,7 +583,7 @@ int main(int argc, char *argv[]) /* Update password for individual user */ rc = update_pwuser(fptr, ftmp, username, password_cmd); }else{ - rc = get_password(password, 1024); + rc = get_password(password, MAX_BUFFER_LEN); if(rc){ fclose(fptr); fclose(ftmp); From d17d7c9229becead17c5cdcf597a942899d0b63c Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 25 Jun 2019 17:01:41 +0100 Subject: [PATCH 02/25] Fix persistent clients being incorrectly expired on Raspberry Pis. Closes #1272. Thanks to BowenMarmot and addendumE. --- ChangeLog.txt | 7 +++++++ src/session_expiry.c | 4 +++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 6b3f8716..5282e1dc 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,10 @@ +1.6.4 - 2019xxxx +================ + +Broker: +- Fix persistent clients being incorrectly expired on Raspberry Pis. + Closes #1272. + 1.6.3 - 20190618 ================ diff --git a/src/session_expiry.c b/src/session_expiry.c index 057e032c..68540a71 100644 --- a/src/session_expiry.c +++ b/src/session_expiry.c @@ -94,7 +94,9 @@ void session_expiry__check(struct mosquitto_db *db, time_t now) last_check = now; DL_FOREACH_SAFE(expiry_list, item, tmp){ - if(item->context->session_expiry_time < now){ + if(item->context->session_expiry_interval != UINT32_MAX + && item->context->session_expiry_time < now){ + context = item->context; session_expiry__remove(context); From 2b2afc93bce07f39d1eb1bc7575cb1f5fedd83a8 Mon Sep 17 00:00:00 2001 From: Roger Light Date: Wed, 3 Jul 2019 09:50:59 +0100 Subject: [PATCH 03/25] Allow other apps access to log file on Windows. This change means that users with the appropriate security permissions can open the log file for reading at the same time that it is being written. Closes #515. --- ChangeLog.txt | 3 +++ lib/util_mosq.c | 2 +- readme-windows.txt | 8 ++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 5282e1dc..53a3dc13 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -4,6 +4,9 @@ Broker: - Fix persistent clients being incorrectly expired on Raspberry Pis. Closes #1272. +- Windows: Allow other applications access to the log file when running. + Closes #515. + 1.6.3 - 20190618 ================ diff --git a/lib/util_mosq.c b/lib/util_mosq.c index 5e1065e7..65fc2215 100644 --- a/lib/util_mosq.c +++ b/lib/util_mosq.c @@ -248,7 +248,7 @@ FILE *mosquitto__fopen(const char *path, const char *mode, bool restrict_read) sec.bInheritHandle = FALSE; sec.lpSecurityDescriptor = &sd; - hfile = CreateFile(buf, GENERIC_READ | GENERIC_WRITE, 0, + hfile = CreateFile(buf, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, &sec, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, diff --git a/readme-windows.txt b/readme-windows.txt index 9325a4c9..7bf0d954 100644 --- a/readme-windows.txt +++ b/readme-windows.txt @@ -61,3 +61,11 @@ command line as follows: C:\Program Files\mosquitto\mosquitto install C:\Program Files\mosquitto\mosquitto uninstall + +Logging +------- + +If you use `log_dest file ...` in your configuration, the log file will be +created with security permissions for the current user only. If running as a +service, this means the SYSTEM user. You will only be able to view the log file +if you add permissions for yourself or whatever user you wish to view the logs. From 9bb9b6e7219b96bb633d85d0d5d1048f073822bc Mon Sep 17 00:00:00 2001 From: YangHau Date: Fri, 12 Jul 2019 16:38:40 +0800 Subject: [PATCH 04/25] Remove redundant initialization in clients the `memset(&cfg, 0, sizeof(struct mosq_config));` already exsits in `client_config_load()`'s `init_config()` function call. So calling it in main function is totally unnecessary. Signed-off-by: YangHau --- client/pub_client.c | 1 - client/rr_client.c | 2 -- client/sub_client.c | 2 -- 3 files changed, 5 deletions(-) diff --git a/client/pub_client.c b/client/pub_client.c index 31740391..62c79921 100644 --- a/client/pub_client.c +++ b/client/pub_client.c @@ -443,7 +443,6 @@ int main(int argc, char *argv[]) if(pub_shared_init()) return 1; - memset(&cfg, 0, sizeof(struct mosq_config)); rc = client_config_load(&cfg, CLIENT_PUB, argc, argv); if(rc){ if(rc == 2){ diff --git a/client/rr_client.c b/client/rr_client.c index 6444c28e..02801e82 100644 --- a/client/rr_client.c +++ b/client/rr_client.c @@ -252,8 +252,6 @@ int main(int argc, char *argv[]) #ifndef WIN32 struct sigaction sigact; #endif - - memset(&cfg, 0, sizeof(struct mosq_config)); mosquitto_lib_init(); diff --git a/client/sub_client.c b/client/sub_client.c index f57a48cc..a279b249 100644 --- a/client/sub_client.c +++ b/client/sub_client.c @@ -278,8 +278,6 @@ int main(int argc, char *argv[]) #ifndef WIN32 struct sigaction sigact; #endif - - memset(&cfg, 0, sizeof(struct mosq_config)); mosquitto_lib_init(); From 3ad780839d4035b52d1bdd06f7b6605dcca54e37 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 24 Jul 2019 11:13:07 +0100 Subject: [PATCH 05/25] Fix MQTT v5 sub opts being set for v3 subs. Closes #1353. Thanks to Ben Barbour. --- ChangeLog.txt | 4 ++++ lib/actions.c | 3 +++ lib/mosquitto.h | 5 +++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 53a3dc13..33a6cf3d 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -7,6 +7,10 @@ Broker: - Windows: Allow other applications access to the log file when running. Closes #515. +Client library: +- Fix MQTT v5 subscription options being incorrectly set for MQTT v3 + subscriptions. Closes #1353. + 1.6.3 - 20190618 ================ diff --git a/lib/actions.c b/lib/actions.c index a5bf673f..b17c560f 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -200,6 +200,9 @@ int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count return MOSQ_ERR_OVERSIZE_PACKET; } } + if(mosq->protocol == mosq_p_mqtt311 || mosq->protocol == mosq_p_mqtt31){ + options = 0; + } return send__subscribe(mosq, mid, sub_count, sub, qos|options, outgoing_properties); } diff --git a/lib/mosquitto.h b/lib/mosquitto.h index 09bba66e..d939bfd2 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -921,8 +921,9 @@ libmosq_EXPORT int mosquitto_subscribe_v5(struct mosquitto *mosq, int *mid, cons * familiar with this, just think of it as a safer "char **", * equivalent to "const char *" for a simple string pointer. * qos - the requested Quality of Service for each subscription. - * options - options to apply to this subscription, OR'd together. Set to 0 to - * use the default options, otherwise choose from the list: + * options - options to apply to this subscription, OR'd together. This + * argument is not used for MQTT v3 susbcriptions. Set to 0 to use + * the default options, otherwise choose from the list: * MQTT_SUB_OPT_NO_LOCAL - with this option set, if this client * publishes to a topic to which it is subscribed, the * broker will not publish the message back to the From b807daed2867bc0bfbd21213a9e4736ab7811f29 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 24 Jul 2019 12:08:43 +0100 Subject: [PATCH 06/25] Fix error codes not being returned when mosquitto_pub exits. Closes #1354. Thanks to Ben Barbour. --- ChangeLog.txt | 4 ++++ client/pub_client.c | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 33a6cf3d..c6e86deb 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -11,6 +11,10 @@ Client library: - Fix MQTT v5 subscription options being incorrectly set for MQTT v3 subscriptions. Closes #1353. +Clients: +- mosquitto_pub: fix error codes not being returned when mosquitto_pub exits. + Closes #1354. + 1.6.3 - 20190618 ================ diff --git a/client/pub_client.c b/client/pub_client.c index 31740391..fb25b451 100644 --- a/client/pub_client.c +++ b/client/pub_client.c @@ -103,7 +103,9 @@ void my_disconnect_callback(struct mosquitto *mosq, void *obj, int rc, const mos UNUSED(rc); UNUSED(properties); - status = STATUS_DISCONNECTED; + if(rc == 0){ + status = STATUS_DISCONNECTED; + } } int my_publish(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, void *payload, int qos, bool retain) From b9bd0bedadf6115c050bfea50c2e84824e966264 Mon Sep 17 00:00:00 2001 From: Lucas Ramage Date: Thu, 25 Jul 2019 12:34:33 -0400 Subject: [PATCH 07/25] Fix typos for READMEs in Docker directory (#1340) * Fix typo --- docker/1.5/README.md | 2 +- docker/1.6/README.md | 2 +- docker/local/README.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/1.5/README.md b/docker/1.5/README.md index 27b05904..ce91cd03 100644 --- a/docker/1.5/README.md +++ b/docker/1.5/README.md @@ -15,7 +15,7 @@ Two docker volumes have been created in the image to be used for persistent stor ## User/Group -The image runs mosqutto under the mosquitto user and group, which are created +The image runs mosquitto under the mosquitto user and group, which are created with a uid and gid of 1883. ## Configuration diff --git a/docker/1.6/README.md b/docker/1.6/README.md index 27b05904..ce91cd03 100644 --- a/docker/1.6/README.md +++ b/docker/1.6/README.md @@ -15,7 +15,7 @@ Two docker volumes have been created in the image to be used for persistent stor ## User/Group -The image runs mosqutto under the mosquitto user and group, which are created +The image runs mosquitto under the mosquitto user and group, which are created with a uid and gid of 1883. ## Configuration diff --git a/docker/local/README.md b/docker/local/README.md index eb830604..f11086aa 100644 --- a/docker/local/README.md +++ b/docker/local/README.md @@ -17,7 +17,7 @@ Two docker volumes have been created in the image to be used for persistent stor ## User/Group -The image runs mosqutto under the mosquitto user and group, which are created +The image runs mosquitto under the mosquitto user and group, which are created with a uid and gid of 1883. ## Configuration From e3271e0c994c4f0c88e749d0eedda12d501ef583 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 25 Jul 2019 21:08:00 +0100 Subject: [PATCH 08/25] Don't define _GNU_SOURCE where already defined. Closes #1357. --- config.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/config.h b/config.h index f717d00c..5cce39ee 100644 --- a/config.h +++ b/config.h @@ -16,7 +16,10 @@ # define _POSIX_C_SOURCE 200809L #endif -#define _GNU_SOURCE + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif #define OPENSSL_LOAD_CONF From 552059e17db007e94e9ddd06bb7a110219853be1 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 30 Jul 2019 15:01:12 +0100 Subject: [PATCH 09/25] Pedantic test fixes from failgrind. --- test/unit/property_user_read.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/test/unit/property_user_read.c b/test/unit/property_user_read.c index d458eb7a..902296bc 100644 --- a/test/unit/property_user_read.c +++ b/test/unit/property_user_read.c @@ -451,14 +451,19 @@ static void missing_read_helper(mosquitto_property *proplist) CU_ASSERT_EQUAL(int32_value, 1800); /* MISSING */ + value = NULL; prop = mosquitto_property_read_string(proplist, MQTT_PROP_CONTENT_TYPE, &value, false); CU_ASSERT_PTR_NULL(prop); /* NOT MISSING */ + value = NULL; prop = mosquitto_property_read_string(proplist, MQTT_PROP_RESPONSE_TOPIC, &value, false); CU_ASSERT_PTR_NOT_NULL(prop); - CU_ASSERT_STRING_EQUAL(value, "response/topic"); - free(value); + CU_ASSERT_PTR_NOT_NULL(value); + if(value){ + CU_ASSERT_STRING_EQUAL(value, "response/topic"); + free(value); + } /* MISSING */ prop = mosquitto_property_read_binary(proplist, MQTT_PROP_CORRELATION_DATA, (void **)&value, &length, false); @@ -474,21 +479,29 @@ static void missing_read_helper(mosquitto_property *proplist) CU_ASSERT_PTR_NULL(prop); /* NOT MISSING */ + value = NULL; prop = mosquitto_property_read_string(proplist, MQTT_PROP_SERVER_REFERENCE, &value, false); CU_ASSERT_PTR_NOT_NULL(prop); - CU_ASSERT_STRING_EQUAL(value, "localhost"); - free(value); + CU_ASSERT_PTR_NOT_NULL(value); + if(value){ + CU_ASSERT_STRING_EQUAL(value, "localhost"); + free(value); + } /* MISSING */ prop = mosquitto_property_read_int32(proplist, MQTT_PROP_SESSION_EXPIRY_INTERVAL, &int32_value, false); CU_ASSERT_PTR_NULL(prop); /* NOT MISSING */ + value = NULL; prop = mosquitto_property_read_binary(proplist, MQTT_PROP_AUTHENTICATION_DATA, (void **)&value, &length, false); CU_ASSERT_PTR_NOT_NULL(prop); - CU_ASSERT_NSTRING_EQUAL(value, "password", strlen("password")); - CU_ASSERT_EQUAL(length, strlen("password")); - free(value); + CU_ASSERT_PTR_NOT_NULL(value); + if(value){ + CU_ASSERT_NSTRING_EQUAL(value, "password", strlen("password")); + CU_ASSERT_EQUAL(length, strlen("password")); + free(value); + } /* MISSING */ prop = mosquitto_property_read_int16(proplist, MQTT_PROP_SERVER_KEEP_ALIVE, &int16_value, false); From 46d12086c9bc99fe2a3f4ad705a8a42de44d6914 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 30 Jul 2019 15:06:55 +0100 Subject: [PATCH 10/25] Set sock to invalid after closing. --- lib/net_mosq.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/net_mosq.c b/lib/net_mosq.c index f207e32a..ea04d1ab 100644 --- a/lib/net_mosq.c +++ b/lib/net_mosq.c @@ -607,12 +607,14 @@ static int net__init_ssl_ctx(struct mosquitto *mosq) if(!engine){ log__printf(mosq, MOSQ_LOG_ERR, "Error loading %s engine\n", mosq->tls_engine); COMPAT_CLOSE(mosq->sock); + mosq->sock = INVALID_SOCKET; return MOSQ_ERR_TLS; } if(!ENGINE_init(engine)){ log__printf(mosq, MOSQ_LOG_ERR, "Failed engine initialisation\n"); ENGINE_free(engine); COMPAT_CLOSE(mosq->sock); + mosq->sock = INVALID_SOCKET; return MOSQ_ERR_TLS; } ENGINE_set_default(engine, ENGINE_METHOD_ALL); @@ -698,6 +700,7 @@ static int net__init_ssl_ctx(struct mosquitto *mosq) log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to set engine secret mode sha1"); ENGINE_FINISH(engine); COMPAT_CLOSE(mosq->sock); + mosq->sock = INVALID_SOCKET; net__print_ssl_error(mosq); return MOSQ_ERR_TLS; } @@ -705,6 +708,7 @@ static int net__init_ssl_ctx(struct mosquitto *mosq) log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to set engine pin"); ENGINE_FINISH(engine); COMPAT_CLOSE(mosq->sock); + mosq->sock = INVALID_SOCKET; net__print_ssl_error(mosq); return MOSQ_ERR_TLS; } @@ -715,6 +719,7 @@ static int net__init_ssl_ctx(struct mosquitto *mosq) log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load engine private key file \"%s\".", mosq->tls_keyfile); ENGINE_FINISH(engine); COMPAT_CLOSE(mosq->sock); + mosq->sock = INVALID_SOCKET; net__print_ssl_error(mosq); return MOSQ_ERR_TLS; } @@ -722,6 +727,7 @@ static int net__init_ssl_ctx(struct mosquitto *mosq) log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to use engine private key file \"%s\".", mosq->tls_keyfile); ENGINE_FINISH(engine); COMPAT_CLOSE(mosq->sock); + mosq->sock = INVALID_SOCKET; net__print_ssl_error(mosq); return MOSQ_ERR_TLS; } @@ -948,12 +954,14 @@ int net__socket_nonblock(mosq_sock_t *sock) if(fcntl(*sock, F_SETFL, opt | O_NONBLOCK) == -1){ /* If either fcntl fails, don't want to allow this client to connect. */ COMPAT_CLOSE(*sock); + *sock = INVALID_SOCKET; return MOSQ_ERR_ERRNO; } #else unsigned long opt = 1; if(ioctlsocket(*sock, FIONBIO, &opt)){ COMPAT_CLOSE(*sock); + mosq->sock = INVALID_SOCKET; return MOSQ_ERR_ERRNO; } #endif From c32715d383f92255c53072c4824fa367a2b7fd67 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 30 Jul 2019 15:09:53 +0100 Subject: [PATCH 11/25] Set *name to NULL on failure. --- lib/property_mosq.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/property_mosq.c b/lib/property_mosq.c index 76158e58..d3854cff 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -1064,7 +1064,10 @@ const mosquitto_property *mosquitto_property_read_string_pair(const mosquitto_pr if(value){ *value = calloc(1, p->value.s.len+1); if(!(*value)){ - if(name) free(*name); + if(name){ + free(*name); + *name = NULL; + } return NULL; } memcpy(*value, p->value.s.v, p->value.s.len); From 42237c023929f5052acc23490edcf95853e2a25c Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 30 Jul 2019 18:42:31 +0100 Subject: [PATCH 12/25] Make behaviour of `mosquitto_connect[_async]()` consistent. `mosquitto_connect_async()` is now consistent with `mosquitto_connect()` when connecting to a non-existent server. Closes #1345. Thanks to Mohammad Reza. --- ChangeLog.txt | 3 +++ lib/connect.c | 33 ++++++++++----------------------- lib/packet_mosq.c | 32 ++++++++++++++++++++++++++++++++ lib/packet_mosq.h | 1 + 4 files changed, 46 insertions(+), 23 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index c6e86deb..3c4898a1 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -10,6 +10,9 @@ Broker: Client library: - Fix MQTT v5 subscription options being incorrectly set for MQTT v3 subscriptions. Closes #1353. +- Make behaviour of `mosquitto_connect_async()` consistent with + `mosquitto_connect()` when connecting to a non-existent server. + Closes #1345. Clients: - mosquitto_pub: fix error codes not being returned when mosquitto_pub exits. diff --git a/lib/connect.c b/lib/connect.c index 7543d4af..8559cd72 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -163,7 +163,6 @@ static int mosquitto__reconnect(struct mosquitto *mosq, bool blocking, const mos const mosquitto_property *outgoing_properties = NULL; mosquitto_property local_property; int rc; - struct mosquitto__packet *packet; if(!mosq) return MOSQ_ERR_INVAL; if(!mosq->host || mosq->port <= 0) return MOSQ_ERR_INVAL; if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED; @@ -201,27 +200,7 @@ static int mosquitto__reconnect(struct mosquitto *mosq, bool blocking, const mos packet__cleanup(&mosq->in_packet); - pthread_mutex_lock(&mosq->current_out_packet_mutex); - pthread_mutex_lock(&mosq->out_packet_mutex); - - if(mosq->out_packet && !mosq->current_out_packet){ - mosq->current_out_packet = mosq->out_packet; - mosq->out_packet = mosq->out_packet->next; - } - - while(mosq->current_out_packet){ - packet = mosq->current_out_packet; - /* Free data and reset values */ - mosq->current_out_packet = mosq->out_packet; - if(mosq->out_packet){ - mosq->out_packet = mosq->out_packet->next; - } - - packet__cleanup(packet); - mosquitto__free(packet); - } - pthread_mutex_unlock(&mosq->out_packet_mutex); - pthread_mutex_unlock(&mosq->current_out_packet_mutex); + packet__cleanup_all(mosq); message__reconnect_reset(mosq); @@ -250,7 +229,15 @@ static int mosquitto__reconnect(struct mosquitto *mosq, bool blocking, const mos }else #endif { - return send__connect(mosq, mosq->keepalive, mosq->clean_start, outgoing_properties); + rc = send__connect(mosq, mosq->keepalive, mosq->clean_start, outgoing_properties); + if(rc){ + packet__cleanup_all(mosq); + net__socket_close(mosq); + pthread_mutex_lock(&mosq->state_mutex); + mosq->state = mosq_cs_new; + pthread_mutex_unlock(&mosq->state_mutex); + } + return rc; } } diff --git a/lib/packet_mosq.c b/lib/packet_mosq.c index 0f7af742..22df79e5 100644 --- a/lib/packet_mosq.c +++ b/lib/packet_mosq.c @@ -98,6 +98,38 @@ void packet__cleanup(struct mosquitto__packet *packet) packet->pos = 0; } + +void packet__cleanup_all(struct mosquitto *mosq) +{ + struct mosquitto__packet *packet; + + pthread_mutex_lock(&mosq->current_out_packet_mutex); + pthread_mutex_lock(&mosq->out_packet_mutex); + + /* Out packet cleanup */ + if(mosq->out_packet && !mosq->current_out_packet){ + mosq->current_out_packet = mosq->out_packet; + mosq->out_packet = mosq->out_packet->next; + } + while(mosq->current_out_packet){ + packet = mosq->current_out_packet; + /* Free data and reset values */ + mosq->current_out_packet = mosq->out_packet; + if(mosq->out_packet){ + mosq->out_packet = mosq->out_packet->next; + } + + packet__cleanup(packet); + mosquitto__free(packet); + } + + packet__cleanup(&mosq->in_packet); + + pthread_mutex_unlock(&mosq->out_packet_mutex); + pthread_mutex_unlock(&mosq->current_out_packet_mutex); +} + + int packet__queue(struct mosquitto *mosq, struct mosquitto__packet *packet) { #ifndef WITH_BROKER diff --git a/lib/packet_mosq.h b/lib/packet_mosq.h index 5967f094..01b7d148 100644 --- a/lib/packet_mosq.h +++ b/lib/packet_mosq.h @@ -25,6 +25,7 @@ struct mosquitto_db; int packet__alloc(struct mosquitto__packet *packet); void packet__cleanup(struct mosquitto__packet *packet); +void packet__cleanup_all(struct mosquitto *mosq); int packet__queue(struct mosquitto *mosq, struct mosquitto__packet *packet); int packet__check_oversize(struct mosquitto *mosq, uint32_t remaining_length); From f21ccc362b4a439368c82ed633c9f71d2d81a3cd Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 30 Jul 2019 18:46:52 +0100 Subject: [PATCH 13/25] Fix mosquitto_string_option(, MOSQ_OPT_TLS_KEYFORM, ) return value `mosquitto_string_option(mosq, MOSQ_OPT_TLS_KEYFORM, ...)` was incorrectly returning `MOSQ_ERR_INVAL` with valid input. This has been fixed. Closes #1360. Thanks to Michael Dombrowski. --- ChangeLog.txt | 3 +++ lib/options.c | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 3c4898a1..6aa81097 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -13,6 +13,9 @@ Client library: - Make behaviour of `mosquitto_connect_async()` consistent with `mosquitto_connect()` when connecting to a non-existent server. Closes #1345. +- `mosquitto_string_option(mosq, MOSQ_OPT_TLS_KEYFORM, ...)` was incorrectly + returning `MOSQ_ERR_INVAL` with valid input. This has been fixed. + Closes #1360. Clients: - mosquitto_pub: fix error codes not being returned when mosquitto_pub exits. diff --git a/lib/options.c b/lib/options.c index 7bab7366..483edbb2 100644 --- a/lib/options.c +++ b/lib/options.c @@ -289,6 +289,7 @@ int mosquitto_string_option(struct mosquitto *mosq, enum mosq_opt_t option, cons }else{ return MOSQ_ERR_INVAL; } + return MOSQ_ERR_SUCCESS; #else return MOSQ_ERR_NOT_SUPPORTED; #endif @@ -322,8 +323,6 @@ int mosquitto_string_option(struct mosquitto *mosq, enum mosq_opt_t option, cons default: return MOSQ_ERR_INVAL; } - - return MOSQ_ERR_INVAL; } From 696a9b8019995043c96a18f5968a06c6cc732726 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 30 Jul 2019 23:25:12 +0100 Subject: [PATCH 14/25] Fix incomgin QoS 2 with max_inflight_messages set to 1. Closes #1332. Thanks to xmas79. --- ChangeLog.txt | 2 + src/handle_publish.c | 1 - test/broker/03-publish-qos1-max-inflight.py | 46 +++++++++++++++++++ test/broker/03-publish-qos2-max-inflight.py | 49 +++++++++++++++++++++ test/broker/Makefile | 1 + test/broker/test.py | 1 + 6 files changed, 99 insertions(+), 1 deletion(-) create mode 100755 test/broker/03-publish-qos1-max-inflight.py create mode 100755 test/broker/03-publish-qos2-max-inflight.py diff --git a/ChangeLog.txt b/ChangeLog.txt index 6aa81097..2c55c4b1 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -6,6 +6,8 @@ Broker: Closes #1272. - Windows: Allow other applications access to the log file when running. Closes #515. +- Fix incoming QoS 2 messages being blocked when `max_inflight_messages` was + set to 1. Closes #1332. Client library: - Fix MQTT v5 subscription options being incorrectly set for MQTT v3 diff --git a/src/handle_publish.c b/src/handle_publish.c index 8b76fd5e..a13160fa 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -331,7 +331,6 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) break; case 2: if(dup == 0){ - util__decrement_receive_quota(context); res = db__message_insert(db, context, mid, mosq_md_in, qos, retain, stored, NULL); }else{ res = 0; diff --git a/test/broker/03-publish-qos1-max-inflight.py b/test/broker/03-publish-qos1-max-inflight.py new file mode 100755 index 00000000..6d18cad8 --- /dev/null +++ b/test/broker/03-publish-qos1-max-inflight.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 + +# Test whether a PUBLISH to a topic with QoS 1 results in the correct packet flow. +# With max_inflight_messages set to 1 + +from mosq_test_helper import * + +def write_config(filename, port): + with open(filename, 'w') as f: + f.write("port %d\n" % (port)) + f.write("max_inflight_messages 1\n") + +port = mosq_test.get_port() +conf_file = os.path.basename(__file__).replace('.py', '.conf') +write_config(conf_file, port) + + +rc = 1 +keepalive = 60 +connect_packet = mosq_test.gen_connect("pub-qos1-test", keepalive=keepalive) +connack_packet = mosq_test.gen_connack(rc=0) + +mid = 311 +publish_packet = mosq_test.gen_publish("pub/qos1/test", qos=1, mid=mid, payload="message") +puback_packet = mosq_test.gen_puback(mid) + +port = mosq_test.get_port() +broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port) + +try: + sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port, timeout=10) + mosq_test.do_send_receive(sock, publish_packet, puback_packet, "puback") + + rc = 0 + + sock.close() +finally: + os.remove(conf_file) + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde.decode('utf-8')) + +exit(rc) + diff --git a/test/broker/03-publish-qos2-max-inflight.py b/test/broker/03-publish-qos2-max-inflight.py new file mode 100755 index 00000000..3b4f608c --- /dev/null +++ b/test/broker/03-publish-qos2-max-inflight.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 + +# Test whether a PUBLISH to a topic with QoS 2 results in the correct packet flow. +# With max_inflight_messages set to 1 + +from mosq_test_helper import * + +def write_config(filename, port): + with open(filename, 'w') as f: + f.write("port %d\n" % (port)) + f.write("max_inflight_messages 1\n") + +port = mosq_test.get_port() +conf_file = os.path.basename(__file__).replace('.py', '.conf') +write_config(conf_file, port) + + +rc = 1 +keepalive = 60 +connect_packet = mosq_test.gen_connect("pub-qos2-test", keepalive=keepalive) +connack_packet = mosq_test.gen_connack(rc=0) + +mid = 312 +publish_packet = mosq_test.gen_publish("pub/qos2/test", qos=2, mid=mid, payload="message") +pubrec_packet = mosq_test.gen_pubrec(mid) +pubrel_packet = mosq_test.gen_pubrel(mid) +pubcomp_packet = mosq_test.gen_pubcomp(mid) + +port = mosq_test.get_port() +broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port) + +try: + sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port, timeout=10) + mosq_test.do_send_receive(sock, publish_packet, pubrec_packet, "pubrec") + mosq_test.do_send_receive(sock, pubrel_packet, pubcomp_packet, "pubcomp") + + rc = 0 + + sock.close() +finally: + os.remove(conf_file) + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde.decode('utf-8')) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index ba91fb8a..3b4ee95b 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -101,6 +101,7 @@ endif ./03-publish-qos1-no-subscribers-v5.py ./03-publish-qos1-retain-disabled.py ./03-publish-qos1.py + ./03-publish-qos2-max-inflight.py ./03-publish-qos2.py 04 : diff --git a/test/broker/test.py b/test/broker/test.py index 497e3627..3d2e3ecd 100755 --- a/test/broker/test.py +++ b/test/broker/test.py @@ -79,6 +79,7 @@ tests = [ (1, './03-publish-qos1-no-subscribers-v5.py'), (1, './03-publish-qos1-retain-disabled.py'), (1, './03-publish-qos1.py'), + (1, './03-publish-qos2-max-inflight.py'), (1, './03-publish-qos2.py'), (1, './04-retain-check-source-persist.py'), From b3f3513b353312e7c1fbcfc54bb0e501e10f5f43 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 31 Jul 2019 11:46:34 +0100 Subject: [PATCH 15/25] Index update. --- www/pages/index.html | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/www/pages/index.html b/www/pages/index.html index 87b07fce..042014f5 100644 --- a/www/pages/index.html +++ b/www/pages/index.html @@ -27,10 +27,8 @@ and mosquitto_sub command line MQTT clients.

Mosquitto is part of the Eclipse - Foundation and is an iot.eclipse.org project.

- - + Foundation, is an iot.eclipse.org + project and is sponsored by cedalo.com.


From efc8ed39afa8c7a684bbca692fe307c89663cc0f Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 31 Jul 2019 18:37:59 +0100 Subject: [PATCH 16/25] Fix incoming msgs not being removed when there are no subs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix incoming messages not being removed for a client if the topic being published to does not have any subscribers. Closes #1322. Thanks to Yannic Schröder. --- ChangeLog.txt | 2 + lib/handle_pubrel.c | 6 +- src/database.c | 13 ++- test/broker/02-subpub-qos2-1322.py | 137 +++++++++++++++++++++++++++++ test/broker/Makefile | 1 + test/broker/test.py | 1 + 6 files changed, 154 insertions(+), 6 deletions(-) create mode 100755 test/broker/02-subpub-qos2-1322.py diff --git a/ChangeLog.txt b/ChangeLog.txt index 2c55c4b1..fb736c96 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -8,6 +8,8 @@ Broker: Closes #515. - Fix incoming QoS 2 messages being blocked when `max_inflight_messages` was set to 1. Closes #1332. +- Fix incoming messages not being removed for a client if the topic being + published to does not have any subscribers. Closes #1322. Client library: - Fix MQTT v5 subscription options being incorrectly set for MQTT v3 diff --git a/lib/handle_pubrel.c b/lib/handle_pubrel.c index d4a90652..209a3e0d 100644 --- a/lib/handle_pubrel.c +++ b/lib/handle_pubrel.c @@ -78,11 +78,11 @@ int handle__pubrel(struct mosquitto_db *db, struct mosquitto *mosq) mosquitto_property_free_all(&properties); rc = db__message_release_incoming(db, mosq, mid); - if(rc == MOSQ_ERR_PROTOCOL){ - return rc; - }else if(rc != MOSQ_ERR_SUCCESS){ + if(rc == MOSQ_ERR_NOT_FOUND){ /* Message not found. Still send a PUBCOMP anyway because this could be * due to a repeated PUBREL after a client has reconnected. */ + }else if(rc != MOSQ_ERR_SUCCESS){ + return rc; } rc = send__pubcomp(mosq, mid); diff --git a/src/database.c b/src/database.c index 87daf68c..715c1690 100644 --- a/src/database.c +++ b/src/database.c @@ -893,6 +893,7 @@ int db__message_release_incoming(struct mosquitto_db *db, struct mosquitto *cont char *source_id; int msg_index = 0; bool deleted = false; + int rc; if(!context) return MOSQ_ERR_INVAL; @@ -910,11 +911,17 @@ int db__message_release_incoming(struct mosquitto_db *db, struct mosquitto *cont * denied/dropped and is being processed so the client doesn't * keep resending it. That means we don't send it to other * clients. */ - if(!topic || !sub__messages_queue(db, source_id, topic, 2, retain, &tail->store)){ + if(!topic){ db__message_remove(db, &context->msgs_in, tail); deleted = true; }else{ - return 1; + rc = sub__messages_queue(db, source_id, topic, 2, retain, &tail->store); + if(rc == MOSQ_ERR_SUCCESS || rc == MOSQ_ERR_NO_SUBSCRIBERS){ + db__message_remove(db, &context->msgs_in, tail); + deleted = true; + }else{ + return 1; + } } } } @@ -936,7 +943,7 @@ int db__message_release_incoming(struct mosquitto_db *db, struct mosquitto *cont if(deleted){ return MOSQ_ERR_SUCCESS; }else{ - return 1; + return MOSQ_ERR_NOT_FOUND; } } diff --git a/test/broker/02-subpub-qos2-1322.py b/test/broker/02-subpub-qos2-1322.py new file mode 100755 index 00000000..00720be5 --- /dev/null +++ b/test/broker/02-subpub-qos2-1322.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python3 + +# Test for issue 1322: + +## restart mosquitto +#sudo systemctl restart mosquitto.service +# +## listen on topic1 +#mosquitto_sub -t "topic1" +# +## publish to topic1 without clean session +#mosquitto_pub -t "topic1" -q 2 -c --id "foobar" -m "message1" +## message1 on topic1 is received as expected +# +## publish to topic2 without clean session +## IMPORTANT: no subscription to this topic is present on broker! +#mosquitto_pub -t "topic2" -q 2 -c --id "foobar" -m "message2" +## this goes nowhere, as no subscriber present +# +## publish to topic1 without clean session +#mosquitto_pub -t "topic1" -q 2 -c --id "foobar" -m "message3" +## message3 on topic1 IS NOT RECEIVED +# +## listen on topic2 +#mosquitto_sub -t "topic2" +# +## publish to topic1 without clean session +#mosquitto_pub -t "topic1" -q 2 -c --id "foobar" -m "message4" +## message2 on topic2 is received incorrectly +# +## publish to topic1 without clean session +#mosquitto_pub -t "topic1" -q 2 -c --id "foobar" -m "message5" +## message5 on topic1 is received as expected (message4 was dropped) + + + +from mosq_test_helper import * + +rc = 1 +keepalive = 60 +pub_connect_packet = mosq_test.gen_connect("pub", keepalive=keepalive, clean_session=False) +pub_connack1_packet = mosq_test.gen_connack(rc=0) +pub_connack2_packet = mosq_test.gen_connack(rc=0, flags=1) + +sub1_connect_packet = mosq_test.gen_connect("sub1", keepalive=keepalive) +sub1_connack_packet = mosq_test.gen_connack(rc=0) + +sub2_connect_packet = mosq_test.gen_connect("sub2", keepalive=keepalive) +sub2_connack_packet = mosq_test.gen_connack(rc=0) + +mid = 1 +subscribe1_packet = mosq_test.gen_subscribe(mid, "topic1", 0) +suback1_packet = mosq_test.gen_suback(mid, 0) + +mid = 1 +subscribe2_packet = mosq_test.gen_subscribe(mid, "topic2", 0) +suback2_packet = mosq_test.gen_suback(mid, 0) + +# All publishes have the same mid +mid = 1 +pubrec_packet = mosq_test.gen_pubrec(mid) +pubrel_packet = mosq_test.gen_pubrel(mid) +pubcomp_packet = mosq_test.gen_pubcomp(mid) + +publish1s_packet = mosq_test.gen_publish("topic1", qos=2, mid=mid, payload="message1") +publish2s_packet = mosq_test.gen_publish("topic2", qos=2, mid=mid, payload="message2") +publish3s_packet = mosq_test.gen_publish("topic1", qos=2, mid=mid, payload="message3") +publish4s_packet = mosq_test.gen_publish("topic1", qos=2, mid=mid, payload="message4") +publish5s_packet = mosq_test.gen_publish("topic1", qos=2, mid=mid, payload="message5") + +publish1r_packet = mosq_test.gen_publish("topic1", qos=0, payload="message1") +publish2r_packet = mosq_test.gen_publish("topic2", qos=0, payload="message2") +publish3r_packet = mosq_test.gen_publish("topic1", qos=0, payload="message3") +publish4r_packet = mosq_test.gen_publish("topic1", qos=0, payload="message4") +publish5r_packet = mosq_test.gen_publish("topic1", qos=0, payload="message5") + +port = mosq_test.get_port() +broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port) + +try: + sub1 = mosq_test.do_client_connect(sub1_connect_packet, sub1_connack_packet, timeout=10, port=port) + mosq_test.do_send_receive(sub1, subscribe1_packet, suback1_packet, "suback1") + + pub = mosq_test.do_client_connect(pub_connect_packet, pub_connack1_packet, timeout=10, port=port) + mosq_test.do_send_receive(pub, publish1s_packet, pubrec_packet, "pubrec1") + mosq_test.do_send_receive(pub, pubrel_packet, pubcomp_packet, "pubcomp1") + pub.close() + + if mosq_test.expect_packet(sub1, "publish1", publish1r_packet): + pub = mosq_test.do_client_connect(pub_connect_packet, pub_connack2_packet, timeout=10, port=port) + mosq_test.do_send_receive(pub, publish2s_packet, pubrec_packet, "pubrec2") + mosq_test.do_send_receive(pub, pubrel_packet, pubcomp_packet, "pubcomp2") + pub.close() + + # We expect nothing on sub1 + mosq_test.do_ping(sub1, error_string="pingresp1") + + pub = mosq_test.do_client_connect(pub_connect_packet, pub_connack2_packet, timeout=10, port=port) + mosq_test.do_send_receive(pub, publish3s_packet, pubrec_packet, "pubrec3") + mosq_test.do_send_receive(pub, pubrel_packet, pubcomp_packet, "pubcomp3") + pub.close() + + if mosq_test.expect_packet(sub1, "publish3", publish3r_packet): + sub2 = mosq_test.do_client_connect(sub2_connect_packet, sub2_connack_packet, timeout=10, port=port) + mosq_test.do_send_receive(sub2, subscribe2_packet, suback2_packet, "suback2") + + pub = mosq_test.do_client_connect(pub_connect_packet, pub_connack2_packet, timeout=10, port=port) + mosq_test.do_send_receive(pub, publish4s_packet, pubrec_packet, "pubrec4") + mosq_test.do_send_receive(pub, pubrel_packet, pubcomp_packet, "pubcomp4") + pub.close() + + # We expect nothing on sub2 + mosq_test.do_ping(sub2, error_string="pingresp2") + + if mosq_test.expect_packet(sub1, "publish4", publish4r_packet): + pub = mosq_test.do_client_connect(pub_connect_packet, pub_connack2_packet, timeout=10, port=port) + mosq_test.do_send_receive(pub, publish5s_packet, pubrec_packet, "pubrec5") + mosq_test.do_send_receive(pub, pubrel_packet, pubcomp_packet, "pubcomp5") + pub.close() + + # We expect nothing on sub2 + mosq_test.do_ping(sub2, error_string="pingresp2") + + if mosq_test.expect_packet(sub1, "publish5", publish5r_packet): + rc = 0 + + sub2.close() + sub1.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde.decode('utf-8')) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index 3b4ee95b..8da4d7fa 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -64,6 +64,7 @@ endif ./02-subpub-qos1-nolocal.py ./02-subpub-qos1-v5.py ./02-subpub-qos1.py + ./02-subpub-qos2-1322.py ./02-subpub-qos2-bad-puback-1.py ./02-subpub-qos2-bad-puback-2.py ./02-subpub-qos2-bad-pubcomp.py diff --git a/test/broker/test.py b/test/broker/test.py index 3d2e3ecd..afaa5388 100755 --- a/test/broker/test.py +++ b/test/broker/test.py @@ -43,6 +43,7 @@ tests = [ (1, './02-subpub-qos1-nolocal.py'), (1, './02-subpub-qos1-v5.py'), (1, './02-subpub-qos1.py'), + (1, './02-subpub-qos2-1322.py'), (1, './02-subpub-qos2-bad-puback-1.py'), (1, './02-subpub-qos2-bad-puback-2.py'), (1, './02-subpub-qos2-bad-pubcomp.py'), From 1001569fa31d00ac805380a047bddbd7f3b88107 Mon Sep 17 00:00:00 2001 From: Jonas Helgemo Date: Thu, 1 Aug 2019 10:37:06 +0200 Subject: [PATCH 17/25] docs: Fix typo on man-page for mosquitto.conf - man-page has a typo in the 'bridge_capath' section under SSL/TLS support Signed-off-by: Jonas Helgemo --- man/mosquitto.conf.5.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml index 3a9bb7f7..bcc88bc6 100644 --- a/man/mosquitto.conf.5.xml +++ b/man/mosquitto.conf.5.xml @@ -1741,7 +1741,7 @@ topic clients/total in 0 test/mosquitto/org $SYS/broker/ file path One of or - must be provided to + must be provided to allow SSL/TLS support. bridge_capath is used to define the path to a directory containing the PEM encoded CA From b9006487d176e1eb8064d4177abe49c62984d54a Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 1 Aug 2019 10:30:13 +0100 Subject: [PATCH 18/25] Fix link in CONTRIBUTING.md. Closes #1362. Thanks to Furkan Aksoy. --- CONTRIBUTING.md | 2 +- ChangeLog.txt | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3707fd56..df7e1f4d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,7 +11,7 @@ implementation, of an MQTT broker to allow new, existing, and emerging applications for Machine-to-Machine (M2M) and Internet of Things (IoT). - -- +- Source diff --git a/ChangeLog.txt b/ChangeLog.txt index fb736c96..6601a1d2 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -25,6 +25,9 @@ Clients: - mosquitto_pub: fix error codes not being returned when mosquitto_pub exits. Closes #1354. +Other: +- Various documentation fixes. + 1.6.3 - 20190618 ================ From d6e4534e5ef10312379876c212865e4026936284 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 1 Aug 2019 10:34:56 +0100 Subject: [PATCH 19/25] Fix location of readme-windows.txt Closes #1361. Thanks to Duck Development. --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 2dce0f84..95cc4dbf 100644 --- a/readme.md +++ b/readme.md @@ -58,7 +58,7 @@ To build from source the recommended route for end users is to download the archive from . On Windows and Mac, use `cmake` to build. On other platforms, just run `make` -to build. For Windows, see also `readme-windows.md`. +to build. For Windows, see also `readme-windows.txt`. If you are building from the git repository then the documentation will not already be built. Use `make binary` to skip building the man pages, or install From a22ccbd88426a74d5c127502fb64be335dafc71b Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 1 Aug 2019 11:32:52 +0100 Subject: [PATCH 20/25] Clients: improve error msgs when connecting v3.x broker with v5 client Closes #1344. Thanks to HowJMay. --- ChangeLog.txt | 5 ++++ client/pub_client.c | 9 ++++++-- client/rr_client.c | 8 +++++-- client/sub_client.c | 10 +++++--- lib/handle_connack.c | 54 ++++++++++++++++++++++++++++---------------- lib/loop.c | 1 - 6 files changed, 60 insertions(+), 27 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 6601a1d2..a5fd7eb6 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -20,10 +20,15 @@ Client library: - `mosquitto_string_option(mosq, MOSQ_OPT_TLS_KEYFORM, ...)` was incorrectly returning `MOSQ_ERR_INVAL` with valid input. This has been fixed. Closes #1360. +- on_connect callback is now called with the correct v5 reason code if a v5 + client connects to a v3.x broker and is sent a CONNACK with the + "unacceptable protocol version" connack reason code. Clients: - mosquitto_pub: fix error codes not being returned when mosquitto_pub exits. Closes #1354. +- All clients: improve error messages when connecting to a v3.x broker when in + v5 mode. Closes #1344. Other: - Various documentation fixes. diff --git a/client/pub_client.c b/client/pub_client.c index 69cea642..0debcaee 100644 --- a/client/pub_client.c +++ b/client/pub_client.c @@ -168,10 +168,15 @@ void my_connect_callback(struct mosquitto *mosq, void *obj, int result, int flag }else{ if(result){ if(cfg.protocol_version == MQTT_PROTOCOL_V5){ - err_printf(&cfg, "%s\n", mosquitto_reason_string(result)); + if(result == MQTT_RC_UNSUPPORTED_PROTOCOL_VERSION){ + err_printf(&cfg, "Connection error: %s. Try connecting to an MQTT v5 broker, or use MQTT v3.x mode.\n", mosquitto_reason_string(result)); + }else{ + err_printf(&cfg, "Connection error: %s\n", mosquitto_reason_string(result)); + } }else{ - err_printf(&cfg, "%s\n", mosquitto_connack_string(result)); + err_printf(&cfg, "Connection error: %s\n", mosquitto_connack_string(result)); } + mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props); } } } diff --git a/client/rr_client.c b/client/rr_client.c index 02801e82..44f105b0 100644 --- a/client/rr_client.c +++ b/client/rr_client.c @@ -122,7 +122,11 @@ void my_connect_callback(struct mosquitto *mosq, void *obj, int result, int flag }else{ client_state = rr_s_disconnect; if(result){ - err_printf(&cfg, "%s\n", mosquitto_connack_string(result)); + if(result == MQTT_RC_UNSUPPORTED_PROTOCOL_VERSION){ + err_printf(&cfg, "Connection error: %s. mosquitto_rr only supports connecting to an MQTT v5 broker\n", mosquitto_reason_string(result)); + }else{ + err_printf(&cfg, "Connection error: %s\n", mosquitto_reason_string(result)); + } } mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props); } @@ -356,7 +360,7 @@ int main(int argc, char *argv[]) } client_config_cleanup(&cfg); if(rc){ - fprintf(stderr, "Error: %s\n", mosquitto_strerror(rc)); + err_printf(&cfg, "Error: %s\n", mosquitto_strerror(rc)); } return rc; diff --git a/client/sub_client.c b/client/sub_client.c index a279b249..68b0e790 100644 --- a/client/sub_client.c +++ b/client/sub_client.c @@ -126,9 +126,13 @@ void my_connect_callback(struct mosquitto *mosq, void *obj, int result, int flag }else{ if(result){ if(cfg.protocol_version == MQTT_PROTOCOL_V5){ - err_printf(&cfg, "%s\n", mosquitto_reason_string(result)); + if(result == MQTT_RC_UNSUPPORTED_PROTOCOL_VERSION){ + err_printf(&cfg, "Connection error: %s. Try connecting to an MQTT v5 broker, or use MQTT v3.x mode.\n", mosquitto_reason_string(result)); + }else{ + err_printf(&cfg, "Connection error: %s\n", mosquitto_reason_string(result)); + } }else{ - err_printf(&cfg, "%s\n", mosquitto_connack_string(result)); + err_printf(&cfg, "Connection error: %s\n", mosquitto_connack_string(result)); } } mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props); @@ -353,7 +357,7 @@ int main(int argc, char *argv[]) } client_config_cleanup(&cfg); if(rc){ - fprintf(stderr, "Error: %s\n", mosquitto_strerror(rc)); + err_printf(&cfg, "Error: %s\n", mosquitto_strerror(rc)); } return rc; diff --git a/lib/handle_connack.c b/lib/handle_connack.c index 19b6a661..60780f6c 100644 --- a/lib/handle_connack.c +++ b/lib/handle_connack.c @@ -28,6 +28,29 @@ Contributors: #include "property_mosq.h" #include "read_handle.h" +static void connack_callback(struct mosquitto *mosq, uint8_t reason_code, uint8_t connect_flags, const mosquitto_property *properties) +{ + log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received CONNACK (%d)", mosq->id, reason_code); + pthread_mutex_lock(&mosq->callback_mutex); + if(mosq->on_connect){ + mosq->in_callback = true; + mosq->on_connect(mosq, mosq->userdata, reason_code); + mosq->in_callback = false; + } + if(mosq->on_connect_with_flags){ + mosq->in_callback = true; + mosq->on_connect_with_flags(mosq, mosq->userdata, reason_code, connect_flags); + mosq->in_callback = false; + } + if(mosq->on_connect_v5){ + mosq->in_callback = true; + mosq->on_connect_v5(mosq, mosq->userdata, reason_code, connect_flags, properties); + mosq->in_callback = false; + } + pthread_mutex_unlock(&mosq->callback_mutex); +} + + int handle__connack(struct mosquitto *mosq) { uint8_t connect_flags; @@ -44,7 +67,17 @@ int handle__connack(struct mosquitto *mosq) if(mosq->protocol == mosq_p_mqtt5){ rc = property__read_all(CMD_CONNACK, &mosq->in_packet, &properties); - if(rc) return rc; + + if(rc == MOSQ_ERR_PROTOCOL && reason_code == CONNACK_REFUSED_PROTOCOL_VERSION){ + /* This could occur because we are connecting to a v3.x broker and + * it has replied with "unacceptable protocol version", but with a + * v3 CONNACK. */ + + connack_callback(mosq, MQTT_RC_UNSUPPORTED_PROTOCOL_VERSION, connect_flags, NULL); + return rc; + }else if(rc){ + return rc; + } } mosquitto_property_read_string(properties, MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER, &clientid, false); @@ -68,24 +101,7 @@ int handle__connack(struct mosquitto *mosq) mosq->msgs_out.inflight_quota = mosq->msgs_out.inflight_maximum; - log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received CONNACK (%d)", mosq->id, reason_code); - pthread_mutex_lock(&mosq->callback_mutex); - if(mosq->on_connect){ - mosq->in_callback = true; - mosq->on_connect(mosq, mosq->userdata, reason_code); - mosq->in_callback = false; - } - if(mosq->on_connect_with_flags){ - mosq->in_callback = true; - mosq->on_connect_with_flags(mosq, mosq->userdata, reason_code, connect_flags); - mosq->in_callback = false; - } - if(mosq->on_connect_v5){ - mosq->in_callback = true; - mosq->on_connect_v5(mosq, mosq->userdata, reason_code, connect_flags, properties); - mosq->in_callback = false; - } - pthread_mutex_unlock(&mosq->callback_mutex); + connack_callback(mosq, reason_code, connect_flags, properties); mosquitto_property_free_all(&properties); switch(reason_code){ diff --git a/lib/loop.c b/lib/loop.c index 2342c945..36763e06 100644 --- a/lib/loop.c +++ b/lib/loop.c @@ -314,7 +314,6 @@ static int mosquitto__loop_rc_handle(struct mosquitto *mosq, int rc) mosq->in_callback = false; } pthread_mutex_unlock(&mosq->callback_mutex); - return rc; } return rc; } From b2aed5cb7e7bdd52183aa5f75be0231b37d617ca Mon Sep 17 00:00:00 2001 From: YangHau Date: Thu, 1 Aug 2019 11:06:52 +0800 Subject: [PATCH 21/25] feat: Remove unecessary if statement free() would take no action if the arguement is a NULL pointer. Therefore, the if statement is totally unnecessary. See ISO-IEC 9899 Signed-off-by: YangHau --- client/client_shared.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/client/client_shared.c b/client/client_shared.c index 7d3ba773..205245a2 100644 --- a/client/client_shared.c +++ b/client/client_shared.c @@ -1427,11 +1427,11 @@ static int mosquitto__parse_socks_url(struct mosq_config *cfg, char *url) return 0; cleanup: - if(username_or_host) free(username_or_host); - if(username) free(username); - if(password) free(password); - if(host) free(host); - if(port) free(port); + free(username_or_host); + free(username); + free(password); + free(host); + free(port); return 1; } #endif From 4253eca81c95159ed6aec5675a30b4cd0f2f2ced Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 1 Aug 2019 14:49:19 +0100 Subject: [PATCH 22/25] Fix memory leak when setting v5 properties in mosquitto_connect_v5() --- ChangeLog.txt | 1 + lib/send_connect.c | 1 + 2 files changed, 2 insertions(+) diff --git a/ChangeLog.txt b/ChangeLog.txt index a5fd7eb6..27b2c3e0 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -23,6 +23,7 @@ Client library: - on_connect callback is now called with the correct v5 reason code if a v5 client connects to a v3.x broker and is sent a CONNACK with the "unacceptable protocol version" connack reason code. +- Fix memory leak when setting v5 properties in mosquitto_connect_v5(). Clients: - mosquitto_pub: fix error codes not being returned when mosquitto_pub exits. diff --git a/lib/send_connect.c b/lib/send_connect.c index 210f125a..e35e6332 100644 --- a/lib/send_connect.c +++ b/lib/send_connect.c @@ -168,6 +168,7 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session property__write_all(packet, properties, false); property__write_all(packet, local_props, false); } + mosquitto_property_free_all(&local_props); /* Payload */ if(clientid){ From 64c6d4d96267f0bb277d2a15405817523c5fe5f3 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 1 Aug 2019 15:47:48 +0100 Subject: [PATCH 23/25] Fix properties not being sent on QoS>0 PUBLISH messages. --- ChangeLog.txt | 1 + lib/actions.c | 13 ++++++++++++- lib/messages_mosq.c | 5 +++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 27b2c3e0..101e3fd7 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -24,6 +24,7 @@ Client library: client connects to a v3.x broker and is sent a CONNACK with the "unacceptable protocol version" connack reason code. - Fix memory leak when setting v5 properties in mosquitto_connect_v5(). +- Fix properties not being sent on QoS>0 PUBLISH messages. Clients: - mosquitto_pub: fix error codes not being returned when mosquitto_pub exits. diff --git a/lib/actions.c b/lib/actions.c index b17c560f..99d03f29 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -40,6 +40,7 @@ int mosquitto_publish_v5(struct mosquitto *mosq, int *mid, const char *topic, in uint16_t local_mid; const mosquitto_property *p; const mosquitto_property *outgoing_properties = NULL; + mosquitto_property *properties_copy = NULL; mosquitto_property local_property; bool have_topic_alias; int rc; @@ -109,8 +110,15 @@ int mosquitto_publish_v5(struct mosquitto *mosq, int *mid, const char *topic, in if(qos == 0){ return send__publish(mosq, local_mid, topic, payloadlen, payload, qos, retain, false, outgoing_properties, NULL, 0); }else{ + if(outgoing_properties){ + rc = mosquitto_property_copy_all(&properties_copy, outgoing_properties); + if(rc) return rc; + } message = mosquitto__calloc(1, sizeof(struct mosquitto_message_all)); - if(!message) return MOSQ_ERR_NOMEM; + if(!message){ + mosquitto_property_free_all(&properties_copy); + return MOSQ_ERR_NOMEM; + } message->next = NULL; message->timestamp = mosquitto_time(); @@ -119,6 +127,7 @@ int mosquitto_publish_v5(struct mosquitto *mosq, int *mid, const char *topic, in message->msg.topic = mosquitto__strdup(topic); if(!message->msg.topic){ message__cleanup(&message); + mosquitto_property_free_all(&properties_copy); return MOSQ_ERR_NOMEM; } } @@ -127,6 +136,7 @@ int mosquitto_publish_v5(struct mosquitto *mosq, int *mid, const char *topic, in message->msg.payload = mosquitto__malloc(payloadlen*sizeof(uint8_t)); if(!message->msg.payload){ message__cleanup(&message); + mosquitto_property_free_all(&properties_copy); return MOSQ_ERR_NOMEM; } memcpy(message->msg.payload, payload, payloadlen*sizeof(uint8_t)); @@ -137,6 +147,7 @@ int mosquitto_publish_v5(struct mosquitto *mosq, int *mid, const char *topic, in message->msg.qos = qos; message->msg.retain = retain; message->dup = false; + message->properties = properties_copy; pthread_mutex_lock(&mosq->msgs_out.mutex); message->state = mosq_ms_invalid; diff --git a/lib/messages_mosq.c b/lib/messages_mosq.c index bf77f5e6..75e4f860 100644 --- a/lib/messages_mosq.c +++ b/lib/messages_mosq.c @@ -39,6 +39,7 @@ void message__cleanup(struct mosquitto_message_all **message) mosquitto__free(msg->msg.topic); mosquitto__free(msg->msg.payload); + mosquitto_property_free_all(&msg->properties); mosquitto__free(msg); } @@ -199,7 +200,7 @@ int message__release_to_inflight(struct mosquitto *mosq, enum mosquitto_msg_dire }else if(cur->msg.qos == 2){ cur->state = mosq_ms_wait_for_pubrec; } - rc = send__publish(mosq, cur->msg.mid, cur->msg.topic, cur->msg.payloadlen, cur->msg.payload, cur->msg.qos, cur->msg.retain, cur->dup, NULL, NULL, 0); + rc = send__publish(mosq, cur->msg.mid, cur->msg.topic, cur->msg.payloadlen, cur->msg.payload, cur->msg.qos, cur->msg.retain, cur->dup, cur->properties, NULL, 0); if(rc){ return rc; } @@ -286,7 +287,7 @@ void message__retry_check(struct mosquitto *mosq) case mosq_ms_publish_qos2: msg->timestamp = now; msg->dup = true; - send__publish(mosq, msg->msg.mid, msg->msg.topic, msg->msg.payloadlen, msg->msg.payload, msg->msg.qos, msg->msg.retain, msg->dup, NULL, NULL, 0); + send__publish(mosq, msg->msg.mid, msg->msg.topic, msg->msg.payloadlen, msg->msg.payload, msg->msg.qos, msg->msg.retain, msg->dup, msg->properties, NULL, 0); break; case mosq_ms_wait_for_pubrel: msg->timestamp = now; From d8f6215569d79ac15f42de8a5f42f61711b23498 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 1 Aug 2019 20:46:23 +0100 Subject: [PATCH 24/25] Windows fix --- lib/net_mosq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/net_mosq.c b/lib/net_mosq.c index ea04d1ab..9fd75856 100644 --- a/lib/net_mosq.c +++ b/lib/net_mosq.c @@ -961,7 +961,7 @@ int net__socket_nonblock(mosq_sock_t *sock) unsigned long opt = 1; if(ioctlsocket(*sock, FIONBIO, &opt)){ COMPAT_CLOSE(*sock); - mosq->sock = INVALID_SOCKET; + *sock = INVALID_SOCKET; return MOSQ_ERR_ERRNO; } #endif From ce3e33e8905c307e2d6783fb8fd1ce3713523c5a Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 1 Aug 2019 20:49:36 +0100 Subject: [PATCH 25/25] Bump version number, add release post. --- CMakeLists.txt | 2 +- ChangeLog.txt | 2 +- config.mk | 2 +- installer/mosquitto.nsi | 2 +- installer/mosquitto64.nsi | 2 +- lib/mosquitto.h | 2 +- set-version.sh | 2 +- snap/snapcraft.yaml | 2 +- www/pages/download.md | 8 +-- www/posts/2019/08/version-1-6-4-released.md | 56 +++++++++++++++++++++ 10 files changed, 68 insertions(+), 12 deletions(-) create mode 100644 www/posts/2019/08/version-1-6-4-released.md diff --git a/CMakeLists.txt b/CMakeLists.txt index e707229b..c670628d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ project(mosquitto) cmake_minimum_required(VERSION 2.8) # Only for version 3 and up. cmake_policy(SET CMP0042 NEW) -set (VERSION 1.6.3) +set (VERSION 1.6.4) add_definitions (-DCMAKE -DVERSION=\"${VERSION}\") diff --git a/ChangeLog.txt b/ChangeLog.txt index 101e3fd7..ba660d80 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,4 +1,4 @@ -1.6.4 - 2019xxxx +1.6.4 - 20190801 ================ Broker: diff --git a/config.mk b/config.mk index e305d0cd..6c23bef9 100644 --- a/config.mk +++ b/config.mk @@ -104,7 +104,7 @@ WITH_COVERAGE:=no # Also bump lib/mosquitto.h, CMakeLists.txt, # installer/mosquitto.nsi, installer/mosquitto64.nsi -VERSION=1.6.3 +VERSION=1.6.4 # Client library SO version. Bump if incompatible API/ABI changes are made. SOVERSION=1 diff --git a/installer/mosquitto.nsi b/installer/mosquitto.nsi index 15cd507d..2190683d 100644 --- a/installer/mosquitto.nsi +++ b/installer/mosquitto.nsi @@ -9,7 +9,7 @@ !define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' Name "Eclipse Mosquitto" -!define VERSION 1.6.3 +!define VERSION 1.6.4 OutFile "mosquitto-${VERSION}-install-windows-x86.exe" InstallDir "$PROGRAMFILES\mosquitto" diff --git a/installer/mosquitto64.nsi b/installer/mosquitto64.nsi index 6027fc89..12a98b84 100644 --- a/installer/mosquitto64.nsi +++ b/installer/mosquitto64.nsi @@ -9,7 +9,7 @@ !define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' Name "Eclipse Mosquitto" -!define VERSION 1.6.3 +!define VERSION 1.6.4 OutFile "mosquitto-${VERSION}-install-windows-x64.exe" !include "x64.nsh" diff --git a/lib/mosquitto.h b/lib/mosquitto.h index d939bfd2..6957b619 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -48,7 +48,7 @@ extern "C" { #define LIBMOSQUITTO_MAJOR 1 #define LIBMOSQUITTO_MINOR 6 -#define LIBMOSQUITTO_REVISION 3 +#define LIBMOSQUITTO_REVISION 4 /* LIBMOSQUITTO_VERSION_NUMBER looks like 1002001 for e.g. version 1.2.1. */ #define LIBMOSQUITTO_VERSION_NUMBER (LIBMOSQUITTO_MAJOR*1000000+LIBMOSQUITTO_MINOR*1000+LIBMOSQUITTO_REVISION) diff --git a/set-version.sh b/set-version.sh index 0e99da2f..5fe6c80c 100755 --- a/set-version.sh +++ b/set-version.sh @@ -2,7 +2,7 @@ MAJOR=1 MINOR=6 -REVISION=3 +REVISION=4 sed -i "s/^VERSION=.*/VERSION=${MAJOR}.${MINOR}.${REVISION}/" config.mk diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index cae454fa..95a4eb1f 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,5 +1,5 @@ name: mosquitto -version: 1.6.3 +version: 1.6.4 summary: Eclipse Mosquitto MQTT broker description: This is a message broker that supports version 3.1 and 3.1.1 of the MQTT protocol. diff --git a/www/pages/download.md b/www/pages/download.md index 13aa8ddc..a2acb0e2 100644 --- a/www/pages/download.md +++ b/www/pages/download.md @@ -1,7 +1,7 @@ + +This is a bugfix release. + +## Broker +- Fix persistent clients being incorrectly expired on Raspberry Pis. + Closes [#1272]. +- Windows: Allow other applications access to the log file when running. + Closes [#515]. +- Fix incoming QoS 2 messages being blocked when `max_inflight_messages` was + set to 1. Closes [#1332]. +- Fix incoming messages not being removed for a client if the topic being + published to does not have any subscribers. Closes [#1322]. + +## Client library +- Fix MQTT v5 subscription options being incorrectly set for MQTT v3 + subscriptions. Closes [#1353]. +- Make behaviour of `mosquitto_connect_async()` consistent with + `mosquitto_connect()` when connecting to a non-existent server. + Closes [#1345]. +- `mosquitto_string_option(mosq, MOSQ_OPT_TLS_KEYFORM, ...)` was incorrectly + returning `MOSQ_ERR_INVAL` with valid input. This has been fixed. + Closes [#1360]. +- `on_connect` callback is now called with the correct v5 reason code if a v5 + client connects to a v3.x broker and is sent a CONNACK with the + "unacceptable protocol version" connack reason code. +- Fix memory leak when setting v5 properties in `mosquitto_connect_v5()`. +- Fix properties not being sent on QoS>0 PUBLISH messages. + +## Clients +- `mosquitto_pub`: fix error codes not being returned when `mosquitto_pub` exits. + Closes [#1354]. +- All clients: improve error messages when connecting to a v3.x broker when in + v5 mode. Closes [#1344]. + +## Other +- Various documentation fixes. + +[#515]: https://github.com/eclipse/mosquitto/issues/515 +[#1272]: https://github.com/eclipse/mosquitto/issues/1272 +[#1322]: https://github.com/eclipse/mosquitto/issues/1322 +[#1332]: https://github.com/eclipse/mosquitto/issues/1332 +[#1344]: https://github.com/eclipse/mosquitto/issues/1344 +[#1345]: https://github.com/eclipse/mosquitto/issues/1345 +[#1353]: https://github.com/eclipse/mosquitto/issues/1353 +[#1354]: https://github.com/eclipse/mosquitto/issues/1354 +[#1360]: https://github.com/eclipse/mosquitto/issues/1360