Merge branch 'fixes'

pull/1371/head v1.6.4
Roger A. Light 6 years ago
commit 95bf4a2714

@ -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}\")

@ -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).
- <https://mosquitto.org/>
- <https://projects.eclipse.org/projects/technology.mosquitto>
- <https://projects.eclipse.org/projects/iot.mosquitto>
Source

@ -1,3 +1,41 @@
1.6.4 - 20190801
================
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.
1.6.3 - 20190618
================

@ -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

@ -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)
@ -166,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);
}
}
}
@ -443,7 +450,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){

@ -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);
}
@ -252,8 +256,6 @@ int main(int argc, char *argv[])
#ifndef WIN32
struct sigaction sigact;
#endif
memset(&cfg, 0, sizeof(struct mosq_config));
mosquitto_lib_init();
@ -358,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;

@ -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);
@ -278,8 +282,6 @@ int main(int argc, char *argv[])
#ifndef WIN32
struct sigaction sigact;
#endif
memset(&cfg, 0, sizeof(struct mosq_config));
mosquitto_lib_init();
@ -355,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;

@ -16,7 +16,10 @@
# define _POSIX_C_SOURCE 200809L
#endif
#define _GNU_SOURCE
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#define OPENSSL_LOAD_CONF

@ -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

@ -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

@ -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

@ -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

@ -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"

@ -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"

@ -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;
@ -200,6 +211,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);
}

@ -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;
}
}

@ -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){

@ -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);

@ -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;
}

@ -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;

@ -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)
@ -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

@ -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);
*sock = INVALID_SOCKET;
return MOSQ_ERR_ERRNO;
}
#endif

@ -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;
}

@ -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

@ -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);

@ -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);

@ -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){

@ -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,

@ -1741,7 +1741,7 @@ topic clients/total in 0 test/mosquitto/org $SYS/broker/
<term><option>bridge_capath</option> <replaceable>file path</replaceable></term>
<listitem>
<para>One of <option>bridge_capath</option> or
<option>bridge_capath</option> must be provided to
<option>bridge_cafile</option> must be provided to
allow SSL/TLS support.</para>
<para>bridge_capath is used to define the path to a
directory containing the PEM encoded CA

@ -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.

@ -58,7 +58,7 @@ To build from source the recommended route for end users is to download the
archive from <https://mosquitto.org/download/>.
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

@ -2,7 +2,7 @@
MAJOR=1
MINOR=6
REVISION=3
REVISION=4
sed -i "s/^VERSION=.*/VERSION=${MAJOR}.${MINOR}.${REVISION}/" config.mk

@ -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.

@ -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;
}
}

@ -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;

@ -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);

@ -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);

@ -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)

@ -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)

@ -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)

@ -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
@ -101,6 +102,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 :

@ -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'),
@ -79,6 +80,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'),

@ -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);

@ -1,7 +1,7 @@
<!--
.. title: Download
.. slug: download
.. date: 2019-04-30 13:12:00 UTC+1
.. date: 2019-08-01 13:12:00 UTC+1
.. tags: tag
.. category: category
.. link: link
@ -11,7 +11,7 @@
# Source
* [mosquitto-1.6.3.tar.gz](https://mosquitto.org/files/source/mosquitto-1.6.3.tar.gz) (319kB) ([GPG signature](https://mosquitto.org/files/source/mosquitto-1.6.3.tar.gz.asc))
* [mosquitto-1.6.4.tar.gz](https://mosquitto.org/files/source/mosquitto-1.6.4.tar.gz) (319kB) ([GPG signature](https://mosquitto.org/files/source/mosquitto-1.6.4.tar.gz.asc))
* [Git source code repository](https://github.com/eclipse/mosquitto) (github.com)
Older downloads are available at [https://mosquitto.org/files/](../files/)
@ -24,8 +24,8 @@ distributions.
## Windows
* [mosquitto-1.6.3-install-windows-x64.exe](https://mosquitto.org/files/binary/win64/mosquitto-1.6.3-install-windows-x64.exe) (~1.4 MB) (64-bit build, Windows Vista and up, built with Visual Studio Community 2017)
* [mosquitto-1.6.3-install-windows-x32.exe](https://mosquitto.org/files/binary/win32/mosquitto-1.6.2-install-windows-x86.exe) (~1.4 MB) (32-bit build, Windows Vista and up, built with Visual Studio Community 2017)
* [mosquitto-1.6.4-install-windows-x64.exe](https://mosquitto.org/files/binary/win64/mosquitto-1.6.4-install-windows-x64.exe) (~1.4 MB) (64-bit build, Windows Vista and up, built with Visual Studio Community 2017)
* [mosquitto-1.6.4-install-windows-x32.exe](https://mosquitto.org/files/binary/win32/mosquitto-1.6.2-install-windows-x86.exe) (~1.4 MB) (32-bit build, Windows Vista and up, built with Visual Studio Community 2017)
See also readme-windows.txt after installing.

@ -27,10 +27,8 @@
and mosquitto_sub command line MQTT clients.</p>
<p>Mosquitto is part of the <a href="https://eclipse.org/">Eclipse
Foundation</a> and is an <a
href="https://iot.eclipse.org/">iot.eclipse.org</a> project.</p>
Foundation</a>, is an <a href="https://iot.eclipse.org/">iot.eclipse.org</a>
project and is sponsored by <a href="https://cedalo.com/">cedalo.com</a>.</p>
</div>
</section>
<hr/>

@ -0,0 +1,56 @@
<!--
.. title: Version 1.6.4 released
.. slug: version-1-6-4-released
.. date: 2019-08-01 18:00:00 UTC+1
.. tags: Releases
.. category:
.. link:
.. description:
.. type: text
-->
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
Loading…
Cancel
Save