1
0
mirror of https://github.com/eclipse/mosquitto.git synced 2025-05-08 16:52:13 +08:00

Merge branch 'master'

Conflicts:
	ChangeLog.txt
	config.mk
	src/context.c
	src/loop.c
	src/subs.c
	test/broker/01-connect-bad-packet.py
	test/broker/02-subpub-qos1-bad-pubcomp.py
	test/broker/02-subpub-qos1-bad-pubrec.py
	test/broker/02-subpub-qos2-bad-puback-1.py
	test/broker/02-subpub-qos2-bad-puback-2.py
	test/broker/02-subpub-qos2-bad-pubcomp.py
	test/broker/02-subpub-qos2.py
	test/broker/07-will-null-topic.py
This commit is contained in:
Roger A. Light 2019-12-03 13:59:05 +00:00
commit c0443637e8
64 changed files with 1262 additions and 826 deletions

View File

@ -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.7)
set (VERSION 1.6.8)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
@ -119,9 +119,9 @@ install(FILES mosquitto.conf aclfile.example pskfile.example pwfile.example DEST
# ========================================
configure_file(libmosquitto.pc.in libmosquitto.pc @ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libmosquitto.pc" DESTINATION "${CMAKE_INSTALL_PREFIX}/share/pkgconfig")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libmosquitto.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
configure_file(libmosquittopp.pc.in libmosquittopp.pc @ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libmosquittopp.pc" DESTINATION "${CMAKE_INSTALL_PREFIX}/share/pkgconfig")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libmosquittopp.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
# ========================================
# Testing

View File

@ -38,6 +38,55 @@ Clients:
- mosquitto_sub will now exit if all subscriptions were denied.
1.6.8 - 20191128
================
Broker:
- Various fixes for `allow_zero_length_clientid` config, where this option was
not being set correctly. Closes #1429.
- Fix incorrect memory tracking causing problems with memory_limit option.
Closes #1437.
- Fix subscription topics being limited to 200 characters instead of 200
hierarchy levels. Closes #1441.
- Only a single CRL could be loaded at once. This has been fixed.
Closes #1442.
- Fix problems with reloading config when `per_listener_settings` was true.
Closes #1459.
- Fix retained messages with an expiry interval not being expired after being
restored from persistence. Closes #1464.
- Fix messages with an expiry interval being sent without an expiry interval
property just before they were expired. Closes #1464.
- Fix TLS Websockets clients not receiving messages after taking over a
previous connection. Closes #1489.
- Fix MQTT 3.1.1 clients using clean session false, or MQTT 5.0 clients using
session-expiry-interval set to infinity never expiring, even when the global
`persistent_client_expiration` option was set. Closes #1494.
Client library:
- Fix publish properties not being passed to on_message_v5 callback for QoS 2
messages. Closes #1432.
- Fix documentation issues in mosquitto.h. Closes #1478.
- Document `mosquitto_connect_srv()`. Closes #1499.
Clients:
- Fix duplicate cfg definition in rr_client. Closes #1453.
- Fix `mosquitto_pub -l` hang when stdin stream ends. Closes #1448.
- Fix `mosquitto_pub -l` not sending the final line of stdin if it does not
end with a new line. Closes #1473.
- Make documentation for `mosquitto_pub -l` match reality - blank lines are
sent as empty messages. Closes #1474.
- Free memory in `mosquitto_sub` when quiting without having made a successful
connection. Closes #1513.
Build:
- Added `CLIENT_STATIC_LDADD` to makefile builds to allow more libraries to be
linked when compiling the clients with a static libmosquitto, as required
for e.g. openssl on some systems.
Installer:
- Fix mosquitto_rr.exe not being included in Windows installers. Closes #1463.
1.6.7 - 20190925
================

View File

@ -21,13 +21,13 @@ static : static_pub static_sub static_rr
# libmosquitto only.
static_pub : pub_client.o pub_shared.o client_props.o client_shared.o ../lib/libmosquitto.a
${CROSS_COMPILE}${CC} $^ -o mosquitto_pub ${CLIENT_LDFLAGS} ${STATIC_LIB_DEPS}
${CROSS_COMPILE}${CC} $^ -o mosquitto_pub ${CLIENT_LDFLAGS} ${STATIC_LIB_DEPS} ${CLIENT_STATIC_LDADD}
static_sub : sub_client.o sub_client_output.o client_props.o client_shared.o ../lib/libmosquitto.a
${CROSS_COMPILE}${CC} $^ -o mosquitto_sub ${CLIENT_LDFLAGS} ${STATIC_LIB_DEPS}
${CROSS_COMPILE}${CC} $^ -o mosquitto_sub ${CLIENT_LDFLAGS} ${STATIC_LIB_DEPS} ${CLIENT_STATIC_LDADD}
static_rr : rr_client.o client_props.o client_shared.o pub_shared.o sub_client_output.o ../lib/libmosquitto.a
${CROSS_COMPILE}${CC} $^ -o mosquitto_rr ${CLIENT_LDFLAGS} ${STATIC_LIB_DEPS}
${CROSS_COMPILE}${CC} $^ -o mosquitto_rr ${CLIENT_LDFLAGS} ${STATIC_LIB_DEPS} ${CLIENT_STATIC_LDADD}
mosquitto_pub : pub_client.o pub_shared.o client_shared.o client_props.o
${CROSS_COMPILE}${CC} $(CLIENT_LDFLAGS) $^ -o $@ $(CLIENT_LDADD)

View File

@ -45,6 +45,7 @@ static int line_buf_len = 1024;
static bool disconnect_sent = false;
static int publish_count = 0;
static bool ready_for_repeat = false;
static volatile int status = STATUS_CONNECTING;
#ifdef WIN32
static uint64_t next_publish_tv;
@ -219,111 +220,122 @@ int pub_shared_init(void)
}
int pub_shared_loop(struct mosquitto *mosq)
int pub_stdin_line_loop(struct mosquitto *mosq)
{
int read_len;
int pos;
int rc, rc2;
char *buf2;
int buf_len_actual;
int mode;
int loop_delay = 1000;
int buf_len_actual = 0;
int pos;
int rc = MOSQ_ERR_SUCCESS;
int read_len;
bool stdin_finished = false;
mosquitto_loop_start(mosq);
stdin_finished = false;
do{
if(status == STATUS_CONNACK_RECVD){
pos = 0;
read_len = line_buf_len;
while(status == STATUS_CONNACK_RECVD && fgets(&line_buf[pos], read_len, stdin)){
buf_len_actual = strlen(line_buf);
if(line_buf[buf_len_actual-1] == '\n'){
line_buf[buf_len_actual-1] = '\0';
rc = my_publish(mosq, &mid_sent, cfg.topic, buf_len_actual-1, line_buf, cfg.qos, cfg.retain);
pos = 0;
if(rc){
err_printf(&cfg, "Error: Publish returned %d, disconnecting.\n", rc);
mosquitto_disconnect_v5(mosq, MQTT_RC_DISCONNECT_WITH_WILL_MSG, cfg.disconnect_props);
}
break;
}else{
line_buf_len += 1024;
pos += 1023;
read_len = 1024;
buf2 = realloc(line_buf, line_buf_len);
if(!buf2){
err_printf(&cfg, "Error: Out of memory.\n");
return MOSQ_ERR_NOMEM;
}
line_buf = buf2;
}
}
if(pos != 0){
rc = my_publish(mosq, &mid_sent, cfg.topic, buf_len_actual, line_buf, cfg.qos, cfg.retain);
if(rc){
err_printf(&cfg, "Error: Publish returned %d, disconnecting.\n", rc);
mosquitto_disconnect_v5(mosq, MQTT_RC_DISCONNECT_WITH_WILL_MSG, cfg.disconnect_props);
}
}
if(feof(stdin)){
if(mid_sent == -1){
/* Empty file */
mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props);
disconnect_sent = true;
status = STATUS_DISCONNECTING;
}else{
last_mid = mid_sent;
status = STATUS_WAITING;
}
stdin_finished = true;
}else if(status == STATUS_DISCONNECTED){
/* Not end of stdin, so we've lost our connection and must
* reconnect */
}
}
if(status == STATUS_WAITING){
if(last_mid_sent == last_mid && disconnect_sent == false){
mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props);
disconnect_sent = true;
}
#ifdef WIN32
Sleep(100);
#else
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 100000000;
nanosleep(&ts, NULL);
#endif
}
}while(stdin_finished == false);
mosquitto_loop_stop(mosq, false);
if(status == STATUS_DISCONNECTED){
return MOSQ_ERR_SUCCESS;
}else{
return rc;
}
}
int pub_other_loop(struct mosquitto *mosq)
{
int rc;
int loop_delay = 1000;
if(cfg.repeat_count > 1 && (cfg.repeat_delay.tv_sec == 0 || cfg.repeat_delay.tv_usec != 0)){
loop_delay = cfg.repeat_delay.tv_usec / 2000;
}
mode = cfg.pub_mode;
if(mode == MSGMODE_STDIN_LINE){
mosquitto_loop_start(mosq);
stdin_finished = false;
}
do{
if(mode == MSGMODE_STDIN_LINE){
if(status == STATUS_CONNACK_RECVD){
pos = 0;
read_len = line_buf_len;
while(status == STATUS_CONNACK_RECVD && fgets(&line_buf[pos], read_len, stdin)){
buf_len_actual = strlen(line_buf);
if(line_buf[buf_len_actual-1] == '\n'){
line_buf[buf_len_actual-1] = '\0';
rc2 = my_publish(mosq, &mid_sent, cfg.topic, buf_len_actual-1, line_buf, cfg.qos, cfg.retain);
if(rc2){
err_printf(&cfg, "Error: Publish returned %d, disconnecting.\n", rc2);
mosquitto_disconnect_v5(mosq, MQTT_RC_DISCONNECT_WITH_WILL_MSG, cfg.disconnect_props);
}
break;
}else{
line_buf_len += 1024;
pos += 1023;
read_len = 1024;
buf2 = realloc(line_buf, line_buf_len);
if(!buf2){
err_printf(&cfg, "Error: Out of memory.\n");
return MOSQ_ERR_NOMEM;
}
line_buf = buf2;
}
}
if(feof(stdin)){
if(mid_sent == -1){
/* Empty file */
mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props);
disconnect_sent = true;
status = STATUS_DISCONNECTING;
}else{
last_mid = mid_sent;
status = STATUS_WAITING;
}
stdin_finished = true;
}else if(status == STATUS_DISCONNECTED){
/* Not end of stdin, so we've lost our connection and must
* reconnect */
}
}else if(status == STATUS_WAITING){
if(last_mid_sent == last_mid && disconnect_sent == false){
mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props);
disconnect_sent = true;
}
#ifdef WIN32
Sleep(100);
#else
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 100000000;
nanosleep(&ts, NULL);
#endif
}
rc = mosquitto_loop(mosq, loop_delay, 1);
if(ready_for_repeat && check_repeat_time()){
rc = MOSQ_ERR_SUCCESS;
}else{
rc = mosquitto_loop(mosq, loop_delay, 1);
if(ready_for_repeat && check_repeat_time()){
rc = 0;
switch(cfg.pub_mode){
case MSGMODE_CMD:
case MSGMODE_FILE:
case MSGMODE_STDIN_FILE:
rc = my_publish(mosq, &mid_sent, cfg.topic, cfg.msglen, cfg.message, cfg.qos, cfg.retain);
break;
case MSGMODE_NULL:
rc = my_publish(mosq, &mid_sent, cfg.topic, 0, NULL, cfg.qos, cfg.retain);
break;
case MSGMODE_STDIN_LINE:
break;
}
if(rc){
err_printf(&cfg, "Error sending repeat publish: %s", mosquitto_strerror(rc));
}
switch(cfg.pub_mode){
case MSGMODE_CMD:
case MSGMODE_FILE:
case MSGMODE_STDIN_FILE:
rc = my_publish(mosq, &mid_sent, cfg.topic, cfg.msglen, cfg.message, cfg.qos, cfg.retain);
break;
case MSGMODE_NULL:
rc = my_publish(mosq, &mid_sent, cfg.topic, 0, NULL, cfg.qos, cfg.retain);
break;
}
if(rc){
err_printf(&cfg, "Error sending repeat publish: %s", mosquitto_strerror(rc));
}
}
}while(rc == MOSQ_ERR_SUCCESS && stdin_finished == false);
}while(rc == MOSQ_ERR_SUCCESS);
if(mode == MSGMODE_STDIN_LINE){
mosquitto_loop_stop(mosq, false);
}
if(status == STATUS_DISCONNECTED){
return MOSQ_ERR_SUCCESS;
}else{
@ -332,6 +344,16 @@ int pub_shared_loop(struct mosquitto *mosq)
}
int pub_shared_loop(struct mosquitto *mosq)
{
if(cfg.pub_mode == MSGMODE_STDIN_LINE){
return pub_stdin_line_loop(mosq);
}else{
return pub_other_loop(mosq);
}
}
void pub_shared_cleanup(void)
{
free(line_buf);

View File

@ -37,7 +37,6 @@ Contributors:
/* Global variables for use in callbacks. See sub_client.c for an example of
* using a struct to hold variables for use in callbacks. */
int mid_sent = -1;
int status = STATUS_CONNECTING;
struct mosq_config cfg;
void my_log_callback(struct mosquitto *mosq, void *obj, int level, const char *str)

View File

@ -23,7 +23,6 @@ Contributors:
#define STATUS_DISCONNECTED 4
extern int mid_sent;
extern int status;
extern struct mosq_config cfg;

View File

@ -48,7 +48,8 @@ enum rr__state {
static enum rr__state client_state = rr_s_new;
struct mosq_config cfg;
extern struct mosq_config cfg;
bool process_messages = true;
int msg_count = 0;
struct mosquitto *mosq = NULL;

View File

@ -46,7 +46,7 @@ static bool timed_out = false;
#ifndef WIN32
void my_signal_handler(int signum)
{
if(signum == SIGALRM){
if(signum == SIGALRM || signum == SIGTERM || signum == SIGINT){
process_messages = false;
mosquitto_disconnect_v5(mosq, MQTT_RC_DISCONNECT_WITH_WILL_MSG, cfg.disconnect_props);
timed_out = true;
@ -354,6 +354,16 @@ int main(int argc, char *argv[])
goto cleanup;
}
if(sigaction(SIGTERM, &sigact, NULL) == -1){
perror("sigaction");
goto cleanup;
}
if(sigaction(SIGINT, &sigact, NULL) == -1){
perror("sigaction");
goto cleanup;
}
if(cfg.timeout){
alarm(cfg.timeout);
}
@ -377,6 +387,7 @@ int main(int argc, char *argv[])
return rc;
cleanup:
mosquitto_destroy(mosq);
mosquitto_lib_cleanup();
client_config_cleanup(&cfg);
return 1;

View File

@ -82,6 +82,11 @@ WITH_STRIP:=no
# Build static libraries
WITH_STATIC_LIBRARIES:=no
# Use this variable to add extra library dependencies when building the clients
# with the static libmosquitto library. This may be required on some systems
# where e.g. -lz or -latomic are needed for openssl.
CLIENT_STATIC_LDADD:=
# Build shared libraries
WITH_SHARED_LIBRARIES:=yes
@ -110,7 +115,7 @@ WITH_CJSON:=yes
# Also bump lib/mosquitto.h, CMakeLists.txt,
# installer/mosquitto.nsi, installer/mosquitto64.nsi
VERSION=1.6.7
VERSION=1.6.8
# Client library SO version. Bump if incompatible API/ABI changes are made.
SOVERSION=1
@ -329,3 +334,7 @@ ifeq ($(WITH_CJSON),yes)
CLIENT_CFLAGS:=$(CLIENT_CFLAGS) -DWITH_CJSON -I/usr/include/cjson
CLIENT_LDADD:=$(CLIENT_LDADD) -lcjson
endif
BROKER_LDADD:=${BROKER_LDADD} ${LDADD}
CLIENT_LDADD:=${CLIENT_LDADD} ${LDADD}
PASSWD_LDADD:=${PASSWD_LDADD} ${LDADD}

View File

@ -3,7 +3,7 @@ MAINTAINER David Audet <david.audet@ca.com>
LABEL Description="Eclipse Mosquitto MQTT Broker"
RUN apk --no-cache add mosquitto=1.4.12-r0 && \
RUN apk --no-cache add mosquitto=1.4.12-r0 ca-certificates && \
mkdir -p /mosquitto/config /mosquitto/data /mosquitto/log && \
cp /etc/mosquitto/mosquitto.conf /mosquitto/config && \
chown -R mosquitto:mosquitto /mosquitto

View File

@ -75,7 +75,7 @@ RUN set -x && \
install -m644 /build/mosq/mosquitto.conf /mosquitto/config/mosquitto.conf && \
chown -R mosquitto:mosquitto /mosquitto && \
apk --no-cache add \
libuuid && \
ca-certificates libuuid && \
apk del build-deps && \
rm -rf /build

View File

@ -78,6 +78,8 @@ RUN set -x && \
install -s -m755 /build/mosq/src/mosquitto_passwd /usr/bin/mosquitto_passwd && \
install -m644 /build/mosq/mosquitto.conf /mosquitto/config/mosquitto.conf && \
chown -R mosquitto:mosquitto /mosquitto && \
apk --no-cache add \
ca-certificates && \
apk del build-deps && \
rm -rf /build

View File

@ -12,7 +12,8 @@ RUN apk --no-cache add \
util-linux-dev \
libwebsockets-dev \
libxslt \
python2
python2 \
ca-certificates
# This build procedure is based on:
# https://github.com/alpinelinux/aports/blob/master/main/mosquitto/APKBUILD
@ -46,6 +47,7 @@ LABEL maintainer="Jonathan Hanson <jonathan@jonathan-hanson.org>" \
# Install the run-time dependencies
RUN apk --no-cache add \
busybox \
ca-certificates \
libcrypto1.0 \
libssl1.0 \
libuuid \

View File

@ -59,6 +59,8 @@ RUN set -x && \
install -s -m755 /build/mosq/src/mosquitto_passwd /usr/bin/mosquitto_passwd && \
install -m644 /build/mosq/mosquitto.conf /mosquitto/config/mosquitto.conf && \
chown -R mosquitto:mosquitto /mosquitto && \
apk --no-cache add \
ca-certificates && \
apk del build-deps && \
rm -rf /build

View File

@ -9,7 +9,7 @@
!define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
Name "Eclipse Mosquitto"
!define VERSION 1.6.7
!define VERSION 1.6.8
OutFile "mosquitto-${VERSION}-install-windows-x86.exe"
InstallDir "$PROGRAMFILES\mosquitto"
@ -45,6 +45,7 @@ Section "Files" SecInstall
File "..\build\src\Release\mosquitto_passwd.exe"
File "..\build\client\Release\mosquitto_pub.exe"
File "..\build\client\Release\mosquitto_sub.exe"
File "..\build\client\Release\mosquitto_rr.exe"
File "..\build\lib\Release\mosquitto.dll"
File "..\build\lib\cpp\Release\mosquittopp.dll"
File "..\aclfile.example"
@ -90,6 +91,7 @@ Section "Uninstall"
Delete "$INSTDIR\mosquitto_passwd.exe"
Delete "$INSTDIR\mosquitto_pub.exe"
Delete "$INSTDIR\mosquitto_sub.exe"
Delete "$INSTDIR\mosquitto_rr.exe"
Delete "$INSTDIR\mosquitto.dll"
Delete "$INSTDIR\mosquittopp.dll"
Delete "$INSTDIR\aclfile.example"

View File

@ -9,7 +9,7 @@
!define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
Name "Eclipse Mosquitto"
!define VERSION 1.6.7
!define VERSION 1.6.8
OutFile "mosquitto-${VERSION}-install-windows-x64.exe"
!include "x64.nsh"
@ -46,6 +46,7 @@ Section "Files" SecInstall
File "..\build64\src\Release\mosquitto_passwd.exe"
File "..\build64\client\Release\mosquitto_pub.exe"
File "..\build64\client\Release\mosquitto_sub.exe"
File "..\build64\client\Release\mosquitto_rr.exe"
File "..\build64\lib\Release\mosquitto.dll"
File "..\build64\lib\cpp\Release\mosquittopp.dll"
File "..\aclfile.example"
@ -91,6 +92,7 @@ Section "Uninstall"
Delete "$INSTDIR\mosquitto_passwd.exe"
Delete "$INSTDIR\mosquitto_pub.exe"
Delete "$INSTDIR\mosquitto_sub.exe"
Delete "$INSTDIR\mosquitto_rr.exe"
Delete "$INSTDIR\mosquitto.dll"
Delete "$INSTDIR\mosquittopp.dll"
Delete "$INSTDIR\aclfile.example"

View File

@ -152,13 +152,13 @@ int handle__publish(struct mosquitto *mosq)
mosquitto_property_free_all(&properties);
return rc;
case 2:
message->properties = properties;
util__decrement_receive_quota(mosq);
rc = send__pubrec(mosq, message->msg.mid, 0);
pthread_mutex_lock(&mosq->msgs_in.mutex);
message->state = mosq_ms_wait_for_pubrel;
message__queue(mosq, message, mosq_md_in);
pthread_mutex_unlock(&mosq->msgs_in.mutex);
mosquitto_property_free_all(&properties);
return rc;
default:
message__cleanup(&message);

View File

@ -114,7 +114,7 @@ int handle__pubrel(struct mosquitto_db *db, struct mosquitto *mosq)
}
if(mosq->on_message_v5){
mosq->in_callback = true;
mosq->on_message_v5(mosq, mosq->userdata, &message->msg, properties);
mosq->on_message_v5(mosq, mosq->userdata, &message->msg, message->properties);
mosq->in_callback = false;
}
pthread_mutex_unlock(&mosq->callback_mutex);

View File

@ -48,7 +48,7 @@ extern "C" {
#define LIBMOSQUITTO_MAJOR 1
#define LIBMOSQUITTO_MINOR 6
#define LIBMOSQUITTO_REVISION 7
#define LIBMOSQUITTO_REVISION 8
/* 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)
@ -393,11 +393,9 @@ libmosq_EXPORT int mosquitto_will_clear(struct mosquitto *mosq);
/*
* Function: mosquitto_username_pw_set
*
* Configure username and password for a mosquitton instance. This is only
* supported by brokers that implement the MQTT spec v3.1. By default, no
* username or password will be sent.
* If username is NULL, the password argument is ignored.
* This must be called before calling mosquitto_connect().
* Configure username and password for a mosquitto instance. By default, no
* username or password will be sent. For v3.1 and v3.1.1 clients, if username
* is NULL, the password argument is ignored.
*
* This is must be called before calling <mosquitto_connect>.
*
@ -481,8 +479,13 @@ libmosq_EXPORT int mosquitto_connect_bind(struct mosquitto *mosq, const char *ho
* Function: mosquitto_connect_bind_v5
*
* Connect to an MQTT broker. This extends the functionality of
* <mosquitto_connect> by adding the bind_address parameter. Use this function
* if you need to restrict network communication over a particular interface.
* <mosquitto_connect> by adding the bind_address parameter and MQTT v5
* properties. Use this function if you need to restrict network communication
* over a particular interface.
*
* Use e.g. <mosquitto_property_add_string> and similar to create a list of
* properties, then attach them to this publish. Properties need freeing with
* <mosquitto_property_free_all>.
*
* Parameters:
* mosq - a valid mosquitto instance.
@ -581,20 +584,18 @@ libmosq_EXPORT int mosquitto_connect_bind_async(struct mosquitto *mosq, const ch
/*
* Function: mosquitto_connect_srv
*
* Connect to an MQTT broker. This is a non-blocking call. If you use
* <mosquitto_connect_async> your client must use the threaded interface
* <mosquitto_loop_start>. If you need to use <mosquitto_loop>, you must use
* <mosquitto_connect> to connect the client.
* Connect to an MQTT broker.
*
* This extends the functionality of <mosquitto_connect_async> by adding the
* bind_address parameter. Use this function if you need to restrict network
* communication over a particular interface.
* If you set `host` to `example.com`, then this call will attempt to retrieve
* the DNS SRV record for `_secure-mqtt._tcp.example.com` or
* `_mqtt._tcp.example.com` to discover which actual host to connect to.
*
* May be called before or after <mosquitto_loop_start>.
* DNS SRV support is not usually compiled in to libmosquitto, use of this call
* is not recommended.
*
* Parameters:
* mosq - a valid mosquitto instance.
* host - the hostname or ip address of the broker to connect to.
* host - the hostname to search for an SRV record.
* keepalive - the number of seconds after which the broker should send a PING
* message to the client if no other messages have been exchanged
* in that time.
@ -631,10 +632,6 @@ libmosq_EXPORT int mosquitto_connect_srv(struct mosquitto *mosq, const char *hos
* MOSQ_ERR_SUCCESS - on success.
* MOSQ_ERR_INVAL - if the input parameters were invalid.
* MOSQ_ERR_NOMEM - if an out of memory condition occurred.
*
* Returns:
* MOSQ_ERR_SUCCESS - on success.
* MOSQ_ERR_INVAL - if the input parameters were invalid.
* MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno
* contains the error code, even on Windows.
* Use strerror_r() where available or FormatMessage() on
@ -662,10 +659,6 @@ libmosq_EXPORT int mosquitto_reconnect(struct mosquitto *mosq);
* MOSQ_ERR_SUCCESS - on success.
* MOSQ_ERR_INVAL - if the input parameters were invalid.
* MOSQ_ERR_NOMEM - if an out of memory condition occurred.
*
* Returns:
* MOSQ_ERR_SUCCESS - on success.
* MOSQ_ERR_INVAL - if the input parameters were invalid.
* MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno
* contains the error code, even on Windows.
* Use strerror_r() where available or FormatMessage() on
@ -696,8 +689,8 @@ libmosq_EXPORT int mosquitto_disconnect(struct mosquitto *mosq);
*
* Disconnect from the broker, with attached MQTT properties.
*
* Use <mosquitto_property_add_*> to create a list of properties, then attach
* them to this publish. Properties need freeing with
* Use e.g. <mosquitto_property_add_string> and similar to create a list of
* properties, then attach them to this publish. Properties need freeing with
* <mosquitto_property_free_all>.
*
* Parameters:
@ -768,8 +761,8 @@ libmosq_EXPORT int mosquitto_publish(struct mosquitto *mosq, int *mid, const cha
*
* Publish a message on a given topic, with attached MQTT properties.
*
* Use <mosquitto_property_add_*> to create a list of properties, then attach
* them to this publish. Properties need freeing with
* Use e.g. <mosquitto_property_add_string> and similar to create a list of
* properties, then attach them to this publish. Properties need freeing with
* <mosquitto_property_free_all>.
*
* Requires the mosquitto instance to be connected with MQTT 5.
@ -850,8 +843,8 @@ libmosq_EXPORT int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const c
*
* Subscribe to a topic, with attached MQTT properties.
*
* Use <mosquitto_property_add_*> to create a list of properties, then attach
* them to this subscribe. Properties need freeing with
* Use e.g. <mosquitto_property_add_string> and similar to create a list of
* properties, then attach them to this publish. Properties need freeing with
* <mosquitto_property_free_all>.
*
* Requires the mosquitto instance to be connected with MQTT 5.
@ -867,26 +860,26 @@ libmosq_EXPORT int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const c
* qos - the requested Quality of Service for this subscription.
* options - options to apply to this subscription, OR'd together. 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
* 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
* client.
* MQTT_SUB_OPT_RETAIN_AS_PUBLISHED - with this option set, messages
* MQTT_SUB_OPT_RETAIN_AS_PUBLISHED: with this option set, messages
* published for this subscription will keep the
* retain flag as was set by the publishing client.
* The default behaviour without this option set has
* the retain flag indicating whether a message is
* fresh/stale.
* MQTT_SUB_OPT_SEND_RETAIN_ALWAYS - with this option set,
* MQTT_SUB_OPT_SEND_RETAIN_ALWAYS: with this option set,
* pre-existing retained messages are sent as soon as
* the subscription is made, even if the subscription
* already exists. This is the default behaviour, so
* it is not necessary to set this option.
* MQTT_SUB_OPT_SEND_RETAIN_NEW - with this option set, pre-existing
* MQTT_SUB_OPT_SEND_RETAIN_NEW: with this option set, pre-existing
* retained messages for this subscription will be
* sent when the subscription is made, but only if the
* subscription does not already exist.
* MQTT_SUB_OPT_SEND_RETAIN_NEVER - with this option set,
* MQTT_SUB_OPT_SEND_RETAIN_NEVER: with this option set,
* pre-existing retained messages will never be sent
* for this subscription.
* properties - a valid mosquitto_property list, or NULL.
@ -925,26 +918,26 @@ libmosq_EXPORT int mosquitto_subscribe_v5(struct mosquitto *mosq, int *mid, cons
* 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
* 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
* client.
* MQTT_SUB_OPT_RETAIN_AS_PUBLISHED - with this option set, messages
* MQTT_SUB_OPT_RETAIN_AS_PUBLISHED: with this option set, messages
* published for this subscription will keep the
* retain flag as was set by the publishing client.
* The default behaviour without this option set has
* the retain flag indicating whether a message is
* fresh/stale.
* MQTT_SUB_OPT_SEND_RETAIN_ALWAYS - with this option set,
* MQTT_SUB_OPT_SEND_RETAIN_ALWAYS: with this option set,
* pre-existing retained messages are sent as soon as
* the subscription is made, even if the subscription
* already exists. This is the default behaviour, so
* it is not necessary to set this option.
* MQTT_SUB_OPT_SEND_RETAIN_NEW - with this option set, pre-existing
* MQTT_SUB_OPT_SEND_RETAIN_NEW: with this option set, pre-existing
* retained messages for this subscription will be
* sent when the subscription is made, but only if the
* subscription does not already exist.
* MQTT_SUB_OPT_SEND_RETAIN_NEVER - with this option set,
* MQTT_SUB_OPT_SEND_RETAIN_NEVER: with this option set,
* pre-existing retained messages will never be sent
* for this subscription.
* properties - a valid mosquitto_property list, or NULL. Only used with MQTT
@ -990,6 +983,10 @@ libmosq_EXPORT int mosquitto_unsubscribe(struct mosquitto *mosq, int *mid, const
*
* Unsubscribe from a topic, with attached MQTT properties.
*
* Use e.g. <mosquitto_property_add_string> and similar to create a list of
* properties, then attach them to this publish. Properties need freeing with
* <mosquitto_property_free_all>.
*
* Parameters:
* mosq - a valid mosquitto instance.
* mid - a pointer to an int. If not NULL, the function will set this to
@ -1101,52 +1098,16 @@ libmosq_EXPORT void mosquitto_message_free_contents(struct mosquitto_message *me
*
* Section: Network loop (managed by libmosquitto)
*
* The internal network loop must be called at a regular interval. The two
* recommended approaches are to use either <mosquitto_loop_forever> or
* <mosquitto_loop_start>. <mosquitto_loop_forever> is a blocking call and is
* suitable for the situation where you only want to handle incoming messages
* in callbacks. <mosquitto_loop_start> is a non-blocking call, it creates a
* separate thread to run the loop for you. Use this function when you have
* other tasks you need to run at the same time as the MQTT client, e.g.
* reading data from a sensor.
*
* ====================================================================== */
/*
* Function: mosquitto_loop
*
* The main network loop for the client. You must call this frequently in order
* to keep communications between the client and broker working. If incoming
* data is present it will then be processed. Outgoing commands, from e.g.
* <mosquitto_publish>, are normally sent immediately that their function is
* called, but this is not always possible. <mosquitto_loop> will also attempt
* to send any remaining outgoing messages, which also includes commands that
* are part of the flow for messages with QoS>0.
*
* An alternative approach is to use <mosquitto_loop_start> to run the client
* loop in its own thread.
*
* This calls select() to monitor the client network socket. If you want to
* integrate mosquitto client operation with your own select() call, use
* <mosquitto_socket>, <mosquitto_loop_read>, <mosquitto_loop_write> and
* <mosquitto_loop_misc>.
*
* Threads:
*
* Parameters:
* mosq - a valid mosquitto instance.
* timeout - Maximum number of milliseconds to wait for network activity
* in the select() call before timing out. Set to 0 for instant
* return. Set negative to use the default of 1000ms.
* max_packets - this parameter is currently unused and should be set to 1 for
* future compatibility.
*
* Returns:
* MOSQ_ERR_SUCCESS - on success.
* MOSQ_ERR_INVAL - if the input parameters were invalid.
* MOSQ_ERR_NOMEM - if an out of memory condition occurred.
* MOSQ_ERR_NO_CONN - if the client isn't connected to a broker.
* MOSQ_ERR_CONN_LOST - if the connection to the broker was lost.
* MOSQ_ERR_PROTOCOL - if there is a protocol error communicating with the
* broker.
* MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno
* contains the error code, even on Windows.
* Use strerror_r() where available or FormatMessage() on
* Windows.
* See Also:
* <mosquitto_loop_forever>, <mosquitto_loop_start>, <mosquitto_loop_stop>
*/
libmosq_EXPORT int mosquitto_loop(struct mosquitto *mosq, int timeout, int max_packets);
/*
* Function: mosquitto_loop_forever
@ -1228,6 +1189,52 @@ libmosq_EXPORT int mosquitto_loop_start(struct mosquitto *mosq);
*/
libmosq_EXPORT int mosquitto_loop_stop(struct mosquitto *mosq, bool force);
/*
* Function: mosquitto_loop
*
* The main network loop for the client. This must be called frequently
* to keep communications between the client and broker working. This is
* carried out by <mosquitto_loop_forever> and <mosquitto_loop_start>, which
* are the recommended ways of handling the network loop. You may also use this
* function if you wish. It must not be called inside a callback.
*
* If incoming data is present it will then be processed. Outgoing commands,
* from e.g. <mosquitto_publish>, are normally sent immediately that their
* function is called, but this is not always possible. <mosquitto_loop> will
* also attempt to send any remaining outgoing messages, which also includes
* commands that are part of the flow for messages with QoS>0.
*
* This calls select() to monitor the client network socket. If you want to
* integrate mosquitto client operation with your own select() call, use
* <mosquitto_socket>, <mosquitto_loop_read>, <mosquitto_loop_write> and
* <mosquitto_loop_misc>.
*
* Threads:
*
* Parameters:
* mosq - a valid mosquitto instance.
* timeout - Maximum number of milliseconds to wait for network activity
* in the select() call before timing out. Set to 0 for instant
* return. Set negative to use the default of 1000ms.
* max_packets - this parameter is currently unused and should be set to 1 for
* future compatibility.
*
* Returns:
* MOSQ_ERR_SUCCESS - on success.
* MOSQ_ERR_INVAL - if the input parameters were invalid.
* MOSQ_ERR_NOMEM - if an out of memory condition occurred.
* MOSQ_ERR_NO_CONN - if the client isn't connected to a broker.
* MOSQ_ERR_CONN_LOST - if the connection to the broker was lost.
* MOSQ_ERR_PROTOCOL - if there is a protocol error communicating with the
* broker.
* MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno
* contains the error code, even on Windows.
* Use strerror_r() where available or FormatMessage() on
* Windows.
* See Also:
* <mosquitto_loop_forever>, <mosquitto_loop_start>, <mosquitto_loop_stop>
*/
libmosq_EXPORT int mosquitto_loop(struct mosquitto *mosq, int timeout, int max_packets);
/* ======================================================================
*
@ -1302,7 +1309,8 @@ libmosq_EXPORT int mosquitto_loop_write(struct mosquitto *mosq, int max_packets)
* monitoring the client network socket for activity yourself.
*
* This function deals with handling PINGs and checking whether messages need
* to be retried, so should be called fairly frequently.
* to be retried, so should be called fairly frequently, around once per second
* is sufficient.
*
* Parameters:
* mosq - a valid mosquitto instance.
@ -1424,12 +1432,12 @@ libmosq_EXPORT int mosquitto_opts_set(struct mosquitto *mosq, enum mosq_opt_t op
* value - the option specific value.
*
* Options:
* MOSQ_OPT_PROTOCOL_VERSION
* MOSQ_OPT_PROTOCOL_VERSION -
* Value must be set to either MQTT_PROTOCOL_V31,
* MQTT_PROTOCOL_V311, or MQTT_PROTOCOL_V5. Must be set before the
* client connects. Defaults to MQTT_PROTOCOL_V311.
*
* MOSQ_OPT_RECEIVE_MAXIMUM
* MOSQ_OPT_RECEIVE_MAXIMUM -
* Value can be set between 1 and 65535 inclusive, and represents
* the maximum number of incoming QoS 1 and QoS 2 messages that this
* client wants to process at once. Defaults to 20. This option is
@ -1439,7 +1447,7 @@ libmosq_EXPORT int mosquitto_opts_set(struct mosquitto *mosq, enum mosq_opt_t op
* will override this option. Using this option is the recommended
* method however.
*
* MOSQ_OPT_SEND_MAXIMUM
* MOSQ_OPT_SEND_MAXIMUM -
* Value can be set between 1 and 65535 inclusive, and represents
* the maximum number of outgoing QoS 1 and QoS 2 messages that this
* client will attempt to have "in flight" at once. Defaults to 20.
@ -1448,7 +1456,7 @@ libmosq_EXPORT int mosquitto_opts_set(struct mosquitto *mosq, enum mosq_opt_t op
* MQTT_PROP_RECEIVE_MAXIMUM property that has a lower value than
* this option, then the broker provided value will be used.
*
* MOSQ_OPT_SSL_CTX_WITH_DEFAULTS
* MOSQ_OPT_SSL_CTX_WITH_DEFAULTS -
* If value is set to a non zero value, then the user specified
* SSL_CTX passed in using MOSQ_OPT_SSL_CTX will have the default
* options applied to it. This means that you only need to change
@ -1457,7 +1465,8 @@ libmosq_EXPORT int mosquitto_opts_set(struct mosquitto *mosq, enum mosq_opt_t op
* use <mosquitto_tls_set> to configure the cafile/capath as a
* minimum.
* This option is only available for openssl 1.1.0 and higher.
* MOSQ_OPT_TLS_OCSP_REQUIRED
*
* MOSQ_OPT_TLS_OCSP_REQUIRED -
* Set whether OCSP checking on TLS connections is required. Set to
* 1 to enable checking, or 0 (the default) for no checking.
*/
@ -1475,7 +1484,7 @@ libmosq_EXPORT int mosquitto_int_option(struct mosquitto *mosq, enum mosq_opt_t
* value - the option specific value.
*
* Options:
* MOSQ_OPT_SSL_CTX
* MOSQ_OPT_SSL_CTX -
* Pass an openssl SSL_CTX to be used when creating TLS connections
* rather than libmosquitto creating its own. This must be called
* before connecting to have any effect. If you use this option, the
@ -2216,26 +2225,26 @@ libmosq_EXPORT int mosquitto_string_to_command(const char *str, int *cmd);
*
* For example:
*
* subtopic: "a/deep/topic/hierarchy"
* subtopic: "a/deep/topic/hierarchy"
*
* Would result in:
* Would result in:
*
* topics[0] = "a"
* topics[1] = "deep"
* topics[2] = "topic"
* topics[3] = "hierarchy"
* topics[0] = "a"
* topics[1] = "deep"
* topics[2] = "topic"
* topics[3] = "hierarchy"
*
* and:
* and:
*
* subtopic: "/a/deep/topic/hierarchy/"
* subtopic: "/a/deep/topic/hierarchy/"
*
* Would result in:
* Would result in:
*
* topics[0] = NULL
* topics[1] = "a"
* topics[2] = "deep"
* topics[3] = "topic"
* topics[4] = "hierarchy"
* topics[0] = NULL
* topics[1] = "a"
* topics[2] = "deep"
* topics[3] = "topic"
* topics[4] = "hierarchy"
*
* Parameters:
* subtopic - the subscription/topic to tokenise
@ -2284,6 +2293,29 @@ libmosq_EXPORT int mosquitto_sub_topic_tokens_free(char ***topics, int count);
/*
* Function: mosquitto_topic_matches_sub
*
* Check whether a topic matches a subscription.
*
* For example:
*
* foo/bar would match the subscription foo/# or +/bar
* non/matching would not match the subscription non/+/+
*
* Parameters:
* sub - subscription string to check topic against.
* topic - topic to check.
* result - bool pointer to hold result. Will be set to true if the topic
* matches the subscription.
*
* Returns:
* MOSQ_ERR_SUCCESS - on success
* MOSQ_ERR_INVAL - if the input parameters were invalid.
* MOSQ_ERR_NOMEM - if an out of memory condition occurred.
*/
libmosq_EXPORT int mosquitto_topic_matches_sub(const char *sub, const char *topic, bool *result);
/*
* Function: mosquitto_topic_matches_sub2
*
* Check whether a topic matches a subscription.
@ -2303,10 +2335,9 @@ libmosq_EXPORT int mosquitto_sub_topic_tokens_free(char ***topics, int count);
*
* Returns:
* MOSQ_ERR_SUCCESS - on success
* MOSQ_ERR_INVAL - if the input parameters were invalid.
* MOSQ_ERR_NOMEM - if an out of memory condition occurred.
* MOSQ_ERR_INVAL - if the input parameters were invalid.
* MOSQ_ERR_NOMEM - if an out of memory condition occurred.
*/
libmosq_EXPORT int mosquitto_topic_matches_sub(const char *sub, const char *topic, bool *result);
libmosq_EXPORT int mosquitto_topic_matches_sub2(const char *sub, size_t sublen, const char *topic, size_t topiclen, bool *result);
/*
@ -2323,6 +2354,31 @@ libmosq_EXPORT int mosquitto_topic_matches_sub2(const char *sub, size_t sublen,
*
* Parameters:
* topic - the topic to check
*
* Returns:
* MOSQ_ERR_SUCCESS - for a valid topic
* MOSQ_ERR_INVAL - if the topic contains a + or a #, or if it is too long.
* MOSQ_ERR_MALFORMED_UTF8 - if sub or topic is not valid UTF-8
*
* See Also:
* <mosquitto_sub_topic_check>
*/
libmosq_EXPORT int mosquitto_pub_topic_check(const char *topic);
/*
* Function: mosquitto_pub_topic_check2
*
* Check whether a topic to be used for publishing is valid.
*
* This searches for + or # in a topic and checks its length.
*
* This check is already carried out in <mosquitto_publish> and
* <mosquitto_will_set>, there is no need to call it directly before them. It
* may be useful if you wish to check the validity of a topic in advance of
* making a connection for example.
*
* Parameters:
* topic - the topic to check
* topiclen - length of the topic in bytes
*
* Returns:
@ -2333,7 +2389,6 @@ libmosq_EXPORT int mosquitto_topic_matches_sub2(const char *sub, size_t sublen,
* See Also:
* <mosquitto_sub_topic_check>
*/
libmosq_EXPORT int mosquitto_pub_topic_check(const char *topic);
libmosq_EXPORT int mosquitto_pub_topic_check2(const char *topic, size_t topiclen);
/*
@ -2352,6 +2407,34 @@ libmosq_EXPORT int mosquitto_pub_topic_check2(const char *topic, size_t topiclen
*
* Parameters:
* topic - the topic to check
*
* Returns:
* MOSQ_ERR_SUCCESS - for a valid topic
* MOSQ_ERR_INVAL - if the topic contains a + or a # that is in an
* invalid position, or if it is too long.
* MOSQ_ERR_MALFORMED_UTF8 - if topic is not valid UTF-8
*
* See Also:
* <mosquitto_sub_topic_check>
*/
libmosq_EXPORT int mosquitto_sub_topic_check(const char *topic);
/*
* Function: mosquitto_sub_topic_check2
*
* Check whether a topic to be used for subscribing is valid.
*
* This searches for + or # in a topic and checks that they aren't in invalid
* positions, such as with foo/#/bar, foo/+bar or foo/bar#, and checks its
* length.
*
* This check is already carried out in <mosquitto_subscribe> and
* <mosquitto_unsubscribe>, there is no need to call it directly before them.
* It may be useful if you wish to check the validity of a topic in advance of
* making a connection for example.
*
* Parameters:
* topic - the topic to check
* topiclen - the length in bytes of the topic
*
* Returns:
@ -2363,10 +2446,34 @@ libmosq_EXPORT int mosquitto_pub_topic_check2(const char *topic, size_t topiclen
* See Also:
* <mosquitto_sub_topic_check>
*/
libmosq_EXPORT int mosquitto_sub_topic_check(const char *topic);
libmosq_EXPORT int mosquitto_sub_topic_check2(const char *topic, size_t topiclen);
/*
* Function: mosquitto_validate_utf8
*
* Helper function to validate whether a UTF-8 string is valid, according to
* the UTF-8 spec and the MQTT additions.
*
* Parameters:
* str - a string to check
* len - the length of the string in bytes
*
* Returns:
* MOSQ_ERR_SUCCESS - on success
* MOSQ_ERR_INVAL - if str is NULL or len<0 or len>65536
* MOSQ_ERR_MALFORMED_UTF8 - if str is not valid UTF-8
*/
libmosq_EXPORT int mosquitto_validate_utf8(const char *str, int len);
/* =============================================================================
*
* Section: One line client helper functions
*
* =============================================================================
*/
struct libmosquitto_will {
char *topic;
void *payload;
@ -2497,24 +2604,6 @@ libmosq_EXPORT int mosquitto_subscribe_callback(
const struct libmosquitto_tls *tls);
/*
* Function: mosquitto_validate_utf8
*
* Helper function to validate whether a UTF-8 string is valid, according to
* the UTF-8 spec and the MQTT additions.
*
* Parameters:
* str - a string to check
* len - the length of the string in bytes
*
* Returns:
* MOSQ_ERR_SUCCESS - on success
* MOSQ_ERR_INVAL - if str is NULL or len<0 or len>65536
* MOSQ_ERR_MALFORMED_UTF8 - if str is not valid UTF-8
*/
libmosq_EXPORT int mosquitto_validate_utf8(const char *str, int len);
/* =============================================================================
*
* Section: Properties

View File

@ -909,7 +909,6 @@ ssize_t net__read(struct mosquitto *mosq, void *buf, size_t count)
errno = 0;
#ifdef WITH_TLS
if(mosq->ssl){
ERR_clear_error();
ret = SSL_read(mosq->ssl, buf, count);
if(ret <= 0){
err = SSL_get_error(mosq->ssl, ret);
@ -924,6 +923,7 @@ ssize_t net__read(struct mosquitto *mosq, void *buf, size_t count)
net__print_ssl_error(mosq);
errno = EPROTO;
}
ERR_clear_error();
#ifdef WIN32
WSASetLastError(errno);
#endif
@ -957,7 +957,6 @@ ssize_t net__write(struct mosquitto *mosq, void *buf, size_t count)
#ifdef WITH_TLS
if(mosq->ssl){
mosq->want_write = false;
ERR_clear_error();
ret = SSL_write(mosq->ssl, buf, count);
if(ret < 0){
err = SSL_get_error(mosq->ssl, ret);
@ -972,6 +971,7 @@ ssize_t net__write(struct mosquitto *mosq, void *buf, size_t count)
net__print_ssl_error(mosq);
errno = EPROTO;
}
ERR_clear_error();
#ifdef WIN32
WSASetLastError(errno);
#endif

View File

@ -11,492 +11,12 @@
<refnamediv>
<refname>libmosquitto</refname>
<refpurpose>MQTT version 3.1.1 client library</refpurpose>
<refpurpose>MQTT version 5.0/3.1.1 client library</refpurpose>
</refnamediv>
<refsect1>
<title>Description</title>
<para>This is an overview of how to use libmosquitto to create MQTT
aware client programs. There may be separate man pages on each of the
functions described here in the future.</para>
<para>This man page is woefully incomplete, please see the comments
in mosquitto.h for missing functions and a description of the
functions.</para>
</refsect1>
<refsect1>
<title>libmosquitto symbol names</title>
<para>All public functions in libmosquitto have the prefix
"mosquitto_". Any other functions defined in the source code are to be
treated as private functions and may change between any release. Do not
use these functions!</para>
</refsect1>
<refsect1>
<title>Functions</title>
<refsect2>
<title>Library version</title>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_lib_version</function></funcdef>
<paramdef>int *<parameter>major</parameter></paramdef>
<paramdef>int *<parameter>minor</parameter></paramdef>
<paramdef>int *<parameter>revision</parameter></paramdef>
</funcprototype></funcsynopsis>
<para>Obtain version information about the library. If any of
major, minor or revision are not NULL they will return the
corresponding version numbers. The return value is an integer
representation of the complete version number (e.g. 1009001 for 1.9.1)
that can be used for comparisons.</para>
</refsect2>
<refsect2>
<title>Library initialisation and cleanup</title>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_lib_init</function></funcdef>
<void/></funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_lib_cleanup</function></funcdef>
<void/></funcprototype></funcsynopsis>
<para>Call mosquitto_lib_init() before using any of the other
library functions and mosquitto_lib_cleanup() after finishing
with the library.</para>
</refsect2>
<refsect2>
<title>Client constructor/destructor</title>
<funcsynopsis><funcprototype><funcdef>struct mosquitto *<function>mosquitto_new</function></funcdef>
<paramdef>const char *<parameter>id</parameter></paramdef>
<paramdef>bool <parameter>clean_session</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype></funcsynopsis>
<para>Create a new mosquitto client instance.</para>
<funcsynopsis><funcprototype><funcdef>void <function>mosquitto_destroy</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
</funcprototype></funcsynopsis>
<para>Use to free memory associated with a mosquitto client instance.</para>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_reinitialise</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>const char *<parameter>id</parameter></paramdef>
<paramdef>bool <parameter>clean_session</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype></funcsynopsis>
</refsect2>
<refsect2>
<title>Authentication and encryption</title>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_username_pw_set</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>const char *<parameter>username</parameter></paramdef>
<paramdef>const char *<parameter>password</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_tls_set</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>const char *<parameter>cafile</parameter></paramdef>
<paramdef>const char *<parameter>capath</parameter></paramdef>
<paramdef>const char *<parameter>certfile</parameter></paramdef>
<paramdef>const char *<parameter>keyfile</parameter></paramdef>
<paramdef>int <parameter>(*pw_callback)(char *buf, int size, int rwflag, void *userdata)</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_tls_opts_set</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>int <parameter>cert_reqs</parameter></paramdef>
<paramdef>const char *<parameter>tls_version</parameter></paramdef>
<paramdef>const char *<parameter>ciphers</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_tls_insecure_set</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>bool <parameter>value</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_tls_psk_set</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>const char *<parameter>psk</parameter></paramdef>
<paramdef>const char *<parameter>identity</parameter></paramdef>
<paramdef>const char *<parameter>ciphers</parameter></paramdef>
</funcprototype></funcsynopsis>
</refsect2>
<refsect2>
<title>Wills</title>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_will_set</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>const char *<parameter>topic</parameter></paramdef>
<paramdef>int <parameter>payloadlen</parameter></paramdef>
<paramdef>const void *<parameter>payload</parameter></paramdef>
<paramdef>int <parameter>qos</parameter></paramdef>
<paramdef>bool <parameter>retain</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_will_clear</function></funcdef>
<paramdef><parameter>struct mosquitto *mosq</parameter></paramdef>
</funcprototype></funcsynopsis>
</refsect2>
<refsect2>
<title>Connect/disconnect</title>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_connect</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>const char *<parameter>host</parameter></paramdef>
<paramdef>int <parameter>port</parameter></paramdef>
<paramdef>int <parameter>keepalive</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_connect_bind</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>const char *<parameter>host</parameter></paramdef>
<paramdef>int <parameter>port</parameter></paramdef>
<paramdef>int <parameter>keepalive</parameter></paramdef>
<paramdef>const char *<parameter>bind_address</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_connect_async</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>const char *<parameter>host</parameter></paramdef>
<paramdef>int <parameter>port</parameter></paramdef>
<paramdef>int <parameter>keepalive</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_connect_bind_async</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>const char *<parameter>host</parameter></paramdef>
<paramdef>int <parameter>port</parameter></paramdef>
<paramdef>int <parameter>keepalive</parameter></paramdef>
<paramdef>const char *<parameter>bind_address</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_reconnect</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_reconnect_async</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_disconnect</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
</funcprototype></funcsynopsis>
</refsect2>
<refsect2>
<title>Publish</title>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_publish</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>int *<parameter>mid</parameter></paramdef>
<paramdef>const char *<parameter>topic</parameter></paramdef>
<paramdef>int <parameter>payloadlen</parameter></paramdef>
<paramdef>const void *<parameter>payload</parameter></paramdef>
<paramdef>int <parameter>qos</parameter></paramdef>
<paramdef>bool <parameter>retain</parameter></paramdef>
</funcprototype></funcsynopsis>
</refsect2>
<refsect2>
<title>Subscribe/unsubscribe</title>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_subscribe</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>int *<parameter>mid</parameter></paramdef>
<paramdef>const char *<parameter>sub</parameter></paramdef>
<paramdef>int <parameter>qos</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_unsubscribe</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>int *<parameter>mid</parameter></paramdef>
<paramdef>const char *<parameter>sub</parameter></paramdef>
</funcprototype></funcsynopsis>
</refsect2>
<refsect2>
<title>Network loop</title>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_loop</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>int <parameter>timeout</parameter></paramdef>
<paramdef>int <parameter>max_packets</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_loop_read</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>int <parameter>max_packets</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_loop_write</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>int <parameter>max_packets</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_loop_misc</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_loop_forever</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>int <parameter>timeout</parameter></paramdef>
<paramdef>int <parameter>max_packets</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_socket</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>bool <function>mosquitto_want_write</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
</funcprototype></funcsynopsis>
</refsect2>
<refsect2>
<title>Threaded network loop</title>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_loop_start</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_loop_stop</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>bool <parameter>force</parameter></paramdef>
</funcprototype></funcsynopsis>
</refsect2>
<refsect2>
<title>Misc client functions</title>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_max_inflight_messages_set</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>unsigned int <parameter>max_inflight_messages</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_reconnect_delay_set</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>unsigned int <parameter>reconnect_delay</parameter></paramdef>
<paramdef>unsigned int <parameter>reconnect_delay_max</parameter></paramdef>
<paramdef>bool <parameter>reconnect_exponential_backoff</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_user_data_set</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype></funcsynopsis>
</refsect2>
<refsect2>
<title>Callbacks</title>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_connect_callback_set</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>void <parameter>(*on_connect)(struct mosquitto *, void *, int)</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_disconnect_callback_set</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>void <parameter>(*on_disconnect)(struct mosquitto *, void *, int)</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_publish_callback_set</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>void <parameter>(*on_publish)(struct mosquitto *, void *, int)</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_message_callback_set</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>void <parameter>(*on_message)(struct mosquitto *, void *, const struct mosquitto_message *)</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_subscribe_callback_set</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>void <parameter>(*on_subscribe)(struct mosquitto *, void *, int, int, const int *)</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_unsubscribe_callback_set</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>void <parameter>(*on_unsubscribe)(struct mosquitto *, void *, int)</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_log_callback_set</function></funcdef>
<paramdef>struct mosquitto *<parameter>mosq</parameter></paramdef>
<paramdef>void <parameter>(*on_unsubscribe)(struct mosquitto *, void *, int, const char *)</parameter></paramdef>
</funcprototype></funcsynopsis>
</refsect2>
<refsect2>
<title>Utility functions</title>
<funcsynopsis><funcprototype><funcdef>const char *<function>mosquitto_connack_string</function></funcdef>
<paramdef>int <parameter>connack_code</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_message_copy</function></funcdef>
<paramdef>struct mosquitto_message *<parameter>dst</parameter></paramdef>
<paramdef>const struct mosquitto_message *<parameter>src</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_message_free</function></funcdef>
<paramdef>struct mosquitto_message **<parameter>message</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>const char *<function>mosquitto_strerror</function></funcdef>
<paramdef>int <parameter>mosq_errno</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_sub_topic_tokenise</function></funcdef>
<paramdef>const char *<parameter>subtopic</parameter></paramdef>
<paramdef>char ***<parameter>topics</parameter></paramdef>
<paramdef>int *<parameter>count</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_sub_topic_tokens_free</function></funcdef>
<paramdef>char ***<parameter>topics</parameter></paramdef>
<paramdef>int <parameter>count</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_topic_matches_sub</function></funcdef>
<paramdef>const char *<parameter>sub</parameter></paramdef>
<paramdef>const char *<parameter>topic</parameter></paramdef>
<paramdef>bool *<parameter>result</parameter></paramdef>
</funcprototype></funcsynopsis>
</refsect2>
<refsect2>
<title>Helper functions</title>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_subscribe_simple</function></funcdef>
<paramdef>struct mosquitto_message **<parameter>message</parameter></paramdef>
<paramdef>int <parameter>msg_count</parameter></paramdef>
<paramdef>bool <parameter>want_retained</parameter></paramdef>
<paramdef>const char *<parameter>topic</parameter></paramdef>
<paramdef>int<parameter>qos</parameter></paramdef>
<paramdef>const char *<parameter>host</parameter></paramdef>
<paramdef>int <parameter>port</parameter></paramdef>
<paramdef>const char *<parameter>client_id</parameter></paramdef>
<paramdef>int <parameter>keepalive</parameter></paramdef>
<paramdef>bool <parameter>clean_session</parameter></paramdef>
<paramdef>const char *<parameter>username</parameter></paramdef>
<paramdef>const char *<parameter>password</parameter></paramdef>
<paramdef>const struct libmosquitto_will *<parameter>will</parameter></paramdef>
<paramdef>const struct libmosquitto_tls *<parameter>tls</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype><funcdef>int <function>mosquitto_subscribe_callback</function></funcdef>
<paramdef>int <parameter>(*callback)(struct mosquitto *, void *, const struct mosquitto_message *)</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
<paramdef>const char *<parameter>topic</parameter></paramdef>
<paramdef>int <parameter>qos</parameter></paramdef>
<paramdef>const char *<parameter>host</parameter></paramdef>
<paramdef>int <parameter>port</parameter></paramdef>
<paramdef>const char *<parameter>client_id</parameter></paramdef>
<paramdef>int <parameter>keepalive</parameter></paramdef>
<paramdef>bool <parameter>clean_session</parameter></paramdef>
<paramdef>const char *<parameter>username</parameter></paramdef>
<paramdef>const char *<parameter>password</parameter></paramdef>
<paramdef>const struct libmosquitto_will *<parameter>will</parameter></paramdef>
<paramdef>const struct libmosquitto_tls *<parameter>tls</parameter></paramdef>
</funcprototype></funcsynopsis>
</refsect2>
</refsect1>
<refsect1>
<title>Examples</title>
<para><programlisting language="C">
#include &lt;stdio.h&gt;
#include &lt;mosquitto.h&gt;
void my_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message)
{
if(message->payloadlen){
printf("%s %s\n", message->topic, message->payload);
}else{
printf("%s (null)\n", message->topic);
}
fflush(stdout);
}
void my_connect_callback(struct mosquitto *mosq, void *userdata, int result)
{
int i;
if(!result){
/* Subscribe to broker information topics on successful connect. */
mosquitto_subscribe(mosq, NULL, "$SYS/#", 2);
}else{
fprintf(stderr, "Connect failed\n");
}
}
void my_subscribe_callback(struct mosquitto *mosq, void *userdata, int mid, int qos_count, const int *granted_qos)
{
int i;
printf("Subscribed (mid: %d): %d", mid, granted_qos[0]);
for(i=1; i&lt;qos_count; i++){
printf(", %d", granted_qos[i]);
}
printf("\n");
}
void my_log_callback(struct mosquitto *mosq, void *userdata, int level, const char *str)
{
/* Pring all log messages regardless of level. */
printf("%s\n", str);
}
int main(int argc, char *argv[])
{
int i;
char *host = "localhost";
int port = 1883;
int keepalive = 60;
bool clean_session = true;
struct mosquitto *mosq = NULL;
mosquitto_lib_init();
mosq = mosquitto_new(NULL, clean_session, NULL);
if(!mosq){
fprintf(stderr, "Error: Out of memory.\n");
return 1;
}
mosquitto_log_callback_set(mosq, my_log_callback);
mosquitto_connect_callback_set(mosq, my_connect_callback);
mosquitto_message_callback_set(mosq, my_message_callback);
mosquitto_subscribe_callback_set(mosq, my_subscribe_callback);
if(mosquitto_connect(mosq, host, port, keepalive)){
fprintf(stderr, "Unable to connect.\n");
return 1;
}
mosquitto_loop_forever(mosq, -1, 1);
mosquitto_destroy(mosq);
mosquitto_lib_cleanup();
return 0;
}
</programlisting></para>
</refsect1>
<refsect1>
<title>See Also</title>
<simplelist type="inline">
<member>
<citerefentry>
<refentrytitle><link xlink:href="mosquitto-8.html">mosquitto</link></refentrytitle>
<manvolnum>8</manvolnum>
</citerefentry>
<citerefentry>
<refentrytitle><link xlink:href="mqtt-7.html">mqtt</link></refentrytitle>
<manvolnum>7</manvolnum>
</citerefentry>
</member>
</simplelist>
<title>Documentation</title>
<para>See <ulink url="https://mosquitto.org/api/"/></para>
</refsect1>
<refsect1>

View File

@ -339,7 +339,7 @@
<term><option>-l</option></term>
<term><option>--stdin-line</option></term>
<listitem>
<para>Send messages read from stdin, splitting separate lines into separate messages. Note that blank lines won't be sent.</para>
<para>Send messages read from stdin, splitting separate lines into separate messages.</para>
</listitem>
</varlistentry>
<varlistentry>

View File

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

View File

@ -1,5 +1,5 @@
name: mosquitto
version: 1.6.7
version: 1.6.8
summary: Eclipse Mosquitto MQTT broker
description: This is a message broker that supports version 3.1 and 3.1.1 of the MQTT
protocol.
@ -16,18 +16,23 @@ apps:
command: launcher.sh
daemon: simple
restart-condition: always
plugs: [network, network-bind]
plugs: [home, network, network-bind]
pub:
command: usr/bin/mosquitto_pub
plugs: [network]
plugs: [home, network]
rr:
command: usr/bin/mosquitto_rr
plugs: [home, network]
sub:
command: usr/bin/mosquitto_sub
plugs: [network]
plugs: [home, network]
passwd:
command: usr/bin/mosquitto_passwd
plugs: [home]
parts:
@ -64,6 +69,7 @@ parts:
prime:
- usr/sbin/mosquitto
- usr/bin/mosquitto_pub
- usr/bin/mosquitto_rr
- usr/bin/mosquitto_sub
- usr/bin/mosquitto_passwd
- usr/lib/libmosquitto.so*

View File

@ -271,6 +271,7 @@ void config__init(struct mosquitto_db *db, struct mosquitto__config *config)
config->default_listener.max_connections = -1;
config->default_listener.protocol = mp_mqtt;
config->default_listener.security_options.allow_anonymous = -1;
config->default_listener.security_options.allow_zero_length_clientid = true;
config->default_listener.maximum_qos = 2;
config->default_listener.max_topic_alias = 10;
}
@ -474,6 +475,7 @@ int config__parse_args(struct mosquitto_db *db, struct mosquitto__config *config
|| config->default_listener.security_options.psk_file
|| config->default_listener.security_options.auth_plugin_config_count
|| config->default_listener.security_options.allow_anonymous != -1
|| config->default_listener.security_options.allow_zero_length_clientid != true
){
config->listener_count++;
@ -532,6 +534,7 @@ int config__parse_args(struct mosquitto_db *db, struct mosquitto__config *config
config->listeners[config->listener_count-1].security_options.auth_plugin_configs = config->default_listener.security_options.auth_plugin_configs;
config->listeners[config->listener_count-1].security_options.auth_plugin_config_count = config->default_listener.security_options.auth_plugin_config_count;
config->listeners[config->listener_count-1].security_options.allow_anonymous = config->default_listener.security_options.allow_anonymous;
config->listeners[config->listener_count-1].security_options.allow_zero_length_clientid = config->default_listener.security_options.allow_zero_length_clientid;
}
/* Default to drop to mosquitto user if we are privileged and no user specified. */
@ -641,6 +644,7 @@ int config__read(struct mosquitto_db *db, struct mosquitto__config *config, bool
config__init_reload(db, &config_reload);
config_reload.listeners = config->listeners;
config_reload.listener_count = config->listener_count;
cur_security_options = NULL;
rc = config__read_file(&config_reload, reload, db->config_file, &cr, 0, &lineno);
}else{
rc = config__read_file(config, reload, db->config_file, &cr, 0, &lineno);
@ -1441,6 +1445,7 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct
}
cur_listener->security_options.allow_anonymous = -1;
cur_listener->security_options.allow_zero_length_clientid = true;
cur_listener->protocol = mp_mqtt;
cur_listener->port = tmp_int;
cur_listener->maximum_qos = 2;

View File

@ -201,8 +201,11 @@ void context__disconnect(struct mosquitto_db *db, struct mosquitto *context)
context__send_will(db, context);
if(context->session_expiry_interval == 0){
if(context->bridge == NULL){
/* Client session is due to be expired now */
#ifdef WITH_BRIDGE
if(context->bridge == NULL)
#endif
{
if(context->will_delay_interval == 0){
/* This will be done later, after the will is published for delay>0. */
context__add_to_disused(db, context);

View File

@ -160,6 +160,9 @@ int connect__on_authorised(struct mosquitto_db *db, struct mosquitto *context, v
}
}
if(context->clean_start == true){
sub__clean_session(db, found_context);
}
session_expiry__remove(found_context);
will_delay__remove(found_context);
will__clear(found_context);

View File

@ -126,7 +126,6 @@ int mosquitto_main_loop(struct mosquitto_db *db, mosq_sock_t *listensock, int li
#endif
int i;
#ifdef WITH_EPOLL
int rc;
int j;
struct epoll_event ev, events[MAX_EVENTS];
#else
@ -134,8 +133,9 @@ int mosquitto_main_loop(struct mosquitto_db *db, mosq_sock_t *listensock, int li
int pollfd_index;
int pollfd_max;
#endif
time_t expiration_check_time = 0;
char *id;
#ifdef WITH_BRIDGE
int rc;
#endif
#if defined(WITH_WEBSOCKETS) && LWS_LIBRARY_VERSION_NUMBER == 3002000
@ -165,10 +165,6 @@ int mosquitto_main_loop(struct mosquitto_db *db, mosq_sock_t *listensock, int li
}
#endif
if(db->config->persistent_client_expiration > 0){
expiration_check_time = time(NULL) + 3600;
}
#ifdef WITH_EPOLL
db->epollfd = 0;
if ((db->epollfd = epoll_create(MAX_EVENTS)) == -1) {
@ -286,32 +282,6 @@ int mosquitto_main_loop(struct mosquitto_db *db, mosq_sock_t *listensock, int li
# endif
#endif
now = time(NULL);
if(db->config->persistent_client_expiration > 0 && now > expiration_check_time){
HASH_ITER(hh_id, db->contexts_by_id, context, ctxt_tmp){
if(context->sock == INVALID_SOCKET && context->session_expiry_interval > 0 && context->session_expiry_interval != UINT32_MAX){
/* This is a persistent client, check to see if the
* last time it connected was longer than
* persistent_client_expiration seconds ago. If so,
* expire it and clean up.
*/
if(now > context->session_expiry_time){
if(context->id){
id = context->id;
}else{
id = "<unknown>";
}
log__printf(NULL, MOSQ_LOG_NOTICE, "Expiring persistent client %s due to timeout.", id);
G_CLIENTS_EXPIRED_INC();
context->session_expiry_interval = 0;
mosquitto__set_state(context, mosq_cs_expiring);
do_disconnect(db, context, MOSQ_ERR_SUCCESS);
}
}
}
expiration_check_time = time(NULL) + 3600;
}
#ifndef WIN32
sigprocmask(SIG_SETMASK, &sigblock, &origsig);
#ifdef WITH_EPOLL

View File

@ -431,7 +431,7 @@ int net__load_crl_file(struct mosquitto__listener *listener)
}
lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
rc = X509_load_crl_file(lookup, listener->crlfile, X509_FILETYPE_PEM);
if(rc != 1){
if(rc < 1){
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load certificate revocation file \"%s\". Check crlfile.", listener->crlfile);
net__print_error(MOSQ_LOG_ERR, "Error: %s");
return 1;

View File

@ -114,6 +114,12 @@ static int persist__client_msg_restore(struct mosquitto_db *db, struct P_client_
struct mosquitto *context;
struct mosquitto_msg_data *msg_data;
HASH_FIND(hh, db->msg_store_load, &chunk->F.store_id, sizeof(dbid_t), load);
if(!load){
/* Can't find message - probably expired */
return MOSQ_ERR_SUCCESS;
}
cmsg = mosquitto__calloc(1, sizeof(struct mosquitto_client_msg));
if(!cmsg){
log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
@ -131,12 +137,6 @@ static int persist__client_msg_restore(struct mosquitto_db *db, struct P_client_
cmsg->dup = chunk->F.retain_dup&0x0F;
cmsg->properties = chunk->properties;
HASH_FIND(hh, db->msg_store_load, &chunk->F.store_id, sizeof(dbid_t), load);
if(!load){
mosquitto__free(cmsg);
log__printf(NULL, MOSQ_LOG_ERR, "Error restoring persistent database, message store corrupt.");
return 1;
}
cmsg->store = load->store;
db__msg_store_ref_inc(cmsg->store);
@ -273,7 +273,13 @@ static int persist__msg_store_chunk_restore(struct mosquitto_db *db, FILE *db_fp
if(chunk.F.expiry_time > 0){
message_expiry_interval64 = chunk.F.expiry_time - time(NULL);
if(message_expiry_interval64 < 0 || message_expiry_interval64 > UINT32_MAX){
message_expiry_interval = 0;
/* Expired message */
mosquitto__free(chunk.source.id);
mosquitto__free(chunk.source.username);
mosquitto__free(chunk.topic);
UHPA_FREE(chunk.payload, chunk.F.payloadlen);
mosquitto__free(load);
return MOSQ_ERR_SUCCESS;
}else{
message_expiry_interval = (uint32_t)message_expiry_interval64;
}
@ -327,8 +333,7 @@ static int persist__retain_chunk_restore(struct mosquitto_db *db, FILE *db_fptr)
if(load){
retain__store(db, load->store->topic, load->store, NULL);
}else{
log__printf(NULL, MOSQ_LOG_ERR, "Error: Corrupt database whilst restoring a retained message.");
return MOSQ_ERR_INVAL;
/* Can't find the message - probably expired */
}
return MOSQ_ERR_SUCCESS;
}

View File

@ -140,7 +140,7 @@ static int retain__process(struct mosquitto_db *db, struct mosquitto__retainhier
mosquitto_property *properties = NULL;
struct mosquitto_msg_store *retained;
if(branch->retained->message_expiry_time > 0 && now > branch->retained->message_expiry_time){
if(branch->retained->message_expiry_time > 0 && now >= branch->retained->message_expiry_time){
db__msg_store_ref_dec(db, &branch->retained);
branch->retained = NULL;
#ifdef WITH_SYS_TREE

View File

@ -22,6 +22,7 @@ Contributors:
#include "mosquitto_broker_internal.h"
#include "memory_mosq.h"
#include "sys_tree.h"
#include "time_mosq.h"
static struct session_expiry_list *expiry_list = NULL;
@ -38,17 +39,32 @@ int session_expiry__add(struct mosquitto_db *db, struct mosquitto *context)
{
struct session_expiry_list *item;
if(db->config->persistent_client_expiration == 0){
if(context->session_expiry_interval == UINT32_MAX){
/* There isn't a global expiry set, and the client has asked to
* never expire, so we don't add it to the list. */
return MOSQ_ERR_SUCCESS;
}
}
item = mosquitto__calloc(1, sizeof(struct session_expiry_list));
if(!item) return MOSQ_ERR_NOMEM;
item->context = context;
item->context->session_expiry_time = time(NULL);
if(db->config->persistent_client_expiration == 0 ||
db->config->persistent_client_expiration < item->context->session_expiry_interval){
if(db->config->persistent_client_expiration == 0){
/* No global expiry, so use the client expiration interval */
item->context->session_expiry_time += item->context->session_expiry_interval;
}else{
item->context->session_expiry_time += db->config->persistent_client_expiration;
/* We have a global expiry interval */
if(db->config->persistent_client_expiration < item->context->session_expiry_interval){
/* The client expiry is longer than the global expiry, so use the global */
item->context->session_expiry_time += db->config->persistent_client_expiration;
}else{
/* The global expiry is longer than the client expiry, so use the client */
item->context->session_expiry_time += item->context->session_expiry_interval;
}
}
context->expiry_list_item = item;
@ -95,12 +111,16 @@ 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_interval != UINT32_MAX
&& item->context->session_expiry_time < now){
if(item->context->session_expiry_time < now){
context = item->context;
session_expiry__remove(context);
if(context->id){
log__printf(NULL, MOSQ_LOG_NOTICE, "Expiring client %s due to timeout.", context->id);
}
G_CLIENTS_EXPIRED_INC();
/* Session has now expired, so clear interval */
context->session_expiry_interval = 0;
/* Session has expired, so will delay should be cleared. */

View File

@ -151,6 +151,7 @@ static int subs__process(struct mosquitto_db *db, struct mosquitto__subhier *hie
}
}
static int sub__add_leaf(struct mosquitto *context, int qos, uint32_t identifier, int options, struct mosquitto__subleaf **head, struct mosquitto__subleaf **newleaf)
{
struct mosquitto__subleaf *leaf;
@ -539,7 +540,7 @@ struct mosquitto__subhier *sub__add_hier_entry(struct mosquitto__subhier *parent
}
child->parent = parent;
child->topic_len = len;
child->topic = malloc(len+1);
child->topic = mosquitto__malloc(len+1);
if(!child->topic){
child->topic_len = 0;
mosquitto__free(child);
@ -829,4 +830,3 @@ void sub__tree_print(struct mosquitto__subhier *root, int level)
sub__tree_print(branch->children, level+1);
}
}

View File

@ -66,6 +66,7 @@ int sub__topic_tokenise(const char *subtopic, struct sub__token **topics)
int start, stop, tlen;
int i;
char *topic;
int count = 0;
assert(subtopic);
assert(topics);
@ -90,6 +91,7 @@ int sub__topic_tokenise(const char *subtopic, struct sub__token **topics)
for(i=start; i<len+1; i++){
if(subtopic[i] == '/' || subtopic[i] == '\0'){
stop = i;
count++;
if(start != stop){
tlen = stop-start;
@ -108,6 +110,11 @@ int sub__topic_tokenise(const char *subtopic, struct sub__token **topics)
}
}
if(count > TOPIC_HIERARCHY_LIMIT){
/* Set limit on hierarchy levels, to restrict stack usage. */
goto cleanup;
}
return MOSQ_ERR_SUCCESS;
cleanup:

View File

@ -22,8 +22,10 @@ def do_test(proto_ver):
sock.close()
if len(data) == 0:
rc = 0
except socket.error:
rc = 0
except socket.error as e:
if e.errno == errno.ECONNRESET:
# Connection has been closed by peer, this is the expected behaviour
rc = 0
finally:
broker.terminate()
broker.wait()

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python3
# Test whether a CONNECT with a zero length client id results in the correct CONNACK packet.
# MQTT V3.1 only - zero length is invalid.
from mosq_test_helper import *
def do_test(proto_ver):

View File

@ -15,7 +15,10 @@ try:
sock = mosq_test.do_client_connect(connect_packet, b"", port=port)
sock.close()
rc = 0
except socket.error as e:
if e.errno == errno.ECONNRESET:
# Connection has been closed by peer, this is the expected behaviour
rc = 0
finally:
broker.terminate()
broker.wait()

View File

@ -0,0 +1,125 @@
#!/usr/bin/env python3
# Test whether a CONNECT with a zero length client id results in the correct behaviour.
# MQTT v3.1.1 - zero length is allowed, unless allow_zero_length_clientid is false, and unless clean_start is False.
# MQTT v5.0 - zero length is allowed, unless allow_zero_length_clientid is false
from mosq_test_helper import *
def write_config(filename, port1, port2, per_listener, allow_zero):
with open(filename, 'w') as f:
f.write("per_listener_settings %s\n" % (per_listener))
f.write("port %d\n" % (port2))
if allow_zero != "":
f.write("allow_zero_length_clientid %s\n" % (allow_zero))
f.write("listener %d\n" % (port1))
if allow_zero != "":
f.write("allow_zero_length_clientid %s\n" % (allow_zero))
def do_test(per_listener, proto_ver, clean_start, allow_zero, client_port, expect_fail):
conf_file = os.path.basename(__file__).replace('.py', '.conf')
write_config(conf_file, port1, port2, per_listener, allow_zero)
rc = 1
keepalive = 10
connect_packet = mosq_test.gen_connect("", keepalive=keepalive, proto_ver=proto_ver, clean_session=clean_start)
if proto_ver == 4:
if expect_fail == True:
connack_packet = mosq_test.gen_connack(rc=2, proto_ver=proto_ver)
else:
connack_packet = mosq_test.gen_connack(rc=0, proto_ver=proto_ver)
else:
if expect_fail == True:
connack_packet = mosq_test.gen_connack(rc=128, proto_ver=proto_ver, properties=None)
else:
props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_ASSIGNED_CLIENT_IDENTIFIER, "auto-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
connack_packet = mosq_test.gen_connack(rc=0, proto_ver=proto_ver, properties=props)
# Remove the "xxxx" part - this means the front part of the packet
# is correct (so remaining length etc. is correct), but we don't
# need to match against the random id.
connack_packet = connack_packet[:-36]
broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port1, use_conf=True)
try:
sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=client_port)
sock.close()
rc = 0
finally:
broker.terminate()
broker.wait()
(stdo, stde) = broker.communicate()
os.remove(conf_file)
if rc:
print(stde.decode('utf-8'))
print("per_listener:%s proto_ver:%d client_port:%d clean_start:%d allow_zero:%s" % (per_listener, proto_ver, client_port, clean_start, allow_zero))
print("port1:%d port2:%d" % (port1, port2))
exit(rc)
(port1, port2) = mosq_test.get_port(2)
test_v4 = True
test_v5 = True
if test_v4 == True:
do_test(per_listener="false", proto_ver=4, client_port=port1, clean_start=True, allow_zero="true", expect_fail=False)
do_test(per_listener="false", proto_ver=4, client_port=port1, clean_start=True, allow_zero="false", expect_fail=True)
do_test(per_listener="false", proto_ver=4, client_port=port1, clean_start=False, allow_zero="true", expect_fail=True)
do_test(per_listener="false", proto_ver=4, client_port=port1, clean_start=False, allow_zero="false", expect_fail=True)
do_test(per_listener="true", proto_ver=4, client_port=port1, clean_start=True, allow_zero="true", expect_fail=False)
do_test(per_listener="true", proto_ver=4, client_port=port1, clean_start=True, allow_zero="false", expect_fail=True)
do_test(per_listener="true", proto_ver=4, client_port=port1, clean_start=False, allow_zero="true", expect_fail=True)
do_test(per_listener="true", proto_ver=4, client_port=port1, clean_start=False, allow_zero="false", expect_fail=True)
do_test(per_listener="false", proto_ver=4, client_port=port2, clean_start=True, allow_zero="true", expect_fail=False)
do_test(per_listener="false", proto_ver=4, client_port=port2, clean_start=True, allow_zero="false", expect_fail=True)
do_test(per_listener="false", proto_ver=4, client_port=port2, clean_start=False, allow_zero="true", expect_fail=True)
do_test(per_listener="false", proto_ver=4, client_port=port2, clean_start=False, allow_zero="false", expect_fail=True)
do_test(per_listener="true", proto_ver=4, client_port=port2, clean_start=True, allow_zero="true", expect_fail=False)
do_test(per_listener="true", proto_ver=4, client_port=port2, clean_start=True, allow_zero="false", expect_fail=True)
do_test(per_listener="true", proto_ver=4, client_port=port2, clean_start=False, allow_zero="true", expect_fail=True)
do_test(per_listener="true", proto_ver=4, client_port=port2, clean_start=False, allow_zero="false", expect_fail=True)
do_test(per_listener="false", proto_ver=4, client_port=port1, clean_start=True, allow_zero="", expect_fail=False)
do_test(per_listener="false", proto_ver=4, client_port=port1, clean_start=False, allow_zero="", expect_fail=True)
do_test(per_listener="true", proto_ver=4, client_port=port1, clean_start=True, allow_zero="", expect_fail=False)
do_test(per_listener="true", proto_ver=4, client_port=port1, clean_start=False, allow_zero="", expect_fail=True)
do_test(per_listener="false", proto_ver=4, client_port=port2, clean_start=True, allow_zero="", expect_fail=False)
do_test(per_listener="false", proto_ver=4, client_port=port2, clean_start=False, allow_zero="", expect_fail=True)
do_test(per_listener="true", proto_ver=4, client_port=port2, clean_start=True, allow_zero="", expect_fail=False)
do_test(per_listener="true", proto_ver=4, client_port=port2, clean_start=False, allow_zero="", expect_fail=True)
if test_v5 == True:
do_test(per_listener="false", proto_ver=5, client_port=port1, clean_start=True, allow_zero="true", expect_fail=False)
do_test(per_listener="false", proto_ver=5, client_port=port1, clean_start=True, allow_zero="false", expect_fail=True)
do_test(per_listener="false", proto_ver=5, client_port=port1, clean_start=False, allow_zero="true", expect_fail=False)
do_test(per_listener="false", proto_ver=5, client_port=port1, clean_start=False, allow_zero="false", expect_fail=True)
do_test(per_listener="true", proto_ver=5, client_port=port1, clean_start=True, allow_zero="true", expect_fail=False)
do_test(per_listener="true", proto_ver=5, client_port=port1, clean_start=True, allow_zero="false", expect_fail=True)
do_test(per_listener="true", proto_ver=5, client_port=port1, clean_start=False, allow_zero="true", expect_fail=False)
do_test(per_listener="true", proto_ver=5, client_port=port1, clean_start=False, allow_zero="false", expect_fail=True)
do_test(per_listener="false", proto_ver=5, client_port=port2, clean_start=True, allow_zero="true", expect_fail=False)
do_test(per_listener="false", proto_ver=5, client_port=port2, clean_start=True, allow_zero="false", expect_fail=True)
do_test(per_listener="false", proto_ver=5, client_port=port2, clean_start=False, allow_zero="true", expect_fail=False)
do_test(per_listener="false", proto_ver=5, client_port=port2, clean_start=False, allow_zero="false", expect_fail=True)
do_test(per_listener="true", proto_ver=5, client_port=port2, clean_start=True, allow_zero="true", expect_fail=False)
do_test(per_listener="true", proto_ver=5, client_port=port2, clean_start=True, allow_zero="false", expect_fail=True)
do_test(per_listener="true", proto_ver=5, client_port=port2, clean_start=False, allow_zero="true", expect_fail=False)
do_test(per_listener="true", proto_ver=5, client_port=port2, clean_start=False, allow_zero="false", expect_fail=True)
do_test(per_listener="false", proto_ver=5, client_port=port1, clean_start=True, allow_zero="", expect_fail=False)
do_test(per_listener="false", proto_ver=5, client_port=port1, clean_start=False, allow_zero="", expect_fail=False)
do_test(per_listener="true", proto_ver=5, client_port=port1, clean_start=True, allow_zero="", expect_fail=False)
do_test(per_listener="true", proto_ver=5, client_port=port1, clean_start=False, allow_zero="", expect_fail=False)
do_test(per_listener="false", proto_ver=5, client_port=port2, clean_start=True, allow_zero="", expect_fail=False)
do_test(per_listener="false", proto_ver=5, client_port=port2, clean_start=False, allow_zero="", expect_fail=False)
do_test(per_listener="true", proto_ver=5, client_port=port2, clean_start=True, allow_zero="", expect_fail=False)
do_test(per_listener="true", proto_ver=5, client_port=port2, clean_start=False, allow_zero="", expect_fail=False)
exit(0)

View File

@ -0,0 +1,50 @@
#!/usr/bin/env python3
# Test whether a client subscribed to a topic receives its own message sent to that topic, for long topics.
from mosq_test_helper import *
def do_test(topic, succeeds):
rc = 1
mid = 53
keepalive = 60
connect_packet = mosq_test.gen_connect("subpub-qos0-test", keepalive=keepalive)
connack_packet = mosq_test.gen_connack(rc=0)
subscribe_packet = mosq_test.gen_subscribe(mid, topic, 0)
suback_packet = mosq_test.gen_suback(mid, 0)
publish_packet = mosq_test.gen_publish(topic, qos=0, payload="message")
port = mosq_test.get_port()
broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port)
try:
sock = mosq_test.do_client_connect(connect_packet, connack_packet, timeout=20, port=port)
if succeeds == True:
mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback")
mosq_test.do_send_receive(sock, publish_packet, publish_packet, "publish")
else:
mosq_test.do_send_receive(sock, subscribe_packet, b"", "suback")
rc = 0
sock.close()
finally:
broker.terminate()
broker.wait()
(stdo, stde) = broker.communicate()
if rc:
print(stde.decode('utf-8'))
exit(rc)
do_test("/"*200, True) # 200 max hierarchy limit
do_test("abc/"*199+"d", True) # 200 max hierarchy limit, longer overall string than 200
do_test("/"*201, False) # Exceeds 200 max hierarchy limit
do_test("abc/"*200+"d", False) # Exceeds 200 max hierarchy limit, longer overall string than 200
exit(0)

View File

@ -55,6 +55,10 @@ def do_test(proto_ver):
rc = 0
sock.close()
except socket.error as e:
if e.errno == errno.ECONNRESET:
# Connection has been closed by peer, this is the expected behaviour
rc = 0
finally:
broker.terminate()
broker.wait()

View File

@ -52,6 +52,10 @@ def do_test(proto_ver):
rc = 0
sock.close()
except socket.error as e:
if e.errno == errno.ECONNRESET:
# Connection has been closed by peer, this is the expected behaviour
rc = 0
finally:
broker.terminate()
broker.wait()

View File

@ -55,6 +55,10 @@ def do_test(proto_ver):
rc = 0
sock.close()
except socket.error as e:
if e.errno == errno.ECONNRESET:
# Connection has been closed by peer, this is the expected behaviour
rc = 0
finally:
broker.terminate()
broker.wait()

View File

@ -54,6 +54,10 @@ def do_test(proto_ver):
rc = 0
sock.close()
except socket.error as e:
if e.errno == errno.ECONNRESET:
# Connection has been closed by peer, this is the expected behaviour
rc = 0
finally:
broker.terminate()
broker.wait()

View File

@ -55,6 +55,10 @@ def do_test(proto_ver):
rc = 0
sock.close()
except socket.error as e:
if e.errno == errno.ECONNRESET:
# Connection has been closed by peer, this is the expected behaviour
rc = 0
finally:
broker.terminate()
broker.wait()

View File

@ -39,6 +39,7 @@ def do_test(proto_ver):
if mosq_test.expect_packet(sock, "publish2", publish_packet2):
mosq_test.do_send_receive(sock, pubrec_packet2, pubrel_packet2, "pubrel2")
sock.send(pubcomp_packet2)
# Broker side of flow complete so can quit here.
rc = 0

View File

@ -17,6 +17,10 @@ def do_test(proto_ver):
sock = mosq_test.do_client_connect(connect_packet, b"", timeout=30, port=port)
rc = 0
sock.close()
except socket.error as e:
if e.errno == errno.ECONNRESET:
# Connection has been closed by peer, this is the expected behaviour
rc = 0
finally:
broker.terminate()
broker.wait()
@ -30,4 +34,3 @@ def do_test(proto_ver):
do_test(proto_ver=4)
do_test(proto_ver=5)
exit(0)

View File

@ -3,7 +3,6 @@
# Test whether a client can connect without an SSL certificate if one is required.
from mosq_test_helper import *
import errno
if sys.version < '2.7':
print("WARNING: SSL not supported on Python 2.6")

View File

@ -41,11 +41,13 @@ ifeq ($(WITH_TLS),yes)
else
./01-connect-uname-password-success-no-tls.py
endif
./01-connect-zero-length-id.py
02 :
./02-shared-qos0-v5.py
./02-subhier-crash.py
./02-subpub-qos0-long-topic.py
./02-subpub-qos0-retain-as-publish.py
./02-subpub-qos0-send-retain.py
./02-subpub-qos0-subscription-id.py

View File

@ -15,3 +15,4 @@ import ssl
import struct
import subprocess
import time
import errno

View File

@ -22,9 +22,11 @@ tests = [
(1, './01-connect-uname-password-denied.py'),
(1, './01-connect-uname-password-success.py'),
(1, './01-connect-uname-pwd-no-flag.py'),
(2, './01-connect-zero-length-id.py'),
(1, './02-shared-qos0-v5.py'),
(1, './02-subhier-crash.py'),
(1, './02-subpub-qos0-long-topic.py'),
(1, './02-subpub-qos0-retain-as-publish.py'),
(1, './02-subpub-qos0-send-retain.py'),
(1, './02-subpub-qos0-subscription-id.py'),

58
test/lib/11-prop-recv-qos0.py Executable file
View File

@ -0,0 +1,58 @@
#!/usr/bin/env python3
# Check whether the v5 message callback gets the properties
from mosq_test_helper import *
port = mosq_test.get_lib_port()
rc = 1
keepalive = 60
connect_packet = mosq_test.gen_connect("prop-test", keepalive=keepalive, proto_ver=5)
connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5)
props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_CONTENT_TYPE, "plain/text")
props += mqtt5_props.gen_string_prop(mqtt5_props.PROP_RESPONSE_TOPIC, "msg/123")
publish_packet = mosq_test.gen_publish("prop/test", qos=0, payload="message", proto_ver=5, properties=props)
ok_packet = mosq_test.gen_publish("ok", qos=0, payload="ok", proto_ver=5)
disconnect_packet = mosq_test.gen_disconnect(proto_ver=5)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.settimeout(10)
sock.bind(('', port))
sock.listen(5)
client_args = sys.argv[1:]
env = dict(os.environ)
env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp'
try:
pp = env['PYTHONPATH']
except KeyError:
pp = ''
env['PYTHONPATH'] = '../../lib/python:'+pp
client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env, port=port)
try:
(conn, address) = sock.accept()
conn.settimeout(10)
if mosq_test.expect_packet(conn, "connect", connect_packet):
conn.send(connack_packet)
conn.send(publish_packet)
if mosq_test.expect_packet(conn, "ok", ok_packet):
rc = 0
conn.close()
finally:
client.terminate()
client.wait()
if rc:
(stdo, stde) = client.communicate()
print(stde)
sock.close()
exit(rc)

62
test/lib/11-prop-recv-qos1.py Executable file
View File

@ -0,0 +1,62 @@
#!/usr/bin/env python3
# Check whether the v5 message callback gets the properties
from mosq_test_helper import *
port = mosq_test.get_lib_port()
rc = 1
keepalive = 60
connect_packet = mosq_test.gen_connect("prop-test", keepalive=keepalive, proto_ver=5)
connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5)
mid = 1
props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_CONTENT_TYPE, "plain/text")
props += mqtt5_props.gen_string_prop(mqtt5_props.PROP_RESPONSE_TOPIC, "msg/123")
publish_packet = mosq_test.gen_publish("prop/test", mid=mid, qos=1, payload="message", proto_ver=5, properties=props)
puback_packet = mosq_test.gen_puback(mid=mid, proto_ver=5)
ok_packet = mosq_test.gen_publish("ok", qos=0, payload="ok", proto_ver=5)
disconnect_packet = mosq_test.gen_disconnect(proto_ver=5)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.settimeout(10)
sock.bind(('', port))
sock.listen(5)
client_args = sys.argv[1:]
env = dict(os.environ)
env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp'
try:
pp = env['PYTHONPATH']
except KeyError:
pp = ''
env['PYTHONPATH'] = '../../lib/python:'+pp
client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env, port=port)
try:
(conn, address) = sock.accept()
conn.settimeout(10)
if mosq_test.expect_packet(conn, "connect", connect_packet):
conn.send(connack_packet)
conn.send(publish_packet)
if mosq_test.expect_packet(conn, "puback", puback_packet):
if mosq_test.expect_packet(conn, "ok", ok_packet):
rc = 0
conn.close()
finally:
client.terminate()
client.wait()
if rc:
(stdo, stde) = client.communicate()
print(stde)
sock.close()
exit(rc)

66
test/lib/11-prop-recv-qos2.py Executable file
View File

@ -0,0 +1,66 @@
#!/usr/bin/env python3
# Check whether the v5 message callback gets the properties
from mosq_test_helper import *
port = mosq_test.get_lib_port()
rc = 1
keepalive = 60
connect_packet = mosq_test.gen_connect("prop-test", keepalive=keepalive, proto_ver=5)
connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5)
mid = 1
props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_CONTENT_TYPE, "plain/text")
props += mqtt5_props.gen_string_prop(mqtt5_props.PROP_RESPONSE_TOPIC, "msg/123")
publish_packet = mosq_test.gen_publish("prop/test", mid=mid, qos=2, payload="message", proto_ver=5, properties=props)
pubrec_packet = mosq_test.gen_pubrec(mid=mid, proto_ver=5)
pubrel_packet = mosq_test.gen_pubrel(mid=mid, proto_ver=5)
pubcomp_packet = mosq_test.gen_pubcomp(mid=mid, proto_ver=5)
ok_packet = mosq_test.gen_publish("ok", qos=0, payload="ok", proto_ver=5)
disconnect_packet = mosq_test.gen_disconnect(proto_ver=5)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.settimeout(10)
sock.bind(('', port))
sock.listen(5)
client_args = sys.argv[1:]
env = dict(os.environ)
env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp'
try:
pp = env['PYTHONPATH']
except KeyError:
pp = ''
env['PYTHONPATH'] = '../../lib/python:'+pp
client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env, port=port)
try:
(conn, address) = sock.accept()
conn.settimeout(10)
if mosq_test.expect_packet(conn, "connect", connect_packet):
conn.send(connack_packet)
conn.send(publish_packet)
if mosq_test.expect_packet(conn, "pubrec", pubrec_packet):
conn.send(pubrel_packet)
if mosq_test.expect_packet(conn, "pubcomp", pubcomp_packet):
if mosq_test.expect_packet(conn, "ok", ok_packet):
rc = 0
conn.close()
finally:
client.terminate()
client.wait()
if rc:
(stdo, stde) = client.communicate()
print(stde)
sock.close()
exit(rc)

View File

@ -68,6 +68,9 @@ endif
./11-prop-oversize-packet.py $@/11-prop-oversize-packet.test
./11-prop-send-content-type.py $@/11-prop-send-content-type.test
./11-prop-send-payload-format.py $@/11-prop-send-payload-format.test
./11-prop-recv-qos0.py $@/11-prop-recv-qos0.test
./11-prop-recv-qos1.py $@/11-prop-recv-qos1.test
./11-prop-recv-qos2.py $@/11-prop-recv-qos2.test
clean :
$(MAKE) -C c clean

View File

@ -42,33 +42,24 @@ int main(int argc, char *argv[])
mosquitto_connect_callback_set(mosq, on_connect);
mosquitto_disconnect_callback_set(mosq, on_disconnect);
mosquitto_subscribe_callback_set(mosq, on_subscribe);
printf("ok, about to call connect_async\n");
// this only works if loop_start is first. with loop_start second,
// it fails on both 1.6.4 _and_ 1.6.5
// in this order, 1.6.4 works and 1.6.5 fails.
rc = mosquitto_loop_start(mosq);
printf("loop_start returned rc: %d\n", rc);
if (rc) {
printf("which is: %s\n", mosquitto_strerror(rc));
if(rc){
printf("loop_start failed: %s\n", mosquitto_strerror(rc));
return rc;
}
// not sure which rc you want to be returned....
rc = mosquitto_connect_async(mosq, "localhost", port, 60);
printf("connect async returned rc: %d\n", rc);
if (rc) {
printf("which is: %s\n", mosquitto_strerror(rc));
if(rc){
printf("connect_async failed: %s\n", mosquitto_strerror(rc));
return rc;
}
printf("ok, so we can start just waiting now, loop_start will run in it's thread\n");
/* 10 millis to be system polite */
//struct timespec tv = { 0, 10e6 };
struct timespec tv = { 1, 0 };
/* 50 millis to be system polite */
struct timespec tv = { 0, 50e6 };
while(should_run){
nanosleep(&tv, NULL);
printf("...waiting...\n");
}
printf("Already exited should_run....\n");
mosquitto_disconnect(mosq);
mosquitto_loop_stop(mosq, false);

View File

@ -42,29 +42,22 @@ int main(int argc, char *argv[])
mosquitto_connect_callback_set(mosq, on_connect);
mosquitto_disconnect_callback_set(mosq, on_disconnect);
mosquitto_subscribe_callback_set(mosq, on_subscribe);
printf("ok, about to call connect_async\n");
rc = mosquitto_connect_async(mosq, "localhost", port, 60);
printf("connect async returned rc: %d\n", rc);
if (rc) {
printf("which is: %s\n", mosquitto_strerror(rc));
if(rc){
printf("connect_async failed: %s\n", mosquitto_strerror(rc));
}
rc = mosquitto_loop_start(mosq);
printf("loop_start returned rc: %d\n", rc);
if (rc) {
printf("which is: %s\n", mosquitto_strerror(rc));
if(rc){
printf("loop_start failed: %s\n", mosquitto_strerror(rc));
}
printf("ok, so we can start just waiting now, loop_start will run in it's thread\n");
/* 10 millis to be system polite */
//struct timespec tv = { 0, 10e6 };
struct timespec tv = { 1, 0 };
/* 50 millis to be system polite */
struct timespec tv = { 0, 50e6 };
while(should_run){
nanosleep(&tv, NULL);
printf("...waiting...\n");
}
printf("Already exited should_run....\n");
mosquitto_disconnect(mosq);
mosquitto_loop_stop(mosq, false);

View File

@ -0,0 +1,81 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mosquitto.h>
#include <mqtt_protocol.h>
static int run = -1;
static int sent_mid = -1;
void on_connect(struct mosquitto *mosq, void *obj, int rc)
{
int rc2;
mosquitto_property *proplist = NULL;
if(rc){
exit(1);
}
}
void on_message_v5(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg, const mosquitto_property *properties)
{
int rc;
char *str;
if(properties){
if(mosquitto_property_read_string(properties, MQTT_PROP_CONTENT_TYPE, &str, false)){
rc = strcmp(str, "plain/text");
free(str);
if(rc == 0){
if(mosquitto_property_read_string(properties, MQTT_PROP_RESPONSE_TOPIC, &str, false)){
rc = strcmp(str, "msg/123");
free(str);
if(rc == 0){
if(msg->qos == 0){
mosquitto_publish(mosq, NULL, "ok", 2, "ok", 0, 0);
return;
}
}
}
}
}
}
/* No matching message, so quit with an error */
exit(1);
}
void on_publish(struct mosquitto *mosq, void *obj, int mid)
{
run = 0;
}
int main(int argc, char *argv[])
{
int rc;
int tmp;
struct mosquitto *mosq;
int port = atoi(argv[1]);
mosquitto_lib_init();
mosq = mosquitto_new("prop-test", true, NULL);
mosquitto_connect_callback_set(mosq, on_connect);
mosquitto_message_v5_callback_set(mosq, on_message_v5);
mosquitto_int_option(mosq, MOSQ_OPT_PROTOCOL_VERSION, MQTT_PROTOCOL_V5);
rc = mosquitto_connect(mosq, "localhost", port, 60);
while(run == -1){
rc = mosquitto_loop(mosq, -1, 1);
}
mosquitto_lib_cleanup();
return run;
}

View File

@ -0,0 +1,81 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mosquitto.h>
#include <mqtt_protocol.h>
static int run = -1;
static int sent_mid = -1;
void on_connect(struct mosquitto *mosq, void *obj, int rc)
{
int rc2;
mosquitto_property *proplist = NULL;
if(rc){
exit(1);
}
}
void on_message_v5(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg, const mosquitto_property *properties)
{
int rc;
char *str;
if(properties){
if(mosquitto_property_read_string(properties, MQTT_PROP_CONTENT_TYPE, &str, false)){
rc = strcmp(str, "plain/text");
free(str);
if(rc == 0){
if(mosquitto_property_read_string(properties, MQTT_PROP_RESPONSE_TOPIC, &str, false)){
rc = strcmp(str, "msg/123");
free(str);
if(rc == 0){
if(msg->qos == 1){
mosquitto_publish(mosq, NULL, "ok", 2, "ok", 0, 0);
return;
}
}
}
}
}
}
/* No matching message, so quit with an error */
exit(1);
}
void on_publish(struct mosquitto *mosq, void *obj, int mid)
{
run = 0;
}
int main(int argc, char *argv[])
{
int rc;
int tmp;
struct mosquitto *mosq;
int port = atoi(argv[1]);
mosquitto_lib_init();
mosq = mosquitto_new("prop-test", true, NULL);
mosquitto_connect_callback_set(mosq, on_connect);
mosquitto_message_v5_callback_set(mosq, on_message_v5);
mosquitto_int_option(mosq, MOSQ_OPT_PROTOCOL_VERSION, MQTT_PROTOCOL_V5);
rc = mosquitto_connect(mosq, "localhost", port, 60);
while(run == -1){
rc = mosquitto_loop(mosq, -1, 1);
}
mosquitto_lib_cleanup();
return run;
}

View File

@ -0,0 +1,82 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mosquitto.h>
#include <mqtt_protocol.h>
static int run = -1;
static int sent_mid = -1;
void on_connect(struct mosquitto *mosq, void *obj, int rc)
{
int rc2;
mosquitto_property *proplist = NULL;
if(rc){
exit(1);
}
}
void on_message_v5(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg, const mosquitto_property *properties)
{
int rc;
char *str;
if(properties){
if(mosquitto_property_read_string(properties, MQTT_PROP_CONTENT_TYPE, &str, false)){
rc = strcmp(str, "plain/text");
free(str);
if(rc == 0){
if(mosquitto_property_read_string(properties, MQTT_PROP_RESPONSE_TOPIC, &str, false)){
rc = strcmp(str, "msg/123");
free(str);
if(rc == 0){
if(msg->qos == 2){
mosquitto_publish(mosq, NULL, "ok", 2, "ok", 0, 0);
return;
}
}
}
}
}
}
/* No matching message, so quit with an error */
exit(1);
}
void on_publish(struct mosquitto *mosq, void *obj, int mid)
{
run = 0;
}
int main(int argc, char *argv[])
{
int rc;
int tmp;
struct mosquitto *mosq;
int port = atoi(argv[1]);
mosquitto_lib_init();
mosq = mosquitto_new("prop-test", true, NULL);
mosquitto_connect_callback_set(mosq, on_connect);
mosquitto_message_v5_callback_set(mosq, on_message_v5);
mosquitto_int_option(mosq, MOSQ_OPT_PROTOCOL_VERSION, MQTT_PROTOCOL_V5);
rc = mosquitto_connect(mosq, "localhost", port, 60);
while(run == -1){
rc = mosquitto_loop(mosq, -1, 1);
}
mosquitto_destroy(mosq);
mosquitto_lib_cleanup();
return run;
}

View File

@ -46,6 +46,9 @@ SRC = \
08-ssl-fake-cacert.c \
09-util-topic-tokenise.c \
11-prop-oversize-packet.c \
11-prop-recv-qos0.c \
11-prop-recv-qos1.c \
11-prop-recv-qos2.c \
11-prop-send-payload-format.c \
11-prop-send-content-type.c

View File

@ -106,7 +106,13 @@ def packet_matches(name, recvd, expected):
def do_send_receive(sock, send_packet, receive_packet, error_string="send receive error"):
sock.send(send_packet)
size = len(send_packet)
total_sent = 0
while total_sent < size:
sent = sock.send(send_packet[total_sent:])
if sent == 0:
raise RuntimeError("socket connection broken")
total_sent += sent
if expect_packet(sock, error_string, receive_packet):
return sock

View File

@ -11,7 +11,7 @@
# Source
* [mosquitto-1.6.7.tar.gz](https://mosquitto.org/files/source/mosquitto-1.6.7.tar.gz) (319kB) ([GPG signature](https://mosquitto.org/files/source/mosquitto-1.6.7.tar.gz.asc))
* [mosquitto-1.6.8.tar.gz](https://mosquitto.org/files/source/mosquitto-1.6.8.tar.gz) (319kB) ([GPG signature](https://mosquitto.org/files/source/mosquitto-1.6.8.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.7-install-windows-x64.exe](https://mosquitto.org/files/binary/win64/mosquitto-1.6.7-install-windows-x64.exe) (~1.4 MB) (64-bit build, Windows Vista and up, built with Visual Studio Community 2017)
* [mosquitto-1.6.7-install-windows-x32.exe](https://mosquitto.org/files/binary/win32/mosquitto-1.6.7-install-windows-x86.exe) (~1.4 MB) (32-bit build, Windows Vista and up, built with Visual Studio Community 2017)
* [mosquitto-1.6.8-install-windows-x64.exe](https://mosquitto.org/files/binary/win64/mosquitto-1.6.8-install-windows-x64.exe) (~1.4 MB) (64-bit build, Windows Vista and up, built with Visual Studio Community 2017)
* [mosquitto-1.6.8-install-windows-x32.exe](https://mosquitto.org/files/binary/win32/mosquitto-1.6.8-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.

View File

@ -53,9 +53,8 @@
href="https://test.mosquitto.org/">test.mosquitto.org</a> where
you can test your clients in a variety of ways: plain MQTT,
MQTT over TLS, MQTT over TLS (with <a
href="https://test.mosquitto.org/ssl/">client certificate</a>,
href="https://test.mosquitto.org/ssl/">client certificate</a>),
MQTT over WebSockets and MQTT over WebSockets with TLS.</p>
platforms.</p>
</div>
<div class="column column-justify">

View File

@ -0,0 +1,75 @@
<!--
.. title: Version 1.6.8 released.
.. slug: version-1-6-8-released
.. date: 2019-11-28 16:44:19 UTC+00:00
.. tags: Releases
.. category:
.. link:
.. description:
.. type: text
-->
Mosquitto 1.6.8 has been released, this is a bugfix release.
# Broker
- Various fixes for `allow_zero_length_clientid` config, where this option was
not being set correctly. Closes [#1429].
- Fix incorrect memory tracking causing problems with `memory_limit` option.
Closes [#1437].
- Fix subscription topics being limited to 200 characters instead of 200
hierarchy levels. Closes [#1441].
- Only a single CRL could be loaded at once. This has been fixed.
Closes [#1442].
- Fix problems with reloading config when `per_listener_settings` was true.
Closes [#1459].
- Fix retained messages with an expiry interval not being expired after being
restored from persistence. Closes [#1464].
- Fix messages with an expiry interval being sent without an expiry interval
property just before they were expired. Closes [#1464].
- Fix TLS Websockets clients not receiving messages after taking over a
previous connection. Closes [#1489].
- Fix MQTT 3.1.1 clients using clean session false, or MQTT 5.0 clients using
session-expiry-interval set to infinity never expiring, even when the global
`persistent_client_expiration` option was set. Closes [#1494].
# Client library
- Fix publish properties not being passed to `on_message_v5()` callback for QoS 2
messages. Closes [#1432].
- Fix documentation issues in mosquitto.h. Closes [#1478].
- Document `mosquitto_connect_srv()`. Closes [#1499].
# Clients
- Fix duplicate cfg definition in rr_client. Closes [#1453].
- Fix `mosquitto_pub -l` hang when stdin stream ends. Closes [#1448].
- Fix `mosquitto_pub -l` not sending the final line of stdin if it does not
end with a new line. Closes [#1473].
- Make documentation for `mosquitto_pub -l` match reality - blank lines are
sent as empty messages. Closes [#1474].
- Free memory in `mosquitto_sub` when quiting without having made a successful
connection. Closes [#1513].
# Build
- Added `CLIENT_STATIC_LDADD` to makefile builds to allow more libraries to be
linked when compiling the clients with a static libmosquitto, as required
for e.g. openssl on some systems.
# Installer
- Fix `mosquitto_rr.exe` not being included in Windows installers. Closes [#1463].
[#1429]: https://github.com/eclipse/mosquitto/issues/1429
[#1432]: https://github.com/eclipse/mosquitto/issues/1432
[#1437]: https://github.com/eclipse/mosquitto/issues/1437
[#1441]: https://github.com/eclipse/mosquitto/issues/1441
[#1442]: https://github.com/eclipse/mosquitto/issues/1442
[#1448]: https://github.com/eclipse/mosquitto/issues/1448
[#1453]: https://github.com/eclipse/mosquitto/issues/1453
[#1459]: https://github.com/eclipse/mosquitto/issues/1459
[#1463]: https://github.com/eclipse/mosquitto/issues/1463
[#1464]: https://github.com/eclipse/mosquitto/issues/1464
[#1473]: https://github.com/eclipse/mosquitto/issues/1473
[#1474]: https://github.com/eclipse/mosquitto/issues/1474
[#1478]: https://github.com/eclipse/mosquitto/issues/1478
[#1489]: https://github.com/eclipse/mosquitto/issues/1489
[#1494]: https://github.com/eclipse/mosquitto/issues/1494
[#1499]: https://github.com/eclipse/mosquitto/issues/1499
[#1513]: https://github.com/eclipse/mosquitto/issues/1513