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/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 6b3f8716..ba660d80 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -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 ================ 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 diff --git a/client/pub_client.c b/client/pub_client.c index 31740391..0debcaee 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) @@ -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){ diff --git a/client/rr_client.c b/client/rr_client.c index 6444c28e..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); } @@ -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; diff --git a/client/sub_client.c b/client/sub_client.c index f57a48cc..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); @@ -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; 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 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/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 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/actions.c b/lib/actions.c index a5bf673f..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; @@ -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); } 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/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/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/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; } 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; diff --git a/lib/mosquitto.h b/lib/mosquitto.h index 09bba66e..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) @@ -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 diff --git a/lib/net_mosq.c b/lib/net_mosq.c index f207e32a..9fd75856 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); + *sock = INVALID_SOCKET; return MOSQ_ERR_ERRNO; } #endif 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; } 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); 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); 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){ 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/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 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. 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 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/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/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/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); 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); 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/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..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 @@ -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 : diff --git a/test/broker/test.py b/test/broker/test.py index 497e3627..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'), @@ -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'), 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); 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