From 48f096bc1c5949fc088ae84f306f69378d4910b6 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 29 Aug 2018 22:13:41 +0100 Subject: [PATCH 001/254] Read/write new 32 bit ints from packets. --- lib/packet_mosq.c | 28 ++++++++++++++++++++++++++++ lib/packet_mosq.h | 2 ++ 2 files changed, 30 insertions(+) diff --git a/lib/packet_mosq.c b/lib/packet_mosq.c index 686006fc89..bb2077c754 100644 --- a/lib/packet_mosq.c +++ b/lib/packet_mosq.c @@ -252,6 +252,34 @@ void packet__write_uint16(struct mosquitto__packet *packet, uint16_t word) } +int packet__read_uint32(struct mosquitto__packet *packet, uint32_t *word) +{ + uint32_t val = 0; + int i; + + assert(packet); + if(packet->pos+4 > packet->remaining_length) return MOSQ_ERR_PROTOCOL; + + for(i=0; i<4; i++){ + val = (val << 8) + packet->payload[packet->pos]; + packet->pos++; + } + + *word = val; + + return MOSQ_ERR_SUCCESS; +} + + +void packet__write_uint32(struct mosquitto__packet *packet, uint32_t word) +{ + packet__write_byte(packet, (word & 0xFF000000) >> 24); + packet__write_byte(packet, (word & 0x00FF0000) >> 16); + packet__write_byte(packet, (word & 0x0000FF00) >> 8); + packet__write_byte(packet, (word & 0x000000FF)); +} + + int packet__write(struct mosquitto *mosq) { ssize_t write_length; diff --git a/lib/packet_mosq.h b/lib/packet_mosq.h index bc6eebfe11..915605d5f0 100644 --- a/lib/packet_mosq.h +++ b/lib/packet_mosq.h @@ -31,11 +31,13 @@ int packet__read_byte(struct mosquitto__packet *packet, uint8_t *byte); int packet__read_bytes(struct mosquitto__packet *packet, void *bytes, uint32_t count); int packet__read_string(struct mosquitto__packet *packet, char **str, int *length); int packet__read_uint16(struct mosquitto__packet *packet, uint16_t *word); +int packet__read_uint32(struct mosquitto__packet *packet, uint32_t *word); void packet__write_byte(struct mosquitto__packet *packet, uint8_t byte); void packet__write_bytes(struct mosquitto__packet *packet, const void *bytes, uint32_t count); void packet__write_string(struct mosquitto__packet *packet, const char *str, uint16_t length); void packet__write_uint16(struct mosquitto__packet *packet, uint16_t word); +void packet__write_uint32(struct mosquitto__packet *packet, uint32_t word); int packet__write(struct mosquitto *mosq); #ifdef WITH_BROKER From 0bacff11dfac29cce9758cbce8da5e6560f5c198 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 29 Aug 2018 22:26:16 +0100 Subject: [PATCH 002/254] Rename mqtt3_protocol.h -> mqtt_protocol.h. --- lib/CMakeLists.txt | 2 +- lib/actions.c | 2 +- lib/handle_ping.c | 2 +- lib/handle_pubackcomp.c | 2 +- lib/handle_pubrec.c | 2 +- lib/handle_pubrel.c | 2 +- lib/handle_unsuback.c | 2 +- lib/{mqtt3_protocol.h => mqtt_protocol.h} | 4 ++-- lib/net_mosq.c | 2 +- lib/packet_mosq.c | 2 +- lib/read_handle.c | 2 +- lib/send_connect.c | 2 +- lib/send_disconnect.c | 2 +- lib/send_mosq.c | 2 +- lib/send_publish.c | 2 +- lib/send_subscribe.c | 2 +- lib/send_unsubscribe.c | 2 +- lib/will_mosq.c | 2 +- src/conf.c | 2 +- src/conf_includedir.c | 2 +- src/handle_connack.c | 2 +- src/handle_connect.c | 2 +- src/handle_publish.c | 2 +- src/handle_unsubscribe.c | 2 +- src/net.c | 2 +- src/read_handle.c | 2 +- src/send_connack.c | 2 +- src/send_suback.c | 2 +- src/websockets.c | 2 +- 29 files changed, 30 insertions(+), 30 deletions(-) rename lib/{mqtt3_protocol.h => mqtt_protocol.h} (99%) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index d537e776d7..48f0c89c07 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -50,7 +50,7 @@ set(C_SRC messages_mosq.c messages_mosq.h mosquitto.c mosquitto.h mosquitto_internal.h - mqtt3_protocol.h + mqtt_protocol.h net_mosq.c net_mosq.h options.c packet_mosq.c packet_mosq.h diff --git a/lib/actions.c b/lib/actions.c index 5e50dbe548..9fb36d618c 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -22,7 +22,7 @@ and the Eclipse Distribution License is available at #include "mosquitto_internal.h" #include "memory_mosq.h" #include "messages_mosq.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" #include "net_mosq.h" #include "send_mosq.h" #include "util_mosq.h" diff --git a/lib/handle_ping.c b/lib/handle_ping.c index 17b53be0b1..ad56dda068 100644 --- a/lib/handle_ping.c +++ b/lib/handle_ping.c @@ -28,7 +28,7 @@ and the Eclipse Distribution License is available at #include "logging_mosq.h" #include "memory_mosq.h" #include "messages_mosq.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" #include "net_mosq.h" #include "packet_mosq.h" #include "read_handle.h" diff --git a/lib/handle_pubackcomp.c b/lib/handle_pubackcomp.c index 37788456bd..a6586f8f00 100644 --- a/lib/handle_pubackcomp.c +++ b/lib/handle_pubackcomp.c @@ -28,7 +28,7 @@ and the Eclipse Distribution License is available at #include "logging_mosq.h" #include "memory_mosq.h" #include "messages_mosq.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" #include "net_mosq.h" #include "packet_mosq.h" #include "read_handle.h" diff --git a/lib/handle_pubrec.c b/lib/handle_pubrec.c index 59eea1b7e7..3f79d50622 100644 --- a/lib/handle_pubrec.c +++ b/lib/handle_pubrec.c @@ -28,7 +28,7 @@ and the Eclipse Distribution License is available at #include "logging_mosq.h" #include "memory_mosq.h" #include "messages_mosq.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" #include "net_mosq.h" #include "packet_mosq.h" #include "read_handle.h" diff --git a/lib/handle_pubrel.c b/lib/handle_pubrel.c index 56660987c9..7c1f137cae 100644 --- a/lib/handle_pubrel.c +++ b/lib/handle_pubrel.c @@ -28,7 +28,7 @@ and the Eclipse Distribution License is available at #include "logging_mosq.h" #include "memory_mosq.h" #include "messages_mosq.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" #include "net_mosq.h" #include "packet_mosq.h" #include "read_handle.h" diff --git a/lib/handle_unsuback.c b/lib/handle_unsuback.c index 6297bb1033..357ef5c9c8 100644 --- a/lib/handle_unsuback.c +++ b/lib/handle_unsuback.c @@ -28,7 +28,7 @@ and the Eclipse Distribution License is available at #include "logging_mosq.h" #include "memory_mosq.h" #include "messages_mosq.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" #include "net_mosq.h" #include "packet_mosq.h" #include "read_handle.h" diff --git a/lib/mqtt3_protocol.h b/lib/mqtt_protocol.h similarity index 99% rename from lib/mqtt3_protocol.h rename to lib/mqtt_protocol.h index 4884bacb75..e148e1ed29 100644 --- a/lib/mqtt3_protocol.h +++ b/lib/mqtt_protocol.h @@ -4,12 +4,12 @@ Copyright (c) 2009-2018 Roger Light All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 and Eclipse Distribution License v1.0 which accompany this distribution. - + The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at http://www.eclipse.org/org/documents/edl-v10.php. - + Contributors: Roger Light - initial implementation and documentation. */ diff --git a/lib/net_mosq.c b/lib/net_mosq.c index d593c7b275..a84d10c5c3 100644 --- a/lib/net_mosq.c +++ b/lib/net_mosq.c @@ -64,7 +64,7 @@ and the Eclipse Distribution License is available at #include "logging_mosq.h" #include "memory_mosq.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" #include "net_mosq.h" #include "time_mosq.h" #include "util_mosq.h" diff --git a/lib/packet_mosq.c b/lib/packet_mosq.c index bb2077c754..ddfaef4987 100644 --- a/lib/packet_mosq.c +++ b/lib/packet_mosq.c @@ -30,7 +30,7 @@ and the Eclipse Distribution License is available at #endif #include "memory_mosq.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" #include "net_mosq.h" #include "packet_mosq.h" #include "read_handle.h" diff --git a/lib/read_handle.c b/lib/read_handle.c index 274a4da59b..fab8b7ddca 100644 --- a/lib/read_handle.c +++ b/lib/read_handle.c @@ -24,7 +24,7 @@ and the Eclipse Distribution License is available at #include "logging_mosq.h" #include "memory_mosq.h" #include "messages_mosq.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" #include "net_mosq.h" #include "packet_mosq.h" #include "read_handle.h" diff --git a/lib/send_connect.c b/lib/send_connect.c index 458f522f14..59802c9bb1 100644 --- a/lib/send_connect.c +++ b/lib/send_connect.c @@ -27,7 +27,7 @@ and the Eclipse Distribution License is available at #include "memory_mosq.h" #include "mosquitto.h" #include "mosquitto_internal.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" #include "packet_mosq.h" int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session) diff --git a/lib/send_disconnect.c b/lib/send_disconnect.c index 0cfea27687..e5009d696f 100644 --- a/lib/send_disconnect.c +++ b/lib/send_disconnect.c @@ -25,7 +25,7 @@ and the Eclipse Distribution License is available at #include "mosquitto.h" #include "mosquitto_internal.h" #include "logging_mosq.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" #include "send_mosq.h" diff --git a/lib/send_mosq.c b/lib/send_mosq.c index ee544e3e7e..3c58d724f6 100644 --- a/lib/send_mosq.c +++ b/lib/send_mosq.c @@ -30,7 +30,7 @@ and the Eclipse Distribution License is available at #include "mosquitto.h" #include "mosquitto_internal.h" #include "logging_mosq.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" #include "memory_mosq.h" #include "net_mosq.h" #include "packet_mosq.h" diff --git a/lib/send_publish.c b/lib/send_publish.c index e9aeeef8d3..124fc85f9f 100644 --- a/lib/send_publish.c +++ b/lib/send_publish.c @@ -29,7 +29,7 @@ and the Eclipse Distribution License is available at #include "mosquitto.h" #include "mosquitto_internal.h" #include "logging_mosq.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" #include "memory_mosq.h" #include "net_mosq.h" #include "packet_mosq.h" diff --git a/lib/send_subscribe.c b/lib/send_subscribe.c index c60ca0f243..6fa4720d30 100644 --- a/lib/send_subscribe.c +++ b/lib/send_subscribe.c @@ -27,7 +27,7 @@ and the Eclipse Distribution License is available at #include "mosquitto_internal.h" #include "logging_mosq.h" #include "memory_mosq.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" #include "packet_mosq.h" #include "util_mosq.h" diff --git a/lib/send_unsubscribe.c b/lib/send_unsubscribe.c index fb66e88c88..18317a1d6d 100644 --- a/lib/send_unsubscribe.c +++ b/lib/send_unsubscribe.c @@ -26,7 +26,7 @@ and the Eclipse Distribution License is available at #include "mosquitto.h" #include "logging_mosq.h" #include "memory_mosq.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" #include "packet_mosq.h" #include "util_mosq.h" diff --git a/lib/will_mosq.c b/lib/will_mosq.c index 3e9495ff28..fe5a0443ef 100644 --- a/lib/will_mosq.c +++ b/lib/will_mosq.c @@ -28,7 +28,7 @@ and the Eclipse Distribution License is available at #include "logging_mosq.h" #include "messages_mosq.h" #include "memory_mosq.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" #include "net_mosq.h" #include "read_handle.h" #include "send_mosq.h" diff --git a/src/conf.c b/src/conf.c index f5e989ff7a..e32ba83946 100644 --- a/src/conf.c +++ b/src/conf.c @@ -44,7 +44,7 @@ and the Eclipse Distribution License is available at #include "memory_mosq.h" #include "tls_mosq.h" #include "util_mosq.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" struct config_recurse { int log_dest; diff --git a/src/conf_includedir.c b/src/conf_includedir.c index 43da9a1645..4fc04a282d 100644 --- a/src/conf_includedir.c +++ b/src/conf_includedir.c @@ -44,7 +44,7 @@ and the Eclipse Distribution License is available at #include "memory_mosq.h" #include "tls_mosq.h" #include "util_mosq.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" int strcasecmp_p(const void *p1, const void *p2) { diff --git a/src/handle_connack.c b/src/handle_connack.c index 52e78e4f2c..9451de8561 100644 --- a/src/handle_connack.c +++ b/src/handle_connack.c @@ -21,7 +21,7 @@ and the Eclipse Distribution License is available at #include "mosquitto_broker_internal.h" #include "memory_mosq.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" #include "packet_mosq.h" #include "send_mosq.h" #include "util_mosq.h" diff --git a/src/handle_connect.c b/src/handle_connect.c index 8796445675..c3e747b307 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -20,7 +20,7 @@ and the Eclipse Distribution License is available at #include #include "mosquitto_broker_internal.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" #include "memory_mosq.h" #include "packet_mosq.h" #include "send_mosq.h" diff --git a/src/handle_publish.c b/src/handle_publish.c index 54976afce7..a6e990ef14 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -21,7 +21,7 @@ and the Eclipse Distribution License is available at #include #include "mosquitto_broker_internal.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" #include "memory_mosq.h" #include "packet_mosq.h" #include "read_handle.h" diff --git a/src/handle_unsubscribe.c b/src/handle_unsubscribe.c index a0f0004681..76b263ff95 100644 --- a/src/handle_unsubscribe.c +++ b/src/handle_unsubscribe.c @@ -21,7 +21,7 @@ and the Eclipse Distribution License is available at #include "mosquitto_broker_internal.h" #include "memory_mosq.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" #include "packet_mosq.h" #include "send_mosq.h" /* diff --git a/src/net.c b/src/net.c index 64f8bdc538..ca3e2d64eb 100644 --- a/src/net.c +++ b/src/net.c @@ -45,7 +45,7 @@ and the Eclipse Distribution License is available at #endif #include "mosquitto_broker_internal.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" #include "memory_mosq.h" #include "net_mosq.h" #include "util_mosq.h" diff --git a/src/read_handle.c b/src/read_handle.c index ac448aab53..9d032ed2f5 100644 --- a/src/read_handle.c +++ b/src/read_handle.c @@ -21,7 +21,7 @@ and the Eclipse Distribution License is available at #include #include "mosquitto_broker_internal.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" #include "memory_mosq.h" #include "packet_mosq.h" #include "read_handle.h" diff --git a/src/send_connack.c b/src/send_connack.c index 12b20724fb..2a15ae3dae 100644 --- a/src/send_connack.c +++ b/src/send_connack.c @@ -17,7 +17,7 @@ and the Eclipse Distribution License is available at #include "config.h" #include "mosquitto_broker_internal.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" #include "memory_mosq.h" #include "packet_mosq.h" #include "util_mosq.h" diff --git a/src/send_suback.c b/src/send_suback.c index adaeb16bd4..7bbe72fa18 100644 --- a/src/send_suback.c +++ b/src/send_suback.c @@ -17,7 +17,7 @@ and the Eclipse Distribution License is available at #include "config.h" #include "mosquitto_broker_internal.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" #include "memory_mosq.h" #include "packet_mosq.h" #include "util_mosq.h" diff --git a/src/websockets.c b/src/websockets.c index 1ab02a9b1c..7c0dca329c 100644 --- a/src/websockets.c +++ b/src/websockets.c @@ -34,7 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include "mosquitto_internal.h" #include "mosquitto_broker_internal.h" -#include "mqtt3_protocol.h" +#include "mqtt_protocol.h" #include "memory_mosq.h" #include "packet_mosq.h" #include "sys_tree.h" From 5dc88fe8f3f52b4db843fce74bc3df1781692a20 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 30 Aug 2018 16:29:30 +0100 Subject: [PATCH 003/254] Add v5 return codes --- lib/mqtt_protocol.h | 69 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 6 deletions(-) diff --git a/lib/mqtt_protocol.h b/lib/mqtt_protocol.h index e148e1ed29..74cfe9150a 100644 --- a/lib/mqtt_protocol.h +++ b/lib/mqtt_protocol.h @@ -25,6 +25,10 @@ and the Eclipse Distribution License is available at #define PROTOCOL_NAME_v311 "MQTT" #define PROTOCOL_VERSION_v311 4 +#define PROTOCOL_NAME_v5 "MQTT" +#define PROTOCOL_VERSION_v5 5 + + /* Message types */ #define CONNECT 0x10 #define CONNACK 0x20 @@ -40,13 +44,66 @@ and the Eclipse Distribution License is available at #define PINGREQ 0xC0 #define PINGRESP 0xD0 #define DISCONNECT 0xE0 +#define AUTH 0xF0 + +enum mqtt311_connack_codes { + CONNACK_ACCEPTED = 0, + CONNACK_REFUSED_PROTOCOL_VERSION = 1, + CONNACK_REFUSED_IDENTIFIER_REJECTED = 2, + CONNACK_REFUSED_SERVER_UNAVAILABLE = 3, + CONNACK_REFUSED_BAD_USERNAME_PASSWORD = 4, + CONNACK_REFUSED_NOT_AUTHORIZED = 5, +}; + + +enum mqtt5_return_codes { + RC5_SUCCESS = 0, /* CONNACK, PUBACK, PUBREC, PUBREL, PUBCOMP, UNSUBACK, AUTH */ + RC5_NORMAL_DISCONNECTION = 0, /* DISCONNECT */ + RC5_GRANTED_QOS0 = 0, /* SUBACK */ + RC5_GRANTED_QOS1 = 1, /* SUBACK */ + RC5_GRANTED_QOS2 = 2, /* SUBACK */ + RC5_DISCONNECT_WITH_WILL_MSG = 4, /* DISCONNECT */ + RC5_NO_MATCHING_SUBSCRIBERS = 16, /* PUBACK, PUBREC */ + RC5_NO_SUBSCRIPTION_EXISTED = 17, /* UNSUBACK */ + RC5_CONTINUE_AUTHENTICATION = 24, /* AUTH */ + RC5_REAUTHENTICATE = 25, /* AUTH */ -#define CONNACK_ACCEPTED 0 -#define CONNACK_REFUSED_PROTOCOL_VERSION 1 -#define CONNACK_REFUSED_IDENTIFIER_REJECTED 2 -#define CONNACK_REFUSED_SERVER_UNAVAILABLE 3 -#define CONNACK_REFUSED_BAD_USERNAME_PASSWORD 4 -#define CONNACK_REFUSED_NOT_AUTHORIZED 5 + RC5_UNSPECIFIED = 128, /* CONNACK, PUBACK, PUBREC, SUBACK, UNSUBACK, DISCONNECT */ + RC5_MALFORMED_PACKET = 129, /* CONNACK, DISCONNECT */ + RC5_PROTOCOL_ERROR = 130, /* DISCONNECT */ + RC5_IMPLEMENTATION_SPECIFIC = 131, /* CONNACK, PUBACK, PUBREC, SUBACK, UNSUBACK, DISCONNECT */ + RC5_UNSUPPORTED_PROTOCOL_VERSION = 132, /* CONNACK */ + RC5_CLIENTID_NOT_VALID = 133, /* CONNACK */ + RC5_BAD_USERNAME_OR_PASSWORD = 134, /* CONNACK */ + RC5_NOT_AUTHORIZED = 135, /* CONNACK, PUBACK, PUBREC, SUBACK, UNSUBACK, DISCONNECT */ + RC5_SERVER_UNAVAILABLE = 136, /* CONNACK */ + RC5_SERVER_BUSY = 137, /* CONNACK, DISCONNECT */ + RC5_BANNED = 138, /* CONNACK */ + RC5_SERVER_SHUTTING_DOWN = 139, /* DISCONNECT */ + RC5_BAD_AUTHENTICATION_METHOD = 140, /* CONNACK */ + RC5_KEEP_ALIVE_TIMEOUT = 141, /* DISCONNECT */ + RC5_SESSION_TAKEN_OVER = 142, /* DISCONNECT */ + RC5_TOPIC_FILTER_INVALID = 143, /* SUBACK, UNSUBACK, DISCONNECT */ + RC5_TOPIC_NAME_INVALID = 144, /* CONNACK, PUBACK, PUBREC, DISCONNECT */ + RC5_PACKET_ID_IN_USE = 145, /* PUBACK, SUBACK, UNSUBACK */ + RC5_PACKET_ID_NOT_FOUND = 146, /* PUBREL, PUBCOMP */ + RC5_RECEIVE_MAXIMUM_EXCEEDED = 147, /* DISCONNECT */ + RC5_TOPIC_ALIAS_INVALID = 148, /* DISCONNECT */ + RC5_PACKET_TOO_LARGE = 149, /* CONNACK, PUBACK, PUBREC, DISCONNECT */ + RC5_MESSAGE_RATE_TOO_HIGH = 150, /* DISCONNECT */ + RC5_QUOTA_EXCEEDED = 151, /* PUBACK, PUBREC, SUBACK, DISCONNECT */ + RC5_ADMINISTRATIVE_ACTION = 152, /* DISCONNECT */ + RC5_PAYLOAD_FORMAT_INVALID = 153, /* CONNACK, DISCONNECT */ + RC5_RETAIN_NOT_ACCEPTED = 154, /* CONNACK, DISCONNECT */ + RC5_QOS_NOT_SUPPORTED = 155, /* CONNACK, DISCONNECT */ + RC5_USE_ANOTHER_SERVER = 156, /* CONNACK, DISCONNECT */ + RC5_SERVER_MOVED = 157, /* CONNACK, DISCONNECT */ + RC5_SHARED_SUBS_NOT_SUPPORTED = 158, /* SUBACK, DISCONNECT */ + RC5_CONNECTION_RATE_EXCEEDED = 159, /* CONNACK, DISCONNECT */ + RC5_MAXIMUM_CONNECT_TIME = 160, /* DISCONNECT */ + RC5_SUBSCRIPTION_IDS_NOT_SUPPORTED = 161, /* SUBACK, DISCONNECT */ + RC5_WILDCARD_SUBS_NOT_SUPPORTED = 162, /* SUBACK, DISCONNECT */ +}; #define MQTT_MAX_PAYLOAD 268435455 From 99c6ec7f6efc2577300b568ae89a762a14d3f37f Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 30 Aug 2018 16:31:51 +0100 Subject: [PATCH 004/254] Protocol name will never be changed from MQTT. --- lib/mqtt_protocol.h | 5 ++--- lib/send_connect.c | 2 +- src/handle_connect.c | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/mqtt_protocol.h b/lib/mqtt_protocol.h index 74cfe9150a..93c7b3e1be 100644 --- a/lib/mqtt_protocol.h +++ b/lib/mqtt_protocol.h @@ -22,10 +22,9 @@ and the Eclipse Distribution License is available at #define PROTOCOL_NAME_v31 "MQIsdp" #define PROTOCOL_VERSION_v31 3 -#define PROTOCOL_NAME_v311 "MQTT" -#define PROTOCOL_VERSION_v311 4 +#define PROTOCOL_NAME "MQTT" -#define PROTOCOL_NAME_v5 "MQTT" +#define PROTOCOL_VERSION_v311 4 #define PROTOCOL_VERSION_v5 5 diff --git a/lib/send_connect.c b/lib/send_connect.c index 59802c9bb1..ef83a1432e 100644 --- a/lib/send_connect.c +++ b/lib/send_connect.c @@ -99,7 +99,7 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session if(version == MQTT_PROTOCOL_V31){ packet__write_string(packet, PROTOCOL_NAME_v31, strlen(PROTOCOL_NAME_v31)); }else if(version == MQTT_PROTOCOL_V311){ - packet__write_string(packet, PROTOCOL_NAME_v311, strlen(PROTOCOL_NAME_v311)); + packet__write_string(packet, PROTOCOL_NAME, strlen(PROTOCOL_NAME)); } #if defined(WITH_BROKER) && defined(WITH_BRIDGE) if(mosq->bridge && mosq->bridge->try_private && mosq->bridge->try_private_accepted){ diff --git a/src/handle_connect.c b/src/handle_connect.c index c3e747b307..55310459a9 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -182,7 +182,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) goto handle_connect_error; } context->protocol = mosq_p_mqtt31; - }else if(!strcmp(protocol_name, PROTOCOL_NAME_v311)){ + }else if(!strcmp(protocol_name, PROTOCOL_NAME)){ if((protocol_version&0x7F) != PROTOCOL_VERSION_v311){ if(db->config->connection_messages == true){ log__printf(NULL, MOSQ_LOG_INFO, "Invalid protocol version %d in CONNECT from %s.", From a127c93a5ae804b096af468d4f18658997794904 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 30 Aug 2018 18:55:43 +0100 Subject: [PATCH 005/254] Property identifiers. --- lib/mqtt_protocol.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/lib/mqtt_protocol.h b/lib/mqtt_protocol.h index 93c7b3e1be..bf8912e138 100644 --- a/lib/mqtt_protocol.h +++ b/lib/mqtt_protocol.h @@ -104,6 +104,36 @@ enum mqtt5_return_codes { RC5_WILDCARD_SUBS_NOT_SUPPORTED = 162, /* SUBACK, DISCONNECT */ }; +enum mqtt5_property { + PROP_PAYLOAD_FORMAT_INDICATOR = 1, /* Byte : PUBLISH, Will Properties */ + PROP_MESSAGE_EXPIRY_INTERVAL = 2, /* 4 byte int : PUBLISH, Will Properties */ + PROP_CONTENT_TYPE = 3, /* UTF-8 string : PUBLISH, Will Properties */ + PROP_RESPONSE_TOPIC = 8, /* UTF-8 string : PUBLISH, Will Properties */ + PROP_CORRELATION_DATA = 9, /* Binary Data : PUBLISH, Will Properties */ + PROP_SUBSCRIPTION_IDENTIFIER = 11, /* Variable byte int : PUBLISH, SUBSCRIBE */ + PROP_SESSION_EXPIRY_INTERVAL = 17, /* 4 byte int : CONNECT, CONNACK, DISCONNECT */ + PROP_ASSIGNED_CLIENT_IDENTIFIER = 18, /* UTF-8 string : CONNACK */ + PROP_SERVER_KEEP_ALIVE = 19, /* 2 byte int : CONNACK */ + PROP_AUTHENTICATION_METHOD = 21, /* UTF-8 string : CONNECT, CONNACK, AUTH */ + PROP_AUTHENTICATION_DATA = 22, /* Binary Data : CONNECT, CONNACK, AUTH */ + PROP_REQUEST_PROBLEM_INFO = 23, /* Byte : CONNECT */ + PROP_WILL_DELAY_INTERVAL = 24, /* 4 byte int : Will properties */ + PROP_REQUEST_RESPONSE_INFO = 25, /* Byte : CONNECT */ + PROP_RESPONSE_INFO = 26, /* UTF-8 string : CONNACK */ + PROP_SERVER_REFERENCE = 28, /* UTF-8 string : CONNACK, DISCONNECT */ + PROP_REASON_STRING = 31, /* UTF-8 string : All except Will properties */ + PROP_RECEIVE_MAXIMUM = 33, /* 2 byte int : CONNECT, CONNACK */ + PROP_TOPIC_ALIAS_MAXIMUM = 34, /* 2 byte int : CONNECT, CONNACK */ + PROP_TOPIC_ALIAS = 35, /* 2 byte int : PUBLISH */ + PROP_MAXIMUM_QOS = 36, /* Byte : CONNACK */ + PROP_RETAIN_AVAILABLE = 37, /* Byte : CONNACK */ + PROP_USER_PROPERTY = 38, /* UTF-8 string pair : All */ + PROP_MAXIMUM_PACKET_SIZE = 39, /* 4 byte int : CONNECT, CONNACK */ + PROP_WILDCARD_SUB_AVAILABLE = 40, /* Byte : CONNACK */ + PROP_SUBSCRIPTION_ID_AVAILABLE = 41, /* Byte : CONNACK */ + PROP_SHARED_SUB_AVAILABLE = 42, /* Byte : CONNACK */ +}; + #define MQTT_MAX_PAYLOAD 268435455 #endif From 33a523eea9a8b56a92722b29401ff94caf955337 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 30 Aug 2018 21:14:38 +0100 Subject: [PATCH 006/254] Add identifiers for v5. Clients know about v5, just need library support... --- client/client_shared.c | 2 ++ client/pub_client.c | 2 +- client/sub_client.c | 2 +- lib/handle_pubrel.c | 2 +- lib/mosquitto.h | 1 + lib/mosquitto_internal.h | 3 ++- man/mosquitto_pub.1.xml | 7 ++++--- man/mosquitto_sub.1.xml | 7 ++++--- src/handle_subscribe.c | 6 +++--- src/handle_unsubscribe.c | 4 ++-- 10 files changed, 21 insertions(+), 15 deletions(-) diff --git a/client/client_shared.c b/client/client_shared.c index d5d3725629..8622cbca68 100644 --- a/client/client_shared.c +++ b/client/client_shared.c @@ -655,6 +655,8 @@ int client_config_line_proc(struct mosq_config *cfg, int pub_or_sub, int argc, c cfg->protocol_version = MQTT_PROTOCOL_V31; }else if(!strcmp(argv[i+1], "mqttv311")){ cfg->protocol_version = MQTT_PROTOCOL_V311; + }else if(!strcmp(argv[i+1], "mqttv5")){ + cfg->protocol_version = MQTT_PROTOCOL_V5; }else{ fprintf(stderr, "Error: Invalid protocol version argument given.\n\n"); return 1; diff --git a/client/pub_client.c b/client/pub_client.c index 8c729b8766..9fb38889c0 100644 --- a/client/pub_client.c +++ b/client/pub_client.c @@ -257,7 +257,7 @@ void print_usage(void) printf(" -t : mqtt topic to publish to.\n"); printf(" -u : provide a username\n"); printf(" -V : specify the version of the MQTT protocol to use when connecting.\n"); - printf(" Can be mqttv31 or mqttv311. Defaults to mqttv311.\n"); + printf(" Can be mqttv5, mqttv311 or mqttv31. Defaults to mqttv311.\n"); printf(" --help : display this message.\n"); printf(" --quiet : don't print error messages.\n"); printf(" --will-payload : payload for the client Will, which is sent by the broker in case of\n"); diff --git a/client/sub_client.c b/client/sub_client.c index 3d91ed0f2e..e118044770 100644 --- a/client/sub_client.c +++ b/client/sub_client.c @@ -190,7 +190,7 @@ void print_usage(void) printf(" -U : unsubscribe from a topic. May be repeated.\n"); printf(" -v : print published messages verbosely.\n"); printf(" -V : specify the version of the MQTT protocol to use when connecting.\n"); - printf(" Can be mqttv31 or mqttv311. Defaults to mqttv311.\n"); + printf(" Can be mqttv5, mqttv311 or mqttv31. Defaults to mqttv311.\n"); #ifndef WIN32 printf(" -W : Specifies a timeout in seconds how long to process incoming MQTT messages.\n"); #endif diff --git a/lib/handle_pubrel.c b/lib/handle_pubrel.c index 7c1f137cae..4e4bf04863 100644 --- a/lib/handle_pubrel.c +++ b/lib/handle_pubrel.c @@ -45,7 +45,7 @@ int handle__pubrel(struct mosquitto_db *db, struct mosquitto *mosq) int rc; assert(mosq); - if(mosq->protocol == mosq_p_mqtt311){ + if(mosq->protocol != mosq_p_mqtt31){ if((mosq->in_packet.command&0x0F) != 0x02){ return MOSQ_ERR_PROTOCOL; } diff --git a/lib/mosquitto.h b/lib/mosquitto.h index 5baa2f1514..938382c370 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -101,6 +101,7 @@ enum mosq_opt_t { #define MQTT_PROTOCOL_V31 3 #define MQTT_PROTOCOL_V311 4 +#define MQTT_PROTOCOL_V5 5 struct mosquitto_message{ int mid; diff --git a/lib/mosquitto_internal.h b/lib/mosquitto_internal.h index de82ec3d3f..d416eccb57 100644 --- a/lib/mosquitto_internal.h +++ b/lib/mosquitto_internal.h @@ -115,7 +115,8 @@ enum mosquitto__protocol { mosq_p_invalid = 0, mosq_p_mqtt31 = 1, mosq_p_mqtt311 = 2, - mosq_p_mqtts = 3 + mosq_p_mqtts = 3, + mosq_p_mqtt5 = 4, }; enum mosquitto__threaded_state { diff --git a/man/mosquitto_pub.1.xml b/man/mosquitto_pub.1.xml index ab221c7d7c..0d6fc31482 100644 --- a/man/mosquitto_pub.1.xml +++ b/man/mosquitto_pub.1.xml @@ -11,7 +11,7 @@ mosquitto_pub - an MQTT version 3.1.1/3.1 client for publishing simple messages + an MQTT version 5/3.1.1/3.1 client for publishing simple messages @@ -85,7 +85,7 @@ Description - mosquitto_pub is a simple MQTT version 3.1.1 + mosquitto_pub is a simple MQTT version 5/3.1.1 client that will publish a single message on a topic and exit. @@ -429,7 +429,8 @@ Specify which version of the MQTT protocol should be used when connecting to the rmeote broker. Can be - or . + , or + . Defaults to . diff --git a/man/mosquitto_sub.1.xml b/man/mosquitto_sub.1.xml index 01f9c979e7..1b83ac8177 100644 --- a/man/mosquitto_sub.1.xml +++ b/man/mosquitto_sub.1.xml @@ -11,7 +11,7 @@ mosquitto_sub - an MQTT version 3.1.1/3.1 client for subscribing to topics + an MQTT version 5/3.1.1/3.1 client for subscribing to topics @@ -87,7 +87,7 @@ Description - mosquitto_sub is a simple MQTT version 3.1.1 + mosquitto_sub is a simple MQTT version 5/3.1.1 client that will subscribe to topics and print the messages that it receives. In addition to subscribing to topics, @@ -525,7 +525,8 @@ Specify which version of the MQTT protocol should be used when connecting to the rmeote broker. Can be - or . + , or + . Defaults to . diff --git a/src/handle_subscribe.c b/src/handle_subscribe.c index 3b2e2591f1..6f3286e188 100644 --- a/src/handle_subscribe.c +++ b/src/handle_subscribe.c @@ -42,7 +42,7 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) log__printf(NULL, MOSQ_LOG_DEBUG, "Received SUBSCRIBE from %s", context->id); /* FIXME - plenty of potential for memory leaks here */ - if(context->protocol == mosq_p_mqtt311){ + if(context->protocol != mosq_p_mqtt31){ if((context->in_packet.command&0x0F) != 0x02){ return MOSQ_ERR_PROTOCOL; } @@ -111,7 +111,7 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) } log__printf(NULL, MOSQ_LOG_DEBUG, "\t%s (QoS %d)", sub, qos); - if(context->protocol == mosq_p_mqtt311){ + if(context->protocol != mosq_p_mqtt31){ rc = mosquitto_acl_check(db, context, sub, 0, NULL, qos, false, MOSQ_ACL_SUBSCRIBE); switch(rc){ case MOSQ_ERR_SUCCESS: @@ -149,7 +149,7 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) } } - if(context->protocol == mosq_p_mqtt311){ + if(context->protocol != mosq_p_mqtt31){ if(payloadlen == 0){ /* No subscriptions specified, protocol error. */ return MOSQ_ERR_PROTOCOL; diff --git a/src/handle_unsubscribe.c b/src/handle_unsubscribe.c index 76b263ff95..4a5bf68064 100644 --- a/src/handle_unsubscribe.c +++ b/src/handle_unsubscribe.c @@ -40,14 +40,14 @@ int handle__unsubscribe(struct mosquitto_db *db, struct mosquitto *context) if(!context) return MOSQ_ERR_INVAL; log__printf(NULL, MOSQ_LOG_DEBUG, "Received UNSUBSCRIBE from %s", context->id); - if(context->protocol == mosq_p_mqtt311){ + if(context->protocol != mosq_p_mqtt31){ if((context->in_packet.command&0x0F) != 0x02){ return MOSQ_ERR_PROTOCOL; } } if(packet__read_uint16(&context->in_packet, &mid)) return 1; - if(context->protocol == mosq_p_mqtt311){ + if(context->protocol == mosq_p_mqtt311 || context->protocol == mosq_p_mqtt5){ if(context->in_packet.pos == context->in_packet.remaining_length){ /* No topic specified, protocol error. */ return MOSQ_ERR_PROTOCOL; From ccc97d8c96c6e679891cc85d29e75cf8c032ea0d Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 30 Aug 2018 22:49:32 +0100 Subject: [PATCH 007/254] Function for reading variable length ints from packet. --- lib/packet_mosq.c | 25 +++++++++++++++++++++++++ lib/packet_mosq.h | 1 + 2 files changed, 26 insertions(+) diff --git a/lib/packet_mosq.c b/lib/packet_mosq.c index ddfaef4987..7891656888 100644 --- a/lib/packet_mosq.c +++ b/lib/packet_mosq.c @@ -280,6 +280,31 @@ void packet__write_uint32(struct mosquitto__packet *packet, uint32_t word) } +int packet__read_varint(struct mosquitto__packet *packet, uint32_t *word) +{ + int i; + int remaining_mult = 1; + uint8_t byte; + + *word = 0; + + for(i=0; i<4; i++){ + if(packet->pos < packet->remaining_length){ + byte = packet->payload[packet->pos]; + word += (byte & 127) * remaining_mult; + remaining_mult *= 128; + packet->pos++; + if((byte & 128) == 0){ + return MOSQ_ERR_SUCCESS; + } + }else{ + return MOSQ_ERR_PROTOCOL; + } + } + return MOSQ_ERR_PROTOCOL; +} + + int packet__write(struct mosquitto *mosq) { ssize_t write_length; diff --git a/lib/packet_mosq.h b/lib/packet_mosq.h index 915605d5f0..56e27e2d46 100644 --- a/lib/packet_mosq.h +++ b/lib/packet_mosq.h @@ -32,6 +32,7 @@ int packet__read_bytes(struct mosquitto__packet *packet, void *bytes, uint32_t c int packet__read_string(struct mosquitto__packet *packet, char **str, int *length); int packet__read_uint16(struct mosquitto__packet *packet, uint16_t *word); int packet__read_uint32(struct mosquitto__packet *packet, uint32_t *word); +int packet__read_varint(struct mosquitto__packet *packet, uint32_t *word); void packet__write_byte(struct mosquitto__packet *packet, uint8_t byte); void packet__write_bytes(struct mosquitto__packet *packet, const void *bytes, uint32_t count); From 561513fdd4f4ebb8234c844d1faa18230a59327e Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sun, 30 Dec 2018 22:51:05 +0100 Subject: [PATCH 008/254] Very simple v5 CONNECT support - no properties. --- lib/options.c | 2 ++ lib/send_connect.c | 16 ++++++++++++---- src/handle_connect.c | 39 ++++++++++++++++++++++++++++----------- src/subs.c | 2 +- 4 files changed, 43 insertions(+), 16 deletions(-) diff --git a/lib/options.c b/lib/options.c index dd9f718099..5ec323023d 100644 --- a/lib/options.c +++ b/lib/options.c @@ -263,6 +263,8 @@ int mosquitto_opts_set(struct mosquitto *mosq, enum mosq_opt_t option, void *val mosq->protocol = mosq_p_mqtt31; }else if(ival == MQTT_PROTOCOL_V311){ mosq->protocol = mosq_p_mqtt311; + }else if(ival == MQTT_PROTOCOL_V5){ + mosq->protocol = mosq_p_mqtt5; }else{ return MOSQ_ERR_INVAL; } diff --git a/lib/send_connect.c b/lib/send_connect.c index ef83a1432e..2295e9b024 100644 --- a/lib/send_connect.c +++ b/lib/send_connect.c @@ -60,12 +60,15 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session password = mosq->password; #endif - if(mosq->protocol == mosq_p_mqtt31){ - version = MQTT_PROTOCOL_V31; - headerlen = 12; + if(mosq->protocol == mosq_p_mqtt5){ + version = MQTT_PROTOCOL_V5; + headerlen = 11; /* FIXME - this has a fixed property length of 0 */ }else if(mosq->protocol == mosq_p_mqtt311){ version = MQTT_PROTOCOL_V311; headerlen = 10; + }else if(mosq->protocol == mosq_p_mqtt31){ + version = MQTT_PROTOCOL_V31; + headerlen = 12; }else{ return MOSQ_ERR_INVAL; } @@ -98,7 +101,7 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session /* Variable header */ if(version == MQTT_PROTOCOL_V31){ packet__write_string(packet, PROTOCOL_NAME_v31, strlen(PROTOCOL_NAME_v31)); - }else if(version == MQTT_PROTOCOL_V311){ + }else{ packet__write_string(packet, PROTOCOL_NAME, strlen(PROTOCOL_NAME)); } #if defined(WITH_BROKER) && defined(WITH_BRIDGE) @@ -121,6 +124,11 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session packet__write_byte(packet, byte); packet__write_uint16(packet, keepalive); + if(mosq->protocol == mosq_p_mqtt5){ + /* Write properties */ + packet__write_byte(packet, 0); /* FIXME - No properties yet. */ + } + /* Payload */ packet__write_string(packet, clientid, strlen(clientid)); if(will){ diff --git a/src/handle_connect.c b/src/handle_connect.c index 55310459a9..d03d147350 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -183,7 +183,11 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) } context->protocol = mosq_p_mqtt31; }else if(!strcmp(protocol_name, PROTOCOL_NAME)){ - if((protocol_version&0x7F) != PROTOCOL_VERSION_v311){ + if((protocol_version&0x7F) == PROTOCOL_VERSION_v311){ + context->protocol = mosq_p_mqtt311; + }else if((protocol_version&0x7F) == PROTOCOL_VERSION_v5){ + context->protocol = mosq_p_mqtt5; + }else{ if(db->config->connection_messages == true){ log__printf(NULL, MOSQ_LOG_INFO, "Invalid protocol version %d in CONNECT from %s.", protocol_version, context->address); @@ -197,7 +201,6 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } - context->protocol = mosq_p_mqtt311; }else{ if(db->config->connection_messages == true){ log__printf(NULL, MOSQ_LOG_INFO, "Invalid protocol \"%s\" in CONNECT from %s.", @@ -211,7 +214,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) rc = 1; goto handle_connect_error; } - if(context->protocol == mosq_p_mqtt311){ + if(context->protocol == mosq_p_mqtt311 || context->protocol == mosq_p_mqtt5){ if((connect_flags & 0x01) != 0x00){ rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; @@ -236,6 +239,20 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) goto handle_connect_error; } + if(protocol_version == PROTOCOL_VERSION_v5){ + /* FIXME */ + uint32_t property_len; + if(packet__read_varint(&context->in_packet, &property_len)){ + rc = 1; + goto handle_connect_error; + } + if(property_len != 0){ + /* FIXME Temporary fudge because of no property support */ + rc = 1; + goto handle_connect_error; + } + } + if(packet__read_string(&context->in_packet, &client_id, &slen)){ rc = 1; goto handle_connect_error; @@ -246,7 +263,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) send__connack(context, 0, CONNACK_REFUSED_IDENTIFIER_REJECTED); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; - }else{ /* mqtt311 */ + }else{ /* mqtt311/mqtt5 */ mosquitto__free(client_id); client_id = NULL; @@ -348,7 +365,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) } } }else{ - if(context->protocol == mosq_p_mqtt311){ + if(context->protocol == mosq_p_mqtt311 || context->protocol == mosq_p_mqtt5){ if(will_qos != 0 || will_retain != 0){ rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; @@ -373,7 +390,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) if(context->protocol == mosq_p_mqtt31){ /* Password flag given, but no password. Ignore. */ password_flag = 0; - }else if(context->protocol == mosq_p_mqtt311){ + }else{ rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } @@ -386,13 +403,13 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) if(context->protocol == mosq_p_mqtt31){ /* Username flag given, but no username. Ignore. */ username_flag = 0; - }else if(context->protocol == mosq_p_mqtt311){ + }else{ rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } } }else{ - if(context->protocol == mosq_p_mqtt311){ + if(context->protocol == mosq_p_mqtt311 || context->protocol == mosq_p_mqtt5){ if(password_flag){ /* username_flag == 0 && password_flag == 1 is forbidden */ rc = MOSQ_ERR_PROTOCOL; @@ -568,7 +585,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) } } - if(context->protocol == mosq_p_mqtt311){ + if(context->protocol == mosq_p_mqtt311 || context->protocol == mosq_p_mqtt5){ if(clean_session == 0){ connect_ack |= 0x01; } @@ -664,7 +681,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) if(context->username){ log__printf(NULL, MOSQ_LOG_NOTICE, "New client connected from %s as %s (c%d, k%d, u'%s').", context->address, client_id, clean_session, context->keepalive, context->username); }else{ - log__printf(NULL, MOSQ_LOG_NOTICE, "New client connected from %s as %s (c%d, k%d).", context->address, client_id, clean_session, context->keepalive); + log__printf(NULL, MOSQ_LOG_NOTICE, "New client connected from %s as %s (p%d, c%d, k%d).", context->address, client_id, context->protocol, clean_session, context->keepalive); } } @@ -721,7 +738,7 @@ int handle__disconnect(struct mosquitto_db *db, struct mosquitto *context) return MOSQ_ERR_PROTOCOL; } log__printf(NULL, MOSQ_LOG_DEBUG, "Received DISCONNECT from %s", context->id); - if(context->protocol == mosq_p_mqtt311){ + if(context->protocol == mosq_p_mqtt311 || context->protocol == mosq_p_mqtt5){ if((context->in_packet.command&0x0F) != 0x00){ do_disconnect(db, context); return MOSQ_ERR_PROTOCOL; diff --git a/src/subs.c b/src/subs.c index 0716fe1945..83eeeafd0f 100644 --- a/src/subs.c +++ b/src/subs.c @@ -266,7 +266,7 @@ static int sub__add_recurse(struct mosquitto_db *db, struct mosquitto *context, if(context->protocol == mosq_p_mqtt31){ return -1; }else{ - /* mqttv311 requires retained messages are resent on + /* mqttv311/mqttv5 requires retained messages are resent on * resubscribe. */ return 0; } From 4ee6941188e53f98efa414790f154daa2ee39afc Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 19 Sep 2018 11:13:50 +0100 Subject: [PATCH 009/254] Primitive v5 CONNACK support - no properties. --- lib/mosquitto_internal.h | 2 +- src/send_connack.c | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/mosquitto_internal.h b/lib/mosquitto_internal.h index d416eccb57..b49bcff7f6 100644 --- a/lib/mosquitto_internal.h +++ b/lib/mosquitto_internal.h @@ -116,7 +116,7 @@ enum mosquitto__protocol { mosq_p_mqtt31 = 1, mosq_p_mqtt311 = 2, mosq_p_mqtts = 3, - mosq_p_mqtt5 = 4, + mosq_p_mqtt5 = 5, }; enum mosquitto__threaded_state { diff --git a/src/send_connack.c b/src/send_connack.c index 2a15ae3dae..3bb6ea7c3e 100644 --- a/src/send_connack.c +++ b/src/send_connack.c @@ -39,7 +39,12 @@ int send__connack(struct mosquitto *context, int ack, int result) if(!packet) return MOSQ_ERR_NOMEM; packet->command = CONNACK; - packet->remaining_length = 2; + if(context->protocol == mosq_p_mqtt5){ + /* FIXME - proper property support */ + packet->remaining_length = 3; + }else{ + packet->remaining_length = 2; + } rc = packet__alloc(packet); if(rc){ mosquitto__free(packet); @@ -47,6 +52,9 @@ int send__connack(struct mosquitto *context, int ack, int result) } packet->payload[packet->pos+0] = ack; packet->payload[packet->pos+1] = result; + if(context->protocol == mosq_p_mqtt5){ + packet->payload[packet->pos+2] = 0; + } return packet__queue(context, packet); } From 17b37097903af7fcfbbe0cd3da82ca5c6f7f436f Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 2 Oct 2018 14:07:23 +0100 Subject: [PATCH 010/254] Fix varint reading. --- lib/packet_mosq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/packet_mosq.c b/lib/packet_mosq.c index 7891656888..f2d2a2422f 100644 --- a/lib/packet_mosq.c +++ b/lib/packet_mosq.c @@ -291,7 +291,7 @@ int packet__read_varint(struct mosquitto__packet *packet, uint32_t *word) for(i=0; i<4; i++){ if(packet->pos < packet->remaining_length){ byte = packet->payload[packet->pos]; - word += (byte & 127) * remaining_mult; + *word += (byte & 127) * remaining_mult; remaining_mult *= 128; packet->pos++; if((byte & 128) == 0){ From 1488992ea8ba4391f5ba293463da66bbbd1087bd Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 2 Oct 2018 16:27:40 +0100 Subject: [PATCH 011/254] Naive reading of MQTT 5 properties. No processing done. --- lib/packet_mosq.c | 4 +- lib/packet_mosq.h | 2 +- lib/property_mosq.c | 261 +++++++++++++++++++++++++++++++++++++++++++ lib/property_mosq.h | 24 ++++ src/CMakeLists.txt | 1 + src/Makefile | 4 + src/handle_connect.c | 14 +-- src/handle_publish.c | 6 + 8 files changed, 303 insertions(+), 13 deletions(-) create mode 100644 lib/property_mosq.c create mode 100644 lib/property_mosq.h diff --git a/lib/packet_mosq.c b/lib/packet_mosq.c index f2d2a2422f..dd29968a7a 100644 --- a/lib/packet_mosq.c +++ b/lib/packet_mosq.c @@ -280,16 +280,18 @@ void packet__write_uint32(struct mosquitto__packet *packet, uint32_t word) } -int packet__read_varint(struct mosquitto__packet *packet, uint32_t *word) +int packet__read_varint(struct mosquitto__packet *packet, int32_t *word, uint8_t *bytes) { int i; int remaining_mult = 1; uint8_t byte; *word = 0; + if(bytes) (*bytes) = 0; for(i=0; i<4; i++){ if(packet->pos < packet->remaining_length){ + if(bytes) (*bytes)++; byte = packet->payload[packet->pos]; *word += (byte & 127) * remaining_mult; remaining_mult *= 128; diff --git a/lib/packet_mosq.h b/lib/packet_mosq.h index 56e27e2d46..f7bcdeb19b 100644 --- a/lib/packet_mosq.h +++ b/lib/packet_mosq.h @@ -32,7 +32,7 @@ int packet__read_bytes(struct mosquitto__packet *packet, void *bytes, uint32_t c int packet__read_string(struct mosquitto__packet *packet, char **str, int *length); int packet__read_uint16(struct mosquitto__packet *packet, uint16_t *word); int packet__read_uint32(struct mosquitto__packet *packet, uint32_t *word); -int packet__read_varint(struct mosquitto__packet *packet, uint32_t *word); +int packet__read_varint(struct mosquitto__packet *packet, int32_t *word, uint8_t *bytes); void packet__write_byte(struct mosquitto__packet *packet, uint8_t byte); void packet__write_bytes(struct mosquitto__packet *packet, const void *bytes, uint32_t count); diff --git a/lib/property_mosq.c b/lib/property_mosq.c new file mode 100644 index 0000000000..73450d58cb --- /dev/null +++ b/lib/property_mosq.c @@ -0,0 +1,261 @@ +/* +Copyright (c) 2018 Roger Light + +All rights reserved. This program and the accompanying materials +are made available under the terms of the Eclipse Public License v1.0 +and Eclipse Distribution License v1.0 which accompany this distribution. + +The Eclipse Public License is available at + http://www.eclipse.org/legal/epl-v10.html +and the Eclipse Distribution License is available at + http://www.eclipse.org/org/documents/edl-v10.php. + +Contributors: + Roger Light - initial implementation and documentation. +*/ + +#include "config.h" + +#include +#include +#include + +#include "logging_mosq.h" +#include "memory_mosq.h" +#include "mqtt_protocol.h" +#include "packet_mosq.h" +#include "property_mosq.h" + +int property__read(struct mosquitto__packet *packet, uint32_t *len) +{ + int rc; + uint8_t byte; + uint16_t int16; + uint32_t int32; + char *str; + int slen; + *len -= 14; + + rc = packet__read_byte(packet, &byte); + if(rc) return rc; + *len -= 1; + + switch(byte){ + case PROP_PAYLOAD_FORMAT_INDICATOR: + rc = packet__read_byte(packet, &byte); + if(rc) return rc; + *len -= 1; /* byte */ + log__printf(NULL, MOSQ_LOG_DEBUG, "Payload format indicator: %d", byte); + break; + + case PROP_MESSAGE_EXPIRY_INTERVAL: + rc = packet__read_uint32(packet, &int32); + if(rc) return rc; + *len -= 4; /* uint32 */ + log__printf(NULL, MOSQ_LOG_DEBUG, "Message expiry: %d", int32); + break; + + case PROP_CONTENT_TYPE: + rc = packet__read_string(packet, &str, &slen); + if(rc) return rc; + *len -= 2 - slen; /* int16, string len */ + log__printf(NULL, MOSQ_LOG_DEBUG, "Content type: %s", str); + break; + + case PROP_RESPONSE_TOPIC: + rc = packet__read_string(packet, &str, &slen); + if(rc) return rc; + *len -= 2 - slen; /* int16, string len */ + log__printf(NULL, MOSQ_LOG_DEBUG, "Response topic: %s", str); + break; + + case PROP_CORRELATION_DATA: + rc = packet__read_string(packet, &str, &slen); + if(rc) return rc; + *len -= 2 - slen; /* int16, string len */ + log__printf(NULL, MOSQ_LOG_DEBUG, "Correlation data: %s", str); + break; + + case PROP_SUBSCRIPTION_IDENTIFIER: + rc = packet__read_varint(packet, &int32, &byte); + *len -= byte; + if(rc) return rc; + log__printf(NULL, MOSQ_LOG_DEBUG, "Subscription identifier: %d", int32); + break; + + case PROP_SESSION_EXPIRY_INTERVAL: + rc = packet__read_uint32(packet, &int32); + if(rc) return rc; + *len -= 4; /* uint32 */ + log__printf(NULL, MOSQ_LOG_DEBUG, "Session expiry: %d", int32); + break; + + case PROP_ASSIGNED_CLIENT_IDENTIFIER: + rc = packet__read_string(packet, &str, &slen); + if(rc) return rc; + *len -= 2 - slen; /* int16, string len */ + log__printf(NULL, MOSQ_LOG_DEBUG, "Assigned client identifier: %s", str); + break; + + case PROP_SERVER_KEEP_ALIVE: + rc = packet__read_uint16(packet, &int16); + if(rc) return rc; + *len -= 2; /* uint16 */ + log__printf(NULL, MOSQ_LOG_DEBUG, "Session expiry: %d", int16); + break; + + case PROP_AUTHENTICATION_METHOD: + rc = packet__read_string(packet, &str, &slen); + if(rc) return rc; + *len -= 2 - slen; /* int16, string len */ + log__printf(NULL, MOSQ_LOG_DEBUG, "Authentication method: %s", str); + break; + + case PROP_AUTHENTICATION_DATA: + rc = packet__read_string(packet, &str, &slen); + if(rc) return rc; + *len -= 2 - slen; /* int16, string len */ + log__printf(NULL, MOSQ_LOG_DEBUG, "Authentication data: %s", str); + break; + + case PROP_REQUEST_PROBLEM_INFO: + rc = packet__read_byte(packet, &byte); + if(rc) return rc; + *len -= 1; /* byte */ + log__printf(NULL, MOSQ_LOG_DEBUG, "Request problem information: %d", byte); + break; + + case PROP_WILL_DELAY_INTERVAL: + rc = packet__read_uint32(packet, &int32); + if(rc) return rc; + *len -= 4; /* uint32 */ + log__printf(NULL, MOSQ_LOG_DEBUG, "Will delay interval: %d", int32); + break; + + case PROP_REQUEST_RESPONSE_INFO: + rc = packet__read_byte(packet, &byte); + if(rc) return rc; + *len -= 1; /* byte */ + log__printf(NULL, MOSQ_LOG_DEBUG, "Request response information: %d", byte); + break; + + case PROP_RESPONSE_INFO: + rc = packet__read_string(packet, &str, &slen); + if(rc) return rc; + *len -= 2 - slen; /* int16, string len */ + log__printf(NULL, MOSQ_LOG_DEBUG, "Response information: %s", str); + break; + + case PROP_SERVER_REFERENCE: + rc = packet__read_string(packet, &str, &slen); + if(rc) return rc; + *len -= 2 - slen; /* int16, string len */ + log__printf(NULL, MOSQ_LOG_DEBUG, "Server reference: %s", str); + break; + + case PROP_REASON_STRING: + rc = packet__read_string(packet, &str, &slen); + if(rc) return rc; + *len -= 2 - slen; /* int16, string len */ + log__printf(NULL, MOSQ_LOG_DEBUG, "Reason string: %s", str); + break; + + case PROP_RECEIVE_MAXIMUM: + rc = packet__read_uint16(packet, &int16); + if(rc) return rc; + *len -= 2; /* uint16 */ + log__printf(NULL, MOSQ_LOG_DEBUG, "Receive maximum: %d", int16); + break; + + case PROP_TOPIC_ALIAS_MAXIMUM: + rc = packet__read_uint16(packet, &int16); + if(rc) return rc; + *len -= 2; /* uint16 */ + log__printf(NULL, MOSQ_LOG_DEBUG, "Topic alias maximum: %d", int16); + break; + + case PROP_TOPIC_ALIAS: + rc = packet__read_uint16(packet, &int16); + if(rc) return rc; + *len -= 2; /* uint16 */ + log__printf(NULL, MOSQ_LOG_DEBUG, "Topic alias: %d", int16); + break; + + case PROP_MAXIMUM_QOS: + rc = packet__read_byte(packet, &byte); + if(rc) return rc; + *len -= 1; /* byte */ + log__printf(NULL, MOSQ_LOG_DEBUG, "Maximum QoS: %d", byte); + break; + + case PROP_RETAIN_AVAILABLE: + rc = packet__read_byte(packet, &byte); + if(rc) return rc; + *len -= 1; /* byte */ + log__printf(NULL, MOSQ_LOG_DEBUG, "Retain available: %d", byte); + break; + + case PROP_USER_PROPERTY: + rc = packet__read_string(packet, &str, &slen); + if(rc) return rc; + *len -= 2 - slen; /* int16, string len */ + log__printf(NULL, MOSQ_LOG_DEBUG, "User property name: %s", str); + + rc = packet__read_string(packet, &str, &slen); + if(rc) return rc; + *len -= 2 - slen; /* int16, string len */ + log__printf(NULL, MOSQ_LOG_DEBUG, "User property value: %s", str); + break; + + case PROP_MAXIMUM_PACKET_SIZE: + rc = packet__read_uint32(packet, &int32); + if(rc) return rc; + *len -= 4; /* uint32 */ + log__printf(NULL, MOSQ_LOG_DEBUG, "Maximum packet size: %d", int32); + break; + + case PROP_WILDCARD_SUB_AVAILABLE: + rc = packet__read_byte(packet, &byte); + if(rc) return rc; + *len -= 1; /* byte */ + log__printf(NULL, MOSQ_LOG_DEBUG, "Wildcard subscription available: %d", byte); + break; + + case PROP_SUBSCRIPTION_ID_AVAILABLE: + rc = packet__read_byte(packet, &byte); + if(rc) return rc; + *len -= 1; /* byte */ + log__printf(NULL, MOSQ_LOG_DEBUG, "Subscription identifier available: %d", byte); + break; + + case PROP_SHARED_SUB_AVAILABLE: + rc = packet__read_byte(packet, &byte); + if(rc) return rc; + *len -= 1; /* byte */ + log__printf(NULL, MOSQ_LOG_DEBUG, "Shared subscription available: %d", byte); + break; + + default: + log__printf(NULL, MOSQ_LOG_DEBUG, "Unsupported property type: %d", byte); + return 1; + } + + return MOSQ_ERR_SUCCESS; +} + + +int property__read_all(struct mosquitto__packet *packet) +{ + int rc; + int32_t proplen; + + rc = packet__read_varint(packet, &proplen, NULL); + if(rc) return rc; + + while(proplen > 0){ + rc = property__read(packet, &proplen); + if(rc) return rc; + } + + return MOSQ_ERR_SUCCESS; +} diff --git a/lib/property_mosq.h b/lib/property_mosq.h new file mode 100644 index 0000000000..7fea9a763c --- /dev/null +++ b/lib/property_mosq.h @@ -0,0 +1,24 @@ +/* +Copyright (c) 2018 Roger Light + +All rights reserved. This program and the accompanying materials +are made available under the terms of the Eclipse Public License v1.0 +and Eclipse Distribution License v1.0 which accompany this distribution. + +The Eclipse Public License is available at + http://www.eclipse.org/legal/epl-v10.html +and the Eclipse Distribution License is available at + http://www.eclipse.org/org/documents/edl-v10.php. + +Contributors: + Roger Light - initial implementation and documentation. +*/ +#ifndef PROPERTY_MOSQ_H +#define PROPERTY_MOSQ_H + +#include "mosquitto_internal.h" +#include "mosquitto.h" + +int property__read_all(struct mosquitto__packet *packet); + +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dab82a481e..c4d5378617 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -29,6 +29,7 @@ set (MOSQ_SRCS ../lib/packet_mosq.c ../lib/packet_mosq.h persist.c persist.h plugin.c + ../lib/property_mosq.c ../lib/property_mosq.h read_handle.c ../lib/read_handle.h subs.c diff --git a/src/Makefile b/src/Makefile index 227f6623e7..dd6a68a498 100644 --- a/src/Makefile +++ b/src/Makefile @@ -31,6 +31,7 @@ OBJS= mosquitto.o \ net.o \ net_mosq.o \ packet_mosq.o \ + property_mosq.o \ persist.o \ plugin.o \ read_handle.o \ @@ -130,6 +131,9 @@ persist.o : persist.c persist.h mosquitto_broker_internal.h packet_mosq.o : ../lib/packet_mosq.c ../lib/packet_mosq.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ +property_mosq.o : ../lib/property_mosq.c ../lib/property_mosq.h + ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ + plugin.o : plugin.c mosquitto_plugin.h mosquitto_broker_internal.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ diff --git a/src/handle_connect.c b/src/handle_connect.c index d03d147350..2384baab8e 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -23,6 +23,7 @@ and the Eclipse Distribution License is available at #include "mqtt_protocol.h" #include "memory_mosq.h" #include "packet_mosq.h" +#include "property_mosq.h" #include "send_mosq.h" #include "sys_tree.h" #include "time_mosq.h" @@ -240,17 +241,8 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) } if(protocol_version == PROTOCOL_VERSION_v5){ - /* FIXME */ - uint32_t property_len; - if(packet__read_varint(&context->in_packet, &property_len)){ - rc = 1; - goto handle_connect_error; - } - if(property_len != 0){ - /* FIXME Temporary fudge because of no property support */ - rc = 1; - goto handle_connect_error; - } + rc = property__read_all(&context->in_packet); + if(rc) return rc; } if(packet__read_string(&context->in_packet, &client_id, &slen)){ diff --git a/src/handle_publish.c b/src/handle_publish.c index a6e990ef14..a6a10d4fe4 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -24,6 +24,7 @@ and the Eclipse Distribution License is available at #include "mqtt_protocol.h" #include "memory_mosq.h" #include "packet_mosq.h" +#include "property_mosq.h" #include "read_handle.h" #include "send_mosq.h" #include "sys_tree.h" @@ -135,6 +136,11 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) } } + if(context->protocol == mosq_p_mqtt5){ + rc = property__read_all(&context->in_packet); + if(rc) return rc; + } + payloadlen = context->in_packet.remaining_length - context->in_packet.pos; G_PUB_BYTES_RECEIVED_INC(payloadlen); if(context->listener && context->listener->mount_point){ From 99a1c0e43a0ef226156645ef8ea40da4be276909 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 3 Oct 2018 10:23:58 +0100 Subject: [PATCH 012/254] Move simple datatype reading functions to own file. This facilitates easier testing. --- lib/CMakeLists.txt | 1 + lib/Makefile | 4 + lib/packet_datatypes.c | 202 +++++++++++++++++++++++++++++++++++++++++ lib/packet_mosq.c | 157 -------------------------------- src/CMakeLists.txt | 1 + src/Makefile | 4 + 6 files changed, 212 insertions(+), 157 deletions(-) create mode 100644 lib/packet_datatypes.c diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 48f0c89c07..603e9f1571 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -53,6 +53,7 @@ set(C_SRC mqtt_protocol.h net_mosq.c net_mosq.h options.c + packet_datatypes.c packet_mosq.c packet_mosq.h read_handle.c read_handle.h send_connect.c diff --git a/lib/Makefile b/lib/Makefile index b768c81bd2..4d0f2833ee 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -21,6 +21,7 @@ MOSQ_OBJS=mosquitto.o \ messages_mosq.o \ net_mosq.o \ options.o \ + packet_datatypes.o \ packet_mosq.o \ read_handle.o \ send_connect.o \ @@ -136,6 +137,9 @@ net_mosq.o : net_mosq.c net_mosq.h options.o : options.c mosquitto.h mosquitto_internal.h ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ +packet_datatypes.o : packet_datatypes.c packet_mosq.h + ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ + packet_mosq.o : packet_mosq.c packet_mosq.h ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ diff --git a/lib/packet_datatypes.c b/lib/packet_datatypes.c new file mode 100644 index 0000000000..7acb7151ae --- /dev/null +++ b/lib/packet_datatypes.c @@ -0,0 +1,202 @@ +/* +Copyright (c) 2009-2018 Roger Light + +All rights reserved. This program and the accompanying materials +are made available under the terms of the Eclipse Public License v1.0 +and Eclipse Distribution License v1.0 which accompany this distribution. + +The Eclipse Public License is available at + http://www.eclipse.org/legal/epl-v10.html +and the Eclipse Distribution License is available at + http://www.eclipse.org/org/documents/edl-v10.php. + +Contributors: + Roger Light - initial implementation and documentation. +*/ + +#include "config.h" + +#include +#include +#include + +#ifdef WITH_BROKER +# include "mosquitto_broker_internal.h" +# ifdef WITH_WEBSOCKETS +# include +# endif +#else +# include "read_handle.h" +#endif + +#include "memory_mosq.h" +#include "mqtt_protocol.h" +#include "net_mosq.h" +#include "packet_mosq.h" +#include "read_handle.h" +#ifdef WITH_BROKER +# include "sys_tree.h" +#else +# define G_BYTES_RECEIVED_INC(A) +# define G_BYTES_SENT_INC(A) +# define G_MSGS_SENT_INC(A) +# define G_PUB_MSGS_SENT_INC(A) +#endif + + +int packet__read_byte(struct mosquitto__packet *packet, uint8_t *byte) +{ + assert(packet); + if(packet->pos+1 > packet->remaining_length) return MOSQ_ERR_PROTOCOL; + + *byte = packet->payload[packet->pos]; + packet->pos++; + + return MOSQ_ERR_SUCCESS; +} + + +void packet__write_byte(struct mosquitto__packet *packet, uint8_t byte) +{ + assert(packet); + assert(packet->pos+1 <= packet->packet_length); + + packet->payload[packet->pos] = byte; + packet->pos++; +} + + +int packet__read_bytes(struct mosquitto__packet *packet, void *bytes, uint32_t count) +{ + assert(packet); + if(packet->pos+count > packet->remaining_length) return MOSQ_ERR_PROTOCOL; + + memcpy(bytes, &(packet->payload[packet->pos]), count); + packet->pos += count; + + return MOSQ_ERR_SUCCESS; +} + + +void packet__write_bytes(struct mosquitto__packet *packet, const void *bytes, uint32_t count) +{ + assert(packet); + assert(packet->pos+count <= packet->packet_length); + + memcpy(&(packet->payload[packet->pos]), bytes, count); + packet->pos += count; +} + + +int packet__read_string(struct mosquitto__packet *packet, char **str, int *length) +{ + uint16_t slen; + int rc; + + assert(packet); + rc = packet__read_uint16(packet, &slen); + if(rc) return rc; + + if(packet->pos+slen > packet->remaining_length) return MOSQ_ERR_PROTOCOL; + + *str = mosquitto__malloc(slen+1); + if(*str){ + memcpy(*str, &(packet->payload[packet->pos]), slen); + (*str)[slen] = '\0'; + packet->pos += slen; + }else{ + return MOSQ_ERR_NOMEM; + } + + *length = slen; + return MOSQ_ERR_SUCCESS; +} + + +void packet__write_string(struct mosquitto__packet *packet, const char *str, uint16_t length) +{ + assert(packet); + packet__write_uint16(packet, length); + packet__write_bytes(packet, str, length); +} + + +int packet__read_uint16(struct mosquitto__packet *packet, uint16_t *word) +{ + uint8_t msb, lsb; + + assert(packet); + if(packet->pos+2 > packet->remaining_length) return MOSQ_ERR_PROTOCOL; + + msb = packet->payload[packet->pos]; + packet->pos++; + lsb = packet->payload[packet->pos]; + packet->pos++; + + *word = (msb<<8) + lsb; + + return MOSQ_ERR_SUCCESS; +} + + +void packet__write_uint16(struct mosquitto__packet *packet, uint16_t word) +{ + packet__write_byte(packet, MOSQ_MSB(word)); + packet__write_byte(packet, MOSQ_LSB(word)); +} + + +int packet__read_uint32(struct mosquitto__packet *packet, uint32_t *word) +{ + uint32_t val = 0; + int i; + + assert(packet); + if(packet->pos+4 > packet->remaining_length) return MOSQ_ERR_PROTOCOL; + + for(i=0; i<4; i++){ + val = (val << 8) + packet->payload[packet->pos]; + packet->pos++; + } + + *word = val; + + return MOSQ_ERR_SUCCESS; +} + + +void packet__write_uint32(struct mosquitto__packet *packet, uint32_t word) +{ + packet__write_byte(packet, (word & 0xFF000000) >> 24); + packet__write_byte(packet, (word & 0x00FF0000) >> 16); + packet__write_byte(packet, (word & 0x0000FF00) >> 8); + packet__write_byte(packet, (word & 0x000000FF)); +} + + +int packet__read_varint(struct mosquitto__packet *packet, int32_t *word, uint8_t *bytes) +{ + int i; + int remaining_mult = 1; + uint8_t byte; + + *word = 0; + if(bytes) (*bytes) = 0; + + for(i=0; i<4; i++){ + if(packet->pos < packet->remaining_length){ + if(bytes) (*bytes)++; + byte = packet->payload[packet->pos]; + *word += (byte & 127) * remaining_mult; + remaining_mult *= 128; + packet->pos++; + if((byte & 128) == 0){ + return MOSQ_ERR_SUCCESS; + } + }else{ + return MOSQ_ERR_PROTOCOL; + } + } + return MOSQ_ERR_PROTOCOL; +} + diff --git a/lib/packet_mosq.c b/lib/packet_mosq.c index dd29968a7a..e7ffe0b459 100644 --- a/lib/packet_mosq.c +++ b/lib/packet_mosq.c @@ -150,163 +150,6 @@ int packet__queue(struct mosquitto *mosq, struct mosquitto__packet *packet) } -int packet__read_byte(struct mosquitto__packet *packet, uint8_t *byte) -{ - assert(packet); - if(packet->pos+1 > packet->remaining_length) return MOSQ_ERR_PROTOCOL; - - *byte = packet->payload[packet->pos]; - packet->pos++; - - return MOSQ_ERR_SUCCESS; -} - - -void packet__write_byte(struct mosquitto__packet *packet, uint8_t byte) -{ - assert(packet); - assert(packet->pos+1 <= packet->packet_length); - - packet->payload[packet->pos] = byte; - packet->pos++; -} - - -int packet__read_bytes(struct mosquitto__packet *packet, void *bytes, uint32_t count) -{ - assert(packet); - if(packet->pos+count > packet->remaining_length) return MOSQ_ERR_PROTOCOL; - - memcpy(bytes, &(packet->payload[packet->pos]), count); - packet->pos += count; - - return MOSQ_ERR_SUCCESS; -} - - -void packet__write_bytes(struct mosquitto__packet *packet, const void *bytes, uint32_t count) -{ - assert(packet); - assert(packet->pos+count <= packet->packet_length); - - memcpy(&(packet->payload[packet->pos]), bytes, count); - packet->pos += count; -} - - -int packet__read_string(struct mosquitto__packet *packet, char **str, int *length) -{ - uint16_t slen; - int rc; - - assert(packet); - rc = packet__read_uint16(packet, &slen); - if(rc) return rc; - - if(packet->pos+slen > packet->remaining_length) return MOSQ_ERR_PROTOCOL; - - *str = mosquitto__malloc(slen+1); - if(*str){ - memcpy(*str, &(packet->payload[packet->pos]), slen); - (*str)[slen] = '\0'; - packet->pos += slen; - }else{ - return MOSQ_ERR_NOMEM; - } - - *length = slen; - return MOSQ_ERR_SUCCESS; -} - - -void packet__write_string(struct mosquitto__packet *packet, const char *str, uint16_t length) -{ - assert(packet); - packet__write_uint16(packet, length); - packet__write_bytes(packet, str, length); -} - - -int packet__read_uint16(struct mosquitto__packet *packet, uint16_t *word) -{ - uint8_t msb, lsb; - - assert(packet); - if(packet->pos+2 > packet->remaining_length) return MOSQ_ERR_PROTOCOL; - - msb = packet->payload[packet->pos]; - packet->pos++; - lsb = packet->payload[packet->pos]; - packet->pos++; - - *word = (msb<<8) + lsb; - - return MOSQ_ERR_SUCCESS; -} - - -void packet__write_uint16(struct mosquitto__packet *packet, uint16_t word) -{ - packet__write_byte(packet, MOSQ_MSB(word)); - packet__write_byte(packet, MOSQ_LSB(word)); -} - - -int packet__read_uint32(struct mosquitto__packet *packet, uint32_t *word) -{ - uint32_t val = 0; - int i; - - assert(packet); - if(packet->pos+4 > packet->remaining_length) return MOSQ_ERR_PROTOCOL; - - for(i=0; i<4; i++){ - val = (val << 8) + packet->payload[packet->pos]; - packet->pos++; - } - - *word = val; - - return MOSQ_ERR_SUCCESS; -} - - -void packet__write_uint32(struct mosquitto__packet *packet, uint32_t word) -{ - packet__write_byte(packet, (word & 0xFF000000) >> 24); - packet__write_byte(packet, (word & 0x00FF0000) >> 16); - packet__write_byte(packet, (word & 0x0000FF00) >> 8); - packet__write_byte(packet, (word & 0x000000FF)); -} - - -int packet__read_varint(struct mosquitto__packet *packet, int32_t *word, uint8_t *bytes) -{ - int i; - int remaining_mult = 1; - uint8_t byte; - - *word = 0; - if(bytes) (*bytes) = 0; - - for(i=0; i<4; i++){ - if(packet->pos < packet->remaining_length){ - if(bytes) (*bytes)++; - byte = packet->payload[packet->pos]; - *word += (byte & 127) * remaining_mult; - remaining_mult *= 128; - packet->pos++; - if((byte & 128) == 0){ - return MOSQ_ERR_SUCCESS; - } - }else{ - return MOSQ_ERR_PROTOCOL; - } - } - return MOSQ_ERR_PROTOCOL; -} - - int packet__write(struct mosquitto *mosq) { ssize_t write_length; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c4d5378617..d14ac49488 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -26,6 +26,7 @@ set (MOSQ_SRCS mosquitto_broker.h mosquitto_broker_internal.h net.c ../lib/net_mosq.c ../lib/net_mosq.h + ../lib/packet_datatypes.c ../lib/packet_mosq.c ../lib/packet_mosq.h persist.c persist.h plugin.c diff --git a/src/Makefile b/src/Makefile index dd6a68a498..f981e2e255 100644 --- a/src/Makefile +++ b/src/Makefile @@ -30,6 +30,7 @@ OBJS= mosquitto.o \ memory_mosq.o \ net.o \ net_mosq.o \ + packet_datatypes.o \ packet_mosq.o \ property_mosq.o \ persist.o \ @@ -128,6 +129,9 @@ net_mosq.o : ../lib/net_mosq.c ../lib/net_mosq.h persist.o : persist.c persist.h mosquitto_broker_internal.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ +packet_datatypes.o : ../lib/packet_datatypes.c ../lib/packet_mosq.h + ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ + packet_mosq.o : ../lib/packet_mosq.c ../lib/packet_mosq.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ From b6b8da1fa6ac7171690104cef0423d11fd048bdb Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 3 Oct 2018 11:29:57 +0100 Subject: [PATCH 013/254] Variable Byte Integer reading tests. --- .gitignore | 16 ++- lib/packet_datatypes.c | 22 ++-- lib/packet_mosq.h | 2 +- test/Makefile | 1 + test/unit/Makefile | 27 +++++ test/unit/datatypes.c | 259 +++++++++++++++++++++++++++++++++++++++++ test/unit/test.c | 27 +++++ 7 files changed, 341 insertions(+), 13 deletions(-) create mode 100644 test/unit/Makefile create mode 100644 test/unit/datatypes.c create mode 100644 test/unit/test.c diff --git a/.gitignore b/.gitignore index 1ae8697375..0bf9912815 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,15 @@ +*.db +*.gcda +*.gcno +*.exe *.o +*.old +*.pyc *.so -*.exe -*.db +*.vglog + c/*.test cpp/*.test -*.pyc -*.vglog build/ @@ -50,5 +54,9 @@ test/ssl/*.csr test/lib/c/*.test test/lib/cpp/*.test +test/unit/coverage.info +test/unit/mosq_test +test/unit/out + www/cache/ __pycache__ diff --git a/lib/packet_datatypes.c b/lib/packet_datatypes.c index 7acb7151ae..3065f124a4 100644 --- a/lib/packet_datatypes.c +++ b/lib/packet_datatypes.c @@ -174,24 +174,30 @@ void packet__write_uint32(struct mosquitto__packet *packet, uint32_t word) } -int packet__read_varint(struct mosquitto__packet *packet, int32_t *word, uint8_t *bytes) +int packet__read_varint(struct mosquitto__packet *packet, int32_t *word, int8_t *bytes) { int i; - int remaining_mult = 1; uint8_t byte; - - *word = 0; - if(bytes) (*bytes) = 0; + int remaining_mult = 1; + int32_t lword = 0; + uint8_t lbytes = 0; for(i=0; i<4; i++){ if(packet->pos < packet->remaining_length){ - if(bytes) (*bytes)++; + lbytes++; byte = packet->payload[packet->pos]; - *word += (byte & 127) * remaining_mult; + lword += (byte & 127) * remaining_mult; remaining_mult *= 128; packet->pos++; if((byte & 128) == 0){ - return MOSQ_ERR_SUCCESS; + if(lbytes > 1 && byte == 0){ + /* Catch overlong encodings */ + return MOSQ_ERR_PROTOCOL; + }else{ + *word = lword; + if(bytes) (*bytes) = lbytes; + return MOSQ_ERR_SUCCESS; + } } }else{ return MOSQ_ERR_PROTOCOL; diff --git a/lib/packet_mosq.h b/lib/packet_mosq.h index f7bcdeb19b..5b5b5c69de 100644 --- a/lib/packet_mosq.h +++ b/lib/packet_mosq.h @@ -32,7 +32,7 @@ int packet__read_bytes(struct mosquitto__packet *packet, void *bytes, uint32_t c int packet__read_string(struct mosquitto__packet *packet, char **str, int *length); int packet__read_uint16(struct mosquitto__packet *packet, uint16_t *word); int packet__read_uint32(struct mosquitto__packet *packet, uint32_t *word); -int packet__read_varint(struct mosquitto__packet *packet, int32_t *word, uint8_t *bytes); +int packet__read_varint(struct mosquitto__packet *packet, int32_t *word, int8_t *bytes); void packet__write_byte(struct mosquitto__packet *packet, uint8_t byte); void packet__write_bytes(struct mosquitto__packet *packet, const void *bytes, uint32_t count); diff --git a/test/Makefile b/test/Makefile index cf94ea7395..e3f6cdf69b 100644 --- a/test/Makefile +++ b/test/Makefile @@ -14,6 +14,7 @@ all : fake_user msgsps_pub msgsps_sub test : $(MAKE) -C broker test $(MAKE) -C lib test + $(MAKE) -C unit test ptest : $(MAKE) -C broker ptest diff --git a/test/unit/Makefile b/test/unit/Makefile new file mode 100644 index 0000000000..4d8d7388f8 --- /dev/null +++ b/test/unit/Makefile @@ -0,0 +1,27 @@ +include ../../config.mk + +.PHONY: all test clean coverage + +CFLAGS=-I../.. -I../../lib -coverage +TEST_LDFLAGS=-lcunit -coverage + +all : test + +packet_datatypes.o : ../../lib/packet_datatypes.c + $(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^ + +memory_mosq.o : ../../lib/memory_mosq.c + $(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^ + +mosq_test : test.o datatypes.o memory_mosq.o packet_datatypes.o + $(CROSS_COMPILE)$(CC) -o $@ $^ ${TEST_LDFLAGS} + +test : mosq_test + ./mosq_test + +clean : + -rm -f test *.o + +coverage : + lcov --capture --directory . --output-file coverage.info + genhtml coverage.info --output-directory out diff --git a/test/unit/datatypes.c b/test/unit/datatypes.c new file mode 100644 index 0000000000..60a0d215ee --- /dev/null +++ b/test/unit/datatypes.c @@ -0,0 +1,259 @@ +#include +#include + +#include "packet_mosq.h" + +static void varint_read_helper( + uint8_t *payload, + int remaining_length, + int rc_expected, + int32_t value_expected, + int8_t bytes_expected) +{ + struct mosquitto__packet packet; + int32_t value = -1; + int8_t bytes = -1; + int rc; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.payload = payload; + packet.remaining_length = remaining_length; + rc = packet__read_varint(&packet, &value, &bytes); + CU_ASSERT_EQUAL(rc, rc_expected); + CU_ASSERT_EQUAL(value, value_expected); + CU_ASSERT_EQUAL(bytes, bytes_expected); +} + + +/* This tests reading a Variable Byte Integer from an incoming packet. + * + * It tests: + * * Empty packet + */ +static void TEST_varint_read_empty(void) +{ + struct mosquitto__packet packet; + int rc; + + /* Empty packet */ + varint_read_helper(NULL, 0, MOSQ_ERR_PROTOCOL, -1, -1); +} + + +/* This tests reading a Variable Byte Integer from an incoming packet. + * + * It tests: + * * Truncated packets (varint encoding is longer than data) + */ +static void TEST_varint_read_truncated(void) +{ + struct mosquitto__packet packet; + uint8_t payload[20]; + int rc; + + /* Varint bigger than packet */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0x80; + varint_read_helper(payload, 1, MOSQ_ERR_PROTOCOL, -1, -1); + + /* Varint bigger than packet */ + memset(payload, 1, sizeof(payload)); + payload[0] = 0x80; + payload[1] = 0x80; + varint_read_helper(payload, 2, MOSQ_ERR_PROTOCOL, -1, -1); + + /* Varint bigger than packet */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0x80; + payload[1] = 0x80; + payload[2] = 0x80; + varint_read_helper(payload, 3, MOSQ_ERR_PROTOCOL, -1, -1); + + /* Varint bigger than packet */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0x80; + payload[1] = 0x80; + payload[2] = 0x80; + payload[3] = 0x80; + varint_read_helper(payload, 4, MOSQ_ERR_PROTOCOL, -1, -1); +} + + +/* This tests reading a Variable Byte Integer from an incoming packet. + * + * It tests: + * * Correct values on boundaries of 1, 2, 3, 4 byte encodings + */ +static void TEST_varint_read_boundaries(void) +{ + struct mosquitto__packet packet; + uint8_t payload[20]; + int rc; + + /* Value = 0 */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0x00; + varint_read_helper(payload, 1, MOSQ_ERR_SUCCESS, 0, 1); + + /* Value = 127 (just beneath the crossover to two bytes */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0x7F; + varint_read_helper(payload, 1, MOSQ_ERR_SUCCESS, 127, 1); + + /* Value = 128 (just after the crossover to two bytes */ + memset(payload, 0, sizeof(payload)); + packet.payload = payload; + payload[0] = 0x80; + payload[1] = 0x01; + varint_read_helper(payload, 2, MOSQ_ERR_SUCCESS, 128, 2); + + /* Value = 16383 (just before the crossover to three bytes */ + memset(payload, 0, sizeof(payload)); + packet.payload = payload; + payload[0] = 0xFF; + payload[1] = 0x7F; + varint_read_helper(payload, 2, MOSQ_ERR_SUCCESS, 16383, 2); + + /* Value = 16384 (just after the crossover to three bytes */ + memset(payload, 0, sizeof(payload)); + packet.payload = payload; + payload[0] = 0x80; + payload[1] = 0x80; + payload[2] = 0x01; + varint_read_helper(payload, 3, MOSQ_ERR_SUCCESS, 16384, 3); + + /* Value = 2,097,151 (just before the crossover to four bytes */ + memset(payload, 0, sizeof(payload)); + packet.payload = payload; + payload[0] = 0xFF; + payload[1] = 0xFF; + payload[2] = 0x7F; + varint_read_helper(payload, 3, MOSQ_ERR_SUCCESS, 2097151, 3); + + /* Value = 2,097,152 (just after the crossover to four bytes */ + memset(payload, 0, sizeof(payload)); + packet.payload = payload; + payload[0] = 0x80; + payload[1] = 0x80; + payload[2] = 0x80; + payload[3] = 0x01; + varint_read_helper(payload, 4, MOSQ_ERR_SUCCESS, 2097152, 4); + + /* Value = 268,435,455 (highest value allowed) */ + memset(payload, 0, sizeof(payload)); + packet.payload = payload; + payload[0] = 0xFF; + payload[1] = 0xFF; + payload[2] = 0xFF; + payload[3] = 0x7F; + varint_read_helper(payload, 4, MOSQ_ERR_SUCCESS, 268435455, 4); +} + +/* This tests reading a Variable Byte Integer from an incoming packet. + * + * It tests: + * * Too long encoding (5 bytes) + */ +static void TEST_varint_read_5_bytes(void) +{ + struct mosquitto__packet packet; + uint8_t payload[20]; + int rc; + + /* Value = 268,435,456 (one higher than highest value allowed) */ + memset(payload, 0, sizeof(payload)); + packet.payload = payload; + payload[0] = 0x80; + payload[1] = 0x80; + payload[2] = 0x80; + payload[3] = 0x80; + payload[4] = 0x01; + varint_read_helper(payload, 5, MOSQ_ERR_PROTOCOL, -1, -1); +} + + +/* This tests reading a Variable Byte Integer from an incoming packet. + * + * It tests: + * * Overlong encodings (e.g. 2 bytes to encode "1") + */ +static void TEST_varint_read_overlong_encoding(void) +{ + struct mosquitto__packet packet; + uint8_t payload[20]; + int rc; + + /* Overlong encoding of 0 (1 byte value encoded as 2 bytes) */ + memset(payload, 0, sizeof(payload)); + packet.payload = payload; + payload[0] = 0x80; + payload[1] = 0x00; + varint_read_helper(payload, 2, MOSQ_ERR_PROTOCOL, -1, -1); + + /* Overlong encoding of 127 (1 byte value encoded as 2 bytes) */ + memset(payload, 0, sizeof(payload)); + packet.payload = payload; + payload[0] = 0xFF; + payload[1] = 0x00; + varint_read_helper(payload, 2, MOSQ_ERR_PROTOCOL, -1, -1); + + /* Overlong encoding of 128 (2 byte value encoded as 3 bytes) */ + memset(payload, 0, sizeof(payload)); + packet.payload = payload; + payload[0] = 0x80; + payload[1] = 0x81; + payload[2] = 0x00; + varint_read_helper(payload, 3, MOSQ_ERR_PROTOCOL, -1, -1); + + /* Overlong encoding of 16,383 (2 byte value encoded as 3 bytes) */ + memset(payload, 0, sizeof(payload)); + packet.payload = payload; + payload[0] = 0xFF; + payload[1] = 0xFF; + payload[2] = 0x00; + varint_read_helper(payload, 3, MOSQ_ERR_PROTOCOL, -1, -1); + + /* Overlong encoding of 16,384 (3 byte value encoded as 4 bytes) */ + memset(payload, 0, sizeof(payload)); + packet.payload = payload; + payload[0] = 0x80; + payload[1] = 0x80; + payload[2] = 0x81; + payload[3] = 0x00; + varint_read_helper(payload, 4, MOSQ_ERR_PROTOCOL, -1, -1); + + /* Overlong encoding of 2,097,151 (3 byte value encoded as 4 bytes) */ + memset(payload, 0, sizeof(payload)); + packet.payload = payload; + payload[0] = 0xFF; + payload[1] = 0xFF; + payload[2] = 0xFF; + payload[3] = 0x00; + varint_read_helper(payload, 4, MOSQ_ERR_PROTOCOL, -1, -1); +} + + +int init_datatype_tests(void) +{ + CU_pSuite test_suite = NULL; + + test_suite = CU_add_suite("datatypes", NULL, NULL); + if(!test_suite){ + printf("Error adding CUnit test suite.\n"); + return 1; + } + + if(0 + || !CU_add_test(test_suite, "Variable Byte Integer read (empty packet)", TEST_varint_read_empty) + || !CU_add_test(test_suite, "Variable Byte Integer read (truncated packets)", TEST_varint_read_truncated) + || !CU_add_test(test_suite, "Variable Byte Integer read (encoding boundaries)", TEST_varint_read_boundaries) + || !CU_add_test(test_suite, "Variable Byte Integer read (five byte encoding)", TEST_varint_read_5_bytes) + || !CU_add_test(test_suite, "Variable Byte Integer read (overlong encodings)", TEST_varint_read_overlong_encoding) + ){ + + printf("Error adding datatypes CUnit tests.\n"); + return 1; + } + + return 0; +} diff --git a/test/unit/test.c b/test/unit/test.c new file mode 100644 index 0000000000..3071fead8f --- /dev/null +++ b/test/unit/test.c @@ -0,0 +1,27 @@ +#include + +#include +#include + +int init_datatype_tests(void); + +int main(int argc, char *argv[]) +{ + + if(CU_initialize_registry() != CUE_SUCCESS){ + printf("Error initializing CUnit registry.\n"); + return 1; + } + + if(init_datatype_tests()){ + CU_cleanup_registry(); + return 1; + } + + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + CU_cleanup_registry(); + + return 0; +} + From ff67672a2c4ef4f1695352a848c3c04882b40999 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 3 Oct 2018 12:04:26 +0100 Subject: [PATCH 014/254] Two Byte Integer read tests. --- test/unit/datatypes.c | 106 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/test/unit/datatypes.c b/test/unit/datatypes.c index 60a0d215ee..2a224f5ed6 100644 --- a/test/unit/datatypes.c +++ b/test/unit/datatypes.c @@ -3,6 +3,25 @@ #include "packet_mosq.h" +static void uint16_read_helper( + uint8_t *payload, + int remaining_length, + int rc_expected, + uint16_t value_expected) +{ + struct mosquitto__packet packet; + uint16_t value = 0; + int rc; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.payload = payload; + packet.remaining_length = remaining_length; + rc = packet__read_uint16(&packet, &value); + CU_ASSERT_EQUAL(rc, rc_expected); + CU_ASSERT_EQUAL(value, value_expected); +} + + static void varint_read_helper( uint8_t *payload, int remaining_length, @@ -25,6 +44,86 @@ static void varint_read_helper( } +/* ======================================================================== + * TWO BYTE INTEGER TESTS + * ======================================================================== */ + +/* This tests reading a Two Byte Integer from an incoming packet. + * + * It tests: + * * Empty packets + * * Truncated packets + * * Success at boundaries + */ +static void TEST_uint16_read_empty(void) +{ + struct mosquitto__packet packet; + uint8_t payload[20]; + int rc; + + /* Empty packet */ + uint16_read_helper(NULL, 0, MOSQ_ERR_PROTOCOL, 0); +} + + +/* This tests reading a Two Byte Integer from an incoming packet. + * + * It tests: + * * Empty packets + * * Truncated packets + * * Success at boundaries + */ +static void TEST_uint16_read_truncated(void) +{ + struct mosquitto__packet packet; + uint8_t payload[20]; + int rc; + + /* 1 byte packet */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0x38; + uint16_read_helper(payload, 1, MOSQ_ERR_PROTOCOL, 0); +} + + +/* This tests reading a Two Byte Integer from an incoming packet. + * + * It tests: + * * Empty packets + * * Truncated packets + * * Success at boundaries + */ +static void TEST_uint16_read_success(void) +{ + struct mosquitto__packet packet; + uint8_t payload[20]; + int rc; + + /* 0 value */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0x00; + payload[1] = 0x00; + uint16_read_helper(payload, 2, MOSQ_ERR_SUCCESS, 0x0000); + + /* Endian check */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0x38; + payload[1] = 0xF3; + uint16_read_helper(payload, 2, MOSQ_ERR_SUCCESS, 0x38F3); + + /* 65,535 value */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0xFF; + payload[1] = 0xFF; + uint16_read_helper(payload, 2, MOSQ_ERR_SUCCESS, 0xFFFF); + +} + + +/* ======================================================================== + * VARIABLE BYTE INTEGER TESTS + * ======================================================================== */ + /* This tests reading a Variable Byte Integer from an incoming packet. * * It tests: @@ -233,6 +332,10 @@ static void TEST_varint_read_overlong_encoding(void) } +/* ======================================================================== + * TEST SUITE SETUP + * ======================================================================== */ + int init_datatype_tests(void) { CU_pSuite test_suite = NULL; @@ -244,6 +347,9 @@ int init_datatype_tests(void) } if(0 + || !CU_add_test(test_suite, "Two Byte Integer read (empty packet)", TEST_uint16_read_empty) + || !CU_add_test(test_suite, "Two Byte Integer read (truncated packet)", TEST_uint16_read_truncated) + || !CU_add_test(test_suite, "Two Byte Integer read (success values)", TEST_uint16_read_success) || !CU_add_test(test_suite, "Variable Byte Integer read (empty packet)", TEST_varint_read_empty) || !CU_add_test(test_suite, "Variable Byte Integer read (truncated packets)", TEST_varint_read_truncated) || !CU_add_test(test_suite, "Variable Byte Integer read (encoding boundaries)", TEST_varint_read_boundaries) From d157e5c41ebb58507cf58429faf9d6bfb446ae62 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 3 Oct 2018 12:40:16 +0100 Subject: [PATCH 015/254] Four Byte Integer read tests. --- test/unit/datatypes.c | 121 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 115 insertions(+), 6 deletions(-) diff --git a/test/unit/datatypes.c b/test/unit/datatypes.c index 2a224f5ed6..cb29befd1c 100644 --- a/test/unit/datatypes.c +++ b/test/unit/datatypes.c @@ -22,6 +22,25 @@ static void uint16_read_helper( } +static void uint32_read_helper( + uint8_t *payload, + int remaining_length, + int rc_expected, + uint32_t value_expected) +{ + struct mosquitto__packet packet; + uint32_t value = 0; + int rc; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.payload = payload; + packet.remaining_length = remaining_length; + rc = packet__read_uint32(&packet, &value); + CU_ASSERT_EQUAL(rc, rc_expected); + CU_ASSERT_EQUAL(value, value_expected); +} + + static void varint_read_helper( uint8_t *payload, int remaining_length, @@ -52,8 +71,6 @@ static void varint_read_helper( * * It tests: * * Empty packets - * * Truncated packets - * * Success at boundaries */ static void TEST_uint16_read_empty(void) { @@ -69,9 +86,7 @@ static void TEST_uint16_read_empty(void) /* This tests reading a Two Byte Integer from an incoming packet. * * It tests: - * * Empty packets * * Truncated packets - * * Success at boundaries */ static void TEST_uint16_read_truncated(void) { @@ -89,9 +104,8 @@ static void TEST_uint16_read_truncated(void) /* This tests reading a Two Byte Integer from an incoming packet. * * It tests: - * * Empty packets - * * Truncated packets * * Success at boundaries + * * Endianness */ static void TEST_uint16_read_success(void) { @@ -120,6 +134,98 @@ static void TEST_uint16_read_success(void) } + + +/* ======================================================================== + * FOUR BYTE INTEGER TESTS + * ======================================================================== */ + +/* This tests reading a Four Byte Integer from an incoming packet. + * + * It tests: + * * Empty packets + */ +static void TEST_uint32_read_empty(void) +{ + struct mosquitto__packet packet; + uint8_t payload[20]; + int rc; + + /* Empty packet */ + uint32_read_helper(NULL, 0, MOSQ_ERR_PROTOCOL, 0); +} + + +/* This tests reading a Four Byte Integer from an incoming packet. + * + * It tests: + * * Truncated packets + */ +static void TEST_uint32_read_truncated(void) +{ + struct mosquitto__packet packet; + uint8_t payload[20]; + int rc; + + /* 1 byte packet */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0x38; + uint32_read_helper(payload, 1, MOSQ_ERR_PROTOCOL, 0); + + /* 2 byte packet */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0x38; + payload[1] = 0x38; + uint32_read_helper(payload, 2, MOSQ_ERR_PROTOCOL, 0); + + /* 3 byte packet */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0x38; + payload[1] = 0x38; + payload[2] = 0x38; + uint32_read_helper(payload, 3, MOSQ_ERR_PROTOCOL, 0); +} + + +/* This tests reading a Four Byte Integer from an incoming packet. + * + * It tests: + * * Success at boundaries + * * Endianness + */ +static void TEST_uint32_read_success(void) +{ + struct mosquitto__packet packet; + uint8_t payload[20]; + int rc; + + /* 0 value */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0x00; + payload[1] = 0x00; + payload[2] = 0x00; + payload[3] = 0x00; + uint32_read_helper(payload, 4, MOSQ_ERR_SUCCESS, 0x00000000); + + /* Endian check */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0x12; + payload[1] = 0x34; + payload[2] = 0x56; + payload[3] = 0x78; + uint32_read_helper(payload, 4, MOSQ_ERR_SUCCESS, 0x12345678); + + /* Biggest value */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0xFF; + payload[1] = 0xFF; + payload[2] = 0xFF; + payload[3] = 0xFF; + uint32_read_helper(payload, 4, MOSQ_ERR_SUCCESS, 0xFFFFFFFF); + +} + + /* ======================================================================== * VARIABLE BYTE INTEGER TESTS * ======================================================================== */ @@ -350,6 +456,9 @@ int init_datatype_tests(void) || !CU_add_test(test_suite, "Two Byte Integer read (empty packet)", TEST_uint16_read_empty) || !CU_add_test(test_suite, "Two Byte Integer read (truncated packet)", TEST_uint16_read_truncated) || !CU_add_test(test_suite, "Two Byte Integer read (success values)", TEST_uint16_read_success) + || !CU_add_test(test_suite, "Four Byte Integer read (empty packet)", TEST_uint32_read_empty) + || !CU_add_test(test_suite, "Four Byte Integer read (truncated packet)", TEST_uint32_read_truncated) + || !CU_add_test(test_suite, "Four Byte Integer read (success values)", TEST_uint32_read_success) || !CU_add_test(test_suite, "Variable Byte Integer read (empty packet)", TEST_varint_read_empty) || !CU_add_test(test_suite, "Variable Byte Integer read (truncated packets)", TEST_varint_read_truncated) || !CU_add_test(test_suite, "Variable Byte Integer read (encoding boundaries)", TEST_varint_read_boundaries) From d532253f109d10d63671e447645f142f38925cac Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 3 Oct 2018 13:02:58 +0100 Subject: [PATCH 016/254] Byte read tests. --- test/unit/datatypes.c | 70 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 4 deletions(-) diff --git a/test/unit/datatypes.c b/test/unit/datatypes.c index cb29befd1c..25b3e0d733 100644 --- a/test/unit/datatypes.c +++ b/test/unit/datatypes.c @@ -3,6 +3,25 @@ #include "packet_mosq.h" +static void byte_read_helper( + uint8_t *payload, + int remaining_length, + int rc_expected, + uint8_t value_expected) +{ + struct mosquitto__packet packet; + uint8_t value = 0; + int rc; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.payload = payload; + packet.remaining_length = remaining_length; + rc = packet__read_byte(&packet, &value); + CU_ASSERT_EQUAL(rc, rc_expected); + CU_ASSERT_EQUAL(value, value_expected); +} + + static void uint16_read_helper( uint8_t *payload, int remaining_length, @@ -63,6 +82,51 @@ static void varint_read_helper( } +/* ======================================================================== + * BYTE INTEGER TESTS + * ======================================================================== */ + +/* This tests reading a Byte from an incoming packet. + * + * It tests: + * * Empty packets + */ +static void TEST_byte_read_empty(void) +{ + /* Empty packet */ + byte_read_helper(NULL, 0, MOSQ_ERR_PROTOCOL, 0); +} + + +/* This tests reading a Byte from an incoming packet. + * + * It tests: + * * Success at boundaries + */ +static void TEST_byte_read_success(void) +{ + struct mosquitto__packet packet; + uint8_t payload[20]; + int rc; + + /* 0 value */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0x00; + byte_read_helper(payload, 1, MOSQ_ERR_SUCCESS, 0x00); + + /* Middle */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0x1F; + byte_read_helper(payload, 1, MOSQ_ERR_SUCCESS, 0x1F); + + /* 65,535 value */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0xFF; + byte_read_helper(payload, 1, MOSQ_ERR_SUCCESS, 0xFF); + +} + + /* ======================================================================== * TWO BYTE INTEGER TESTS * ======================================================================== */ @@ -75,7 +139,6 @@ static void varint_read_helper( static void TEST_uint16_read_empty(void) { struct mosquitto__packet packet; - uint8_t payload[20]; int rc; /* Empty packet */ @@ -134,8 +197,6 @@ static void TEST_uint16_read_success(void) } - - /* ======================================================================== * FOUR BYTE INTEGER TESTS * ======================================================================== */ @@ -148,7 +209,6 @@ static void TEST_uint16_read_success(void) static void TEST_uint32_read_empty(void) { struct mosquitto__packet packet; - uint8_t payload[20]; int rc; /* Empty packet */ @@ -453,6 +513,8 @@ int init_datatype_tests(void) } if(0 + || !CU_add_test(test_suite, "Byte read (empty packet)", TEST_byte_read_empty) + || !CU_add_test(test_suite, "Byte read (success values)", TEST_byte_read_success) || !CU_add_test(test_suite, "Two Byte Integer read (empty packet)", TEST_uint16_read_empty) || !CU_add_test(test_suite, "Two Byte Integer read (truncated packet)", TEST_uint16_read_truncated) || !CU_add_test(test_suite, "Two Byte Integer read (success values)", TEST_uint16_read_success) From 400db91166f7bf594f5c62a99d507528727153d6 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 3 Oct 2018 15:04:24 +0100 Subject: [PATCH 017/254] Handle UTF-8 validation in packet__read_string. --- lib/packet_datatypes.c | 6 ++++++ src/handle_connect.c | 19 +------------------ src/handle_publish.c | 5 ----- src/handle_subscribe.c | 7 ------- src/handle_unsubscribe.c | 7 ------- 5 files changed, 7 insertions(+), 37 deletions(-) diff --git a/lib/packet_datatypes.c b/lib/packet_datatypes.c index 3065f124a4..9e31974fe1 100644 --- a/lib/packet_datatypes.c +++ b/lib/packet_datatypes.c @@ -108,6 +108,12 @@ int packet__read_string(struct mosquitto__packet *packet, char **str, int *lengt return MOSQ_ERR_NOMEM; } + if(mosquitto_validate_utf8(*str, slen)){ + mosquitto__free(*str); + *str = NULL; + return MOSQ_ERR_MALFORMED_UTF8; + } + *length = slen; return MOSQ_ERR_SUCCESS; } diff --git a/src/handle_connect.c b/src/handle_connect.c index 2384baab8e..e2780daf0d 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -292,11 +292,6 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) } } - if(mosquitto_validate_utf8(client_id, slen) != MOSQ_ERR_SUCCESS){ - rc = 1; - goto handle_connect_error; - } - if(will){ will_struct = mosquitto__calloc(1, sizeof(struct mosquitto_message)); if(!will_struct){ @@ -311,14 +306,6 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) rc = 1; goto handle_connect_error; } - if(mosquitto_validate_utf8(will_topic, slen)){ - log__printf(NULL, MOSQ_LOG_INFO, - "Malformed UTF-8 in will topic string from %s, disconnecting.", - client_id); - - rc = 1; - goto handle_connect_error; - } if(context->listener->mount_point){ slen = strlen(context->listener->mount_point) + strlen(will_topic) + 1; @@ -368,12 +355,8 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) if(username_flag){ rc = packet__read_string(&context->in_packet, &username, &slen); if(rc == MOSQ_ERR_SUCCESS){ - if(mosquitto_validate_utf8(username, slen) != MOSQ_ERR_SUCCESS){ - rc = MOSQ_ERR_PROTOCOL; - goto handle_connect_error; - } - if(password_flag){ + /* FIXME - MQTT 5 this is binary data */ rc = packet__read_string(&context->in_packet, &password, &slen); if(rc == MOSQ_ERR_NOMEM){ rc = MOSQ_ERR_NOMEM; diff --git a/src/handle_publish.c b/src/handle_publish.c index a6a10d4fe4..e9aa701675 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -70,11 +70,6 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) return 1; } - if(mosquitto_validate_utf8(topic, slen) != MOSQ_ERR_SUCCESS){ - mosquitto__free(topic); - return 1; - } - #ifdef WITH_BRIDGE if(context->bridge && context->bridge->topics && context->bridge->topic_remapping){ for(i=0; ibridge->topic_count; i++){ diff --git a/src/handle_subscribe.c b/src/handle_subscribe.c index 6f3286e188..e2f49e377f 100644 --- a/src/handle_subscribe.c +++ b/src/handle_subscribe.c @@ -73,13 +73,6 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) mosquitto__free(payload); return 1; } - if(mosquitto_validate_utf8(sub, slen)){ - log__printf(NULL, MOSQ_LOG_INFO, - "Malformed UTF-8 in subscription string from %s, disconnecting.", - context->id); - mosquitto__free(sub); - return 1; - } if(packet__read_byte(&context->in_packet, &qos)){ mosquitto__free(sub); diff --git a/src/handle_unsubscribe.c b/src/handle_unsubscribe.c index 4a5bf68064..3bb8bd4aa0 100644 --- a/src/handle_unsubscribe.c +++ b/src/handle_unsubscribe.c @@ -74,13 +74,6 @@ int handle__unsubscribe(struct mosquitto_db *db, struct mosquitto *context) mosquitto__free(sub); return 1; } - if(mosquitto_validate_utf8(sub, slen)){ - log__printf(NULL, MOSQ_LOG_INFO, - "Malformed UTF-8 in unsubscription string from %s, disconnecting.", - context->id); - mosquitto__free(sub); - return 1; - } log__printf(NULL, MOSQ_LOG_DEBUG, "\t%s", sub); sub__remove(db, context, sub, db->subs); From 0fad0bd02530ccdc5b15dbb1510de9b3466287a7 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 3 Oct 2018 15:04:55 +0100 Subject: [PATCH 018/254] UTF-8 String read tests. --- test/unit/Makefile | 13 ++- test/unit/datatypes.c | 216 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 184 insertions(+), 45 deletions(-) diff --git a/test/unit/Makefile b/test/unit/Makefile index 4d8d7388f8..e6e679c009 100644 --- a/test/unit/Makefile +++ b/test/unit/Makefile @@ -2,19 +2,22 @@ include ../../config.mk .PHONY: all test clean coverage -CFLAGS=-I../.. -I../../lib -coverage +CFLAGS=-I../.. -I../../lib -coverage -Wall TEST_LDFLAGS=-lcunit -coverage all : test -packet_datatypes.o : ../../lib/packet_datatypes.c - $(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^ +mosq_test : test.o datatypes.o memory_mosq.o packet_datatypes.o utf8_mosq.o + $(CROSS_COMPILE)$(CC) -o $@ $^ ${TEST_LDFLAGS} memory_mosq.o : ../../lib/memory_mosq.c $(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^ -mosq_test : test.o datatypes.o memory_mosq.o packet_datatypes.o - $(CROSS_COMPILE)$(CC) -o $@ $^ ${TEST_LDFLAGS} +packet_datatypes.o : ../../lib/packet_datatypes.c + $(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^ + +utf8_mosq.o : ../../lib/utf8_mosq.c + $(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^ test : mosq_test ./mosq_test diff --git a/test/unit/datatypes.c b/test/unit/datatypes.c index 25b3e0d733..05439e25b3 100644 --- a/test/unit/datatypes.c +++ b/test/unit/datatypes.c @@ -82,6 +82,33 @@ static void varint_read_helper( } +static void string_read_helper( + uint8_t *payload, + int remaining_length, + int rc_expected, + const char *value_expected, + int length_expected) +{ + struct mosquitto__packet packet; + char *value = NULL; + int length = -1; + int rc; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.payload = payload; + packet.remaining_length = remaining_length; + rc = packet__read_string(&packet, &value, &length); + CU_ASSERT_EQUAL(rc, rc_expected); + if(value_expected){ + CU_ASSERT_NSTRING_EQUAL(value, value_expected, length_expected); + }else{ + CU_ASSERT_EQUAL(value, NULL); + } + CU_ASSERT_EQUAL(length, length_expected); + free(value); +} + + /* ======================================================================== * BYTE INTEGER TESTS * ======================================================================== */ @@ -105,9 +132,7 @@ static void TEST_byte_read_empty(void) */ static void TEST_byte_read_success(void) { - struct mosquitto__packet packet; uint8_t payload[20]; - int rc; /* 0 value */ memset(payload, 0, sizeof(payload)); @@ -138,9 +163,6 @@ static void TEST_byte_read_success(void) */ static void TEST_uint16_read_empty(void) { - struct mosquitto__packet packet; - int rc; - /* Empty packet */ uint16_read_helper(NULL, 0, MOSQ_ERR_PROTOCOL, 0); } @@ -153,9 +175,7 @@ static void TEST_uint16_read_empty(void) */ static void TEST_uint16_read_truncated(void) { - struct mosquitto__packet packet; uint8_t payload[20]; - int rc; /* 1 byte packet */ memset(payload, 0, sizeof(payload)); @@ -172,9 +192,7 @@ static void TEST_uint16_read_truncated(void) */ static void TEST_uint16_read_success(void) { - struct mosquitto__packet packet; uint8_t payload[20]; - int rc; /* 0 value */ memset(payload, 0, sizeof(payload)); @@ -208,9 +226,6 @@ static void TEST_uint16_read_success(void) */ static void TEST_uint32_read_empty(void) { - struct mosquitto__packet packet; - int rc; - /* Empty packet */ uint32_read_helper(NULL, 0, MOSQ_ERR_PROTOCOL, 0); } @@ -223,9 +238,7 @@ static void TEST_uint32_read_empty(void) */ static void TEST_uint32_read_truncated(void) { - struct mosquitto__packet packet; uint8_t payload[20]; - int rc; /* 1 byte packet */ memset(payload, 0, sizeof(payload)); @@ -255,9 +268,7 @@ static void TEST_uint32_read_truncated(void) */ static void TEST_uint32_read_success(void) { - struct mosquitto__packet packet; uint8_t payload[20]; - int rc; /* 0 value */ memset(payload, 0, sizeof(payload)); @@ -297,9 +308,6 @@ static void TEST_uint32_read_success(void) */ static void TEST_varint_read_empty(void) { - struct mosquitto__packet packet; - int rc; - /* Empty packet */ varint_read_helper(NULL, 0, MOSQ_ERR_PROTOCOL, -1, -1); } @@ -312,9 +320,7 @@ static void TEST_varint_read_empty(void) */ static void TEST_varint_read_truncated(void) { - struct mosquitto__packet packet; uint8_t payload[20]; - int rc; /* Varint bigger than packet */ memset(payload, 0, sizeof(payload)); @@ -351,9 +357,7 @@ static void TEST_varint_read_truncated(void) */ static void TEST_varint_read_boundaries(void) { - struct mosquitto__packet packet; uint8_t payload[20]; - int rc; /* Value = 0 */ memset(payload, 0, sizeof(payload)); @@ -367,21 +371,18 @@ static void TEST_varint_read_boundaries(void) /* Value = 128 (just after the crossover to two bytes */ memset(payload, 0, sizeof(payload)); - packet.payload = payload; payload[0] = 0x80; payload[1] = 0x01; varint_read_helper(payload, 2, MOSQ_ERR_SUCCESS, 128, 2); /* Value = 16383 (just before the crossover to three bytes */ memset(payload, 0, sizeof(payload)); - packet.payload = payload; payload[0] = 0xFF; payload[1] = 0x7F; varint_read_helper(payload, 2, MOSQ_ERR_SUCCESS, 16383, 2); /* Value = 16384 (just after the crossover to three bytes */ memset(payload, 0, sizeof(payload)); - packet.payload = payload; payload[0] = 0x80; payload[1] = 0x80; payload[2] = 0x01; @@ -389,7 +390,6 @@ static void TEST_varint_read_boundaries(void) /* Value = 2,097,151 (just before the crossover to four bytes */ memset(payload, 0, sizeof(payload)); - packet.payload = payload; payload[0] = 0xFF; payload[1] = 0xFF; payload[2] = 0x7F; @@ -397,7 +397,6 @@ static void TEST_varint_read_boundaries(void) /* Value = 2,097,152 (just after the crossover to four bytes */ memset(payload, 0, sizeof(payload)); - packet.payload = payload; payload[0] = 0x80; payload[1] = 0x80; payload[2] = 0x80; @@ -406,7 +405,6 @@ static void TEST_varint_read_boundaries(void) /* Value = 268,435,455 (highest value allowed) */ memset(payload, 0, sizeof(payload)); - packet.payload = payload; payload[0] = 0xFF; payload[1] = 0xFF; payload[2] = 0xFF; @@ -421,13 +419,10 @@ static void TEST_varint_read_boundaries(void) */ static void TEST_varint_read_5_bytes(void) { - struct mosquitto__packet packet; uint8_t payload[20]; - int rc; /* Value = 268,435,456 (one higher than highest value allowed) */ memset(payload, 0, sizeof(payload)); - packet.payload = payload; payload[0] = 0x80; payload[1] = 0x80; payload[2] = 0x80; @@ -444,27 +439,22 @@ static void TEST_varint_read_5_bytes(void) */ static void TEST_varint_read_overlong_encoding(void) { - struct mosquitto__packet packet; uint8_t payload[20]; - int rc; /* Overlong encoding of 0 (1 byte value encoded as 2 bytes) */ memset(payload, 0, sizeof(payload)); - packet.payload = payload; payload[0] = 0x80; payload[1] = 0x00; varint_read_helper(payload, 2, MOSQ_ERR_PROTOCOL, -1, -1); /* Overlong encoding of 127 (1 byte value encoded as 2 bytes) */ memset(payload, 0, sizeof(payload)); - packet.payload = payload; payload[0] = 0xFF; payload[1] = 0x00; varint_read_helper(payload, 2, MOSQ_ERR_PROTOCOL, -1, -1); /* Overlong encoding of 128 (2 byte value encoded as 3 bytes) */ memset(payload, 0, sizeof(payload)); - packet.payload = payload; payload[0] = 0x80; payload[1] = 0x81; payload[2] = 0x00; @@ -472,7 +462,6 @@ static void TEST_varint_read_overlong_encoding(void) /* Overlong encoding of 16,383 (2 byte value encoded as 3 bytes) */ memset(payload, 0, sizeof(payload)); - packet.payload = payload; payload[0] = 0xFF; payload[1] = 0xFF; payload[2] = 0x00; @@ -480,7 +469,6 @@ static void TEST_varint_read_overlong_encoding(void) /* Overlong encoding of 16,384 (3 byte value encoded as 4 bytes) */ memset(payload, 0, sizeof(payload)); - packet.payload = payload; payload[0] = 0x80; payload[1] = 0x80; payload[2] = 0x81; @@ -489,7 +477,6 @@ static void TEST_varint_read_overlong_encoding(void) /* Overlong encoding of 2,097,151 (3 byte value encoded as 4 bytes) */ memset(payload, 0, sizeof(payload)); - packet.payload = payload; payload[0] = 0xFF; payload[1] = 0xFF; payload[2] = 0xFF; @@ -498,6 +485,149 @@ static void TEST_varint_read_overlong_encoding(void) } +/* ======================================================================== + * UTF-8 STRING TESTS + * ======================================================================== */ + +/* This tests reading a UTF-8 Encoded String from an incoming packet. + * + * It tests: + * * Empty packet + */ +static void TEST_string_read_empty(void) +{ + string_read_helper(NULL, 0, MOSQ_ERR_PROTOCOL, NULL, -1); +} + +/* This tests reading a UTF-8 Encoded String from an incoming packet. + * + * It tests: + * * Truncated packets + */ +static void TEST_string_read_truncated(void) +{ + uint8_t payload[20]; + + /* 1 byte packet */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0x02; + string_read_helper(payload, 1, MOSQ_ERR_PROTOCOL, NULL, -1); + + /* 2 byte packet */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0x02; + payload[1] = 0x02; + string_read_helper(payload, 2, MOSQ_ERR_PROTOCOL, NULL, -1); + + /* 3 byte packet */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0x00; + payload[1] = 0x02; + payload[2] = 'a'; + string_read_helper(payload, 3, MOSQ_ERR_PROTOCOL, NULL, -1); + + /* 3 byte packet */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0x00; + payload[1] = 0x03; + payload[2] = 'a'; + payload[3] = 'b'; + string_read_helper(payload, 4, MOSQ_ERR_PROTOCOL, NULL, -1); +} + + +/* This tests reading a UTF-8 Encoded String from an incoming packet. + * + * It tests: + * * Empty string + */ +static void TEST_string_read_empty_string(void) +{ + uint8_t payload[20]; + + memset(payload, 0, sizeof(payload)); + payload[0] = 0x00; + payload[1] = 0x00; + string_read_helper(payload, 2, MOSQ_ERR_SUCCESS, "", 0); +} + +/* This tests reading a UTF-8 Encoded String from an incoming packet. + * + * It tests: + * * Valid string + */ +static void TEST_string_read_valid_string(void) +{ + uint8_t payload[20]; + + memset(payload, 0, sizeof(payload)); + payload[0] = 0x00; + payload[1] = 0x0b; + payload[2] = 't'; + payload[3] = 'e'; + payload[4] = 's'; + payload[5] = 't'; + payload[6] = ' '; + payload[7] = 's'; + payload[8] = 't'; + payload[9] = 'r'; + payload[10] = 'i'; + payload[11] = 'n'; + payload[12] = 'g'; + string_read_helper(payload, 13, MOSQ_ERR_SUCCESS, "test string", 11); +} + + +/* This tests reading a UTF-8 Encoded String from an incoming packet. + * + * It tests: + * * Malformed UTF-8 (note, comprehensive UTF-8 tests are elsewhere) + */ +static void TEST_string_read_malformed_string(void) +{ + uint8_t payload[20]; + + memset(payload, 0, sizeof(payload)); + payload[0] = 0x00; + payload[1] = 0x07; + payload[2] = 't'; + payload[3] = 'e'; + payload[4] = 's'; + payload[5] = 't'; + payload[6] = 0xED; /* U+D800 - single UTF-16 surrogate */ + payload[7] = 0xA0; + payload[8] = 0x80; + string_read_helper(payload, 9, MOSQ_ERR_MALFORMED_UTF8, NULL, -1); +} + + +/* This tests reading a UTF-8 Encoded String from an incoming packet. + * + * It tests: + * * MQTT-1.5.4-3 - Is 0xEF 0xBB 0xBF treated correctly. + */ +static void TEST_string_read_mqtt_1_5_4_3(void) +{ + uint8_t payload[20]; + + memset(payload, 0, sizeof(payload)); + payload[0] = 0x00; + payload[1] = 0x0b; + payload[2] = 't'; + payload[3] = 'e'; + payload[4] = 's'; + payload[5] = 't'; + payload[6] = 0xEF; /* U+FEFF - zero with no-break space */ + payload[7] = 0xBB; + payload[8] = 0xBF; + payload[9] = 't'; + payload[10] = 'e'; + payload[11] = 's'; + payload[12] = 't'; + string_read_helper(payload, 13, MOSQ_ERR_SUCCESS, &payload[2], 11); +} + + /* ======================================================================== * TEST SUITE SETUP * ======================================================================== */ @@ -526,6 +656,12 @@ int init_datatype_tests(void) || !CU_add_test(test_suite, "Variable Byte Integer read (encoding boundaries)", TEST_varint_read_boundaries) || !CU_add_test(test_suite, "Variable Byte Integer read (five byte encoding)", TEST_varint_read_5_bytes) || !CU_add_test(test_suite, "Variable Byte Integer read (overlong encodings)", TEST_varint_read_overlong_encoding) + || !CU_add_test(test_suite, "UTF-8 string read (empty packet)", TEST_string_read_empty) + || !CU_add_test(test_suite, "UTF-8 string read (truncated packet)", TEST_string_read_truncated) + || !CU_add_test(test_suite, "UTF-8 string read (empty string)", TEST_string_read_empty_string) + || !CU_add_test(test_suite, "UTF-8 string read (valid string)", TEST_string_read_valid_string) + || !CU_add_test(test_suite, "UTF-8 string read (malformed string)", TEST_string_read_malformed_string) + || !CU_add_test(test_suite, "UTF-8 string read (MQTT-1.5.4-3)", TEST_string_read_mqtt_1_5_4_3) ){ printf("Error adding datatypes CUnit tests.\n"); From debf7493adf1fba5b38859f1d061624c0dff9775 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 3 Oct 2018 18:42:15 +0100 Subject: [PATCH 019/254] UTF-8 validation tests and fixes. --- lib/utf8_mosq.c | 8 ++ test/unit/Makefile | 2 +- test/unit/test.c | 6 + test/unit/utf8.c | 301 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 316 insertions(+), 1 deletion(-) create mode 100644 test/unit/utf8.c diff --git a/lib/utf8_mosq.c b/lib/utf8_mosq.c index 7ee6055986..d188d3dbeb 100644 --- a/lib/utf8_mosq.c +++ b/lib/utf8_mosq.c @@ -87,6 +87,14 @@ int mosquitto_validate_utf8(const char *str, int len) }else if(codelen == 4 && (codepoint < 0x10000 || codepoint > 0x10FFFF)){ return MOSQ_ERR_MALFORMED_UTF8; } + + /* Check for non-characters */ + if(codepoint >= 0xFDD0 && codepoint <= 0xFDEF){ + return MOSQ_ERR_MALFORMED_UTF8; + } + if((codepoint & 0xFFFF) == 0xFFFE || (codepoint & 0xFFFF) == 0xFFFF){ + return MOSQ_ERR_MALFORMED_UTF8; + } } return MOSQ_ERR_SUCCESS; } diff --git a/test/unit/Makefile b/test/unit/Makefile index e6e679c009..226d6caf47 100644 --- a/test/unit/Makefile +++ b/test/unit/Makefile @@ -7,7 +7,7 @@ TEST_LDFLAGS=-lcunit -coverage all : test -mosq_test : test.o datatypes.o memory_mosq.o packet_datatypes.o utf8_mosq.o +mosq_test : test.o datatypes.o utf8.o memory_mosq.o packet_datatypes.o utf8_mosq.o $(CROSS_COMPILE)$(CC) -o $@ $^ ${TEST_LDFLAGS} memory_mosq.o : ../../lib/memory_mosq.c diff --git a/test/unit/test.c b/test/unit/test.c index 3071fead8f..9c23ee08b1 100644 --- a/test/unit/test.c +++ b/test/unit/test.c @@ -4,6 +4,7 @@ #include int init_datatype_tests(void); +int init_utf8_tests(void); int main(int argc, char *argv[]) { @@ -13,6 +14,11 @@ int main(int argc, char *argv[]) return 1; } + if(init_utf8_tests()){ + CU_cleanup_registry(); + return 1; + } + if(init_datatype_tests()){ CU_cleanup_registry(); return 1; diff --git a/test/unit/utf8.c b/test/unit/utf8.c new file mode 100644 index 0000000000..532df5193f --- /dev/null +++ b/test/unit/utf8.c @@ -0,0 +1,301 @@ +#include +#include + +#include "mosquitto.h" + +/* Test data taken from + * http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt but modified for + * updated standard (no 5, 6 byte lengths) */ + +static void utf8_helper_len(const char *text, int len, int expected) +{ + int result; + + result = mosquitto_validate_utf8(text, len); + CU_ASSERT_EQUAL(result, expected); +} + +static void utf8_helper(const char *text, int expected) +{ + utf8_helper_len(text, strlen(text), expected); +} + + +static void TEST_utf8_empty(void) +{ + utf8_helper_len(NULL, 0, MOSQ_ERR_INVAL); +} + + +static void TEST_utf8_valid(void) +{ + /* 1 Some correct UTF-8 text */ + utf8_helper("", MOSQ_ERR_SUCCESS); + utf8_helper("You should see the Greek word 'kosme': \"κόσμε\"", MOSQ_ERR_SUCCESS); +} + + +static void TEST_utf8_boundary_conditions(void) +{ + /* 2 Boundary condition test cases */ + /* 2.1 First possible sequence of a certain length */ + utf8_helper_len("2.1.1 1 byte (U-00000000): \"\0\"", 39, MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("2.1.2 2 bytes (U-00000080): \"€\"", MOSQ_ERR_SUCCESS); + utf8_helper("2.1.3 3 bytes (U-00000800): \"à €\"", MOSQ_ERR_SUCCESS); + utf8_helper("2.1.4 4 bytes (U-00010000): \"ð€€\"", MOSQ_ERR_SUCCESS); + + /* 2.2 Last possible sequence of a certain length */ + + utf8_helper("2.2.1 1 byte (U-0000007F): \"\"", MOSQ_ERR_SUCCESS); + utf8_helper("2.2.2 2 bytes (U-000007FF): \"ß¿\"", MOSQ_ERR_SUCCESS); + /* Non character */ + utf8_helper("2.2.3 3 bytes (U-0000FFFF): \"ï¿¿\"", MOSQ_ERR_MALFORMED_UTF8); + /* Non character */ + utf8_helper("2.2.4 4 bytes (U-0010FFFF): \"÷¿¿¿\"", MOSQ_ERR_MALFORMED_UTF8); + + /* 2.3 Other boundary conditions */ + + utf8_helper("2.3.1 U-0000D7FF = ed 9f bf = \"퟿\"", MOSQ_ERR_SUCCESS); + utf8_helper("2.3.2 U-0000E000 = ee 80 80 = \"\"", MOSQ_ERR_SUCCESS); + utf8_helper("2.3.3 U-0000FFFD = ef bf bd = \"�\"", MOSQ_ERR_SUCCESS); + /* Non character */ + utf8_helper("2.3.4 U-0010FFFF = f4 8f bf bf = \"ô¿¿\"", MOSQ_ERR_MALFORMED_UTF8); + /* This used to be valid in pre-2003 utf-8 */ + utf8_helper("2.3.5 U-00110000 = f4 90 80 80 = \"ô€€\"", MOSQ_ERR_MALFORMED_UTF8); +} + + +static void TEST_utf8_malformed_sequences(void) +{ + /* 3 Malformed sequences */ + /* 3.1 Unexpected continuation bytes */ + utf8_helper("3.1.1 First continuation byte 0x80: \"€\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("3.1.2 Last continuation byte 0xbf: \"¿\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("3.1.3 2 continuation bytes: \"€¿\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("3.1.4 3 continuation bytes: \"€¿€\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("3.1.5 4 continuation bytes: \"€¿€¿\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("3.1.6 5 continuation bytes: \"€¿€¿€\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("3.1.7 6 continuation bytes: \"€¿€¿€¿\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("3.1.8 7 continuation bytes: \"€¿€¿€¿€\"", MOSQ_ERR_MALFORMED_UTF8); + + /* 3.1.9 Sequence of all 64 possible continuation bytes (0x80-0xbf): */ + utf8_helper("€‚ƒ„…†‡ˆ‰Š‹ŒŽ", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("‘’“”•–—˜™š›œžŸ", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper(" ¡¢£¤¥¦§¨©ª«¬­®¯", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("°±²³´µ¶·¸¹º»¼½¾¿\"", MOSQ_ERR_MALFORMED_UTF8); + + /* 3.2 Lonely start characters */ + + /* 3.2.1 All 32 first bytes of 2-byte sequences (0xc0-0xdf), + each followed by a space character: */ + utf8_helper("\"À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß \"", MOSQ_ERR_MALFORMED_UTF8); + + /* 3.2.2 All 16 first bytes of 3-byte sequences (0xe0-0xef), + each followed by a space character: */ + utf8_helper("\"à á â ã ä å æ ç è é ê ë ì í î ï \"", MOSQ_ERR_MALFORMED_UTF8); + + /* 3.2.3 All 8 first bytes of 4-byte sequences (0xf0-0xf7), + each followed by a space character: */ + utf8_helper("\"ð ñ ò ó ô õ ö ÷ \"", MOSQ_ERR_MALFORMED_UTF8); + + /* 3.2.4 All 4 first bytes of 5-byte sequences (0xf8-0xfb), + each followed by a space character: */ + utf8_helper("\"ø ù ú û \"", MOSQ_ERR_MALFORMED_UTF8); + + /* 3.2.5 All 2 first bytes of 6-byte sequences (0xfc-0xfd), + each followed by a space character: */ + utf8_helper("\"ü ý \"", MOSQ_ERR_MALFORMED_UTF8); + + /* 3.3 Sequences with last continuation byte missing + + All bytes of an incomplete sequence should be signalled as a single + malformed sequence, i.e., you should see only a single replacement + character in each of the next 10 tests. (Characters as in section 2) */ + + utf8_helper("3.3.1 2-byte sequence with last byte missing (U+0000): \"À\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("3.3.2 3-byte sequence with last byte missing (U+0000): \"à€\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("3.3.3 4-byte sequence with last byte missing (U+0000): \"ð€€\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("3.3.4 5-byte sequence with last byte missing (U+0000): \"ø€€€\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("3.3.5 6-byte sequence with last byte missing (U+0000): \"ü€€€€\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("3.3.6 2-byte sequence with last byte missing (U-000007FF): \"ß\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("3.3.7 3-byte sequence with last byte missing (U-0000FFFF): \"ï¿\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("3.3.8 4-byte sequence with last byte missing (U-001FFFFF): \"÷¿¿\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("3.3.9 5-byte sequence with last byte missing (U-03FFFFFF): \"û¿¿¿\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("3.3.10 6-byte sequence with last byte missing (U-7FFFFFFF): \"ý¿¿¿¿\"", MOSQ_ERR_MALFORMED_UTF8); + + /* 3.4 Concatenation of incomplete sequences + + All the 10 sequences of 3.3 concatenated, you should see 10 malformed + sequences being signalled:*/ + + utf8_helper("\"Àà€ð€€ø€€€ü€€€€ßï¿÷¿¿û¿¿¿ý¿¿¿¿\"", MOSQ_ERR_MALFORMED_UTF8); + + /* 3.5 Impossible bytes + + The following two bytes cannot appear in a correct UTF-8 string */ + + utf8_helper("3.5.1 fe = \"þ\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("3.5.2 ff = \"ÿ\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("3.5.3 fe fe ff ff = \"þþÿÿ\"", MOSQ_ERR_MALFORMED_UTF8); +} + +static void TEST_utf8_overlong_encoding(void) +{ + /* 4 Overlong sequences + + The following sequences are not malformed according to the letter of + the Unicode 2.0 standard. However, they are longer then necessary and + a correct UTF-8 encoder is not allowed to produce them. A "safe UTF-8 + decoder" should reject them just like malformed sequences for two + reasons: (1) It helps to debug applications if overlong sequences are + not treated as valid representations of characters, because this helps + to spot problems more quickly. (2) Overlong sequences provide + alternative representations of characters, that could maliciously be + used to bypass filters that check only for ASCII characters. For + instance, a 2-byte encoded line feed (LF) would not be caught by a + line counter that counts only 0x0a bytes, but it would still be + processed as a line feed by an unsafe UTF-8 decoder later in the + pipeline. From a security point of view, ASCII compatibility of UTF-8 + sequences means also, that ASCII characters are *only* allowed to be + represented by ASCII bytes in the range 0x00-0x7f. To ensure this + aspect of ASCII compatibility, use only "safe UTF-8 decoders" that + reject overlong UTF-8 sequences for which a shorter encoding exists. */ + + /* 4.1 Examples of an overlong ASCII character + + With a safe UTF-8 decoder, all of the following five overlong + representations of the ASCII character slash ("/") should be rejected + like a malformed UTF-8 sequence, for instance by substituting it with + a replacement character. If you see a slash below, you do not have a + safe UTF-8 decoder! */ + + utf8_helper("4.1.1 U+002F = c0 af = \"À¯\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("4.1.2 U+002F = e0 80 af = \"à€¯\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("4.1.3 U+002F = f0 80 80 af = \"ð€€¯\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("4.1.4 U+002F = f8 80 80 80 af = \"ø€€€¯\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("4.1.5 U+002F = fc 80 80 80 80 af = \"ü€€€€¯\"", MOSQ_ERR_MALFORMED_UTF8); + + /* 4.2 Maximum overlong sequences + + Below you see the highest Unicode value that is still resulting in an + overlong sequence if represented with the given number of bytes. This + is a boundary test for safe UTF-8 decoders. All five characters should + be rejected like malformed UTF-8 sequences. */ + + utf8_helper("4.2.1 U-0000007F = c1 bf = \"Á¿\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("4.2.2 U-000007FF = e0 9f bf = \"àŸ¿\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("4.2.3 U-0000FFFF = f0 8f bf bf = \"ð¿¿\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("4.2.4 U-001FFFFF = f8 87 bf bf bf = \"ø‡¿¿¿\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("4.2.5 U-03FFFFFF = fc 83 bf bf bf bf = \"üƒ¿¿¿¿\"", MOSQ_ERR_MALFORMED_UTF8); + + /* 4.3 Overlong representation of the NUL character + + The following five sequences should also be rejected like malformed + UTF-8 sequences and should not be treated like the ASCII NUL + character. */ + + utf8_helper("4.3.1 U+0000 = c0 80 = \"À€\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("4.3.2 U+0000 = e0 80 80 = \"à€€\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("4.3.3 U+0000 = f0 80 80 80 = \"ð€€€\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("4.3.4 U+0000 = f8 80 80 80 80 = \"ø€€€€\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("4.3.5 U+0000 = fc 80 80 80 80 80 = \"ü€€€€€\"", MOSQ_ERR_MALFORMED_UTF8); +} + + +static void TEST_utf8_illegal_code_positions(void) +{ + /* 5 Illegal code positions + + The following UTF-8 sequences should be rejected like malformed + sequences, because they never represent valid ISO 10646 characters and + a UTF-8 decoder that accepts them might introduce security problems + comparable to overlong UTF-8 sequences. */ + + /* 5.1 Single UTF-16 surrogates */ + + utf8_helper("5.1.1 U+D800 = ed a0 80 = \"í €\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("5.1.2 U+DB7F = ed ad bf = \"í­¿\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("5.1.3 U+DB80 = ed ae 80 = \"í®€\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("5.1.4 U+DBFF = ed af bf = \"í¯¿\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("5.1.5 U+DC00 = ed b0 80 = \"í°€\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("5.1.6 U+DF80 = ed be 80 = \"í¾€\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("5.1.7 U+DFFF = ed bf bf = \"í¿¿\"", MOSQ_ERR_MALFORMED_UTF8); + + /* 5.2 Paired UTF-16 surrogates */ + + /* FIXME - these need splitting up into separate tests. */ + utf8_helper("5.2.1 U+D800 U+DC00 = ed a0 80 ed b0 80 = \"𐀀\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("5.2.2 U+D800 U+DFFF = ed a0 80 ed bf bf = \"𐏿\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("5.2.3 U+DB7F U+DC00 = ed ad bf ed b0 80 = \"í­¿í°€\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("5.2.4 U+DB7F U+DFFF = ed ad bf ed bf bf = \"í­¿í¿¿\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("5.2.5 U+DB80 U+DC00 = ed ae 80 ed b0 80 = \"󰀀\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("5.2.6 U+DB80 U+DFFF = ed ae 80 ed bf bf = \"󰏿\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("5.2.7 U+DBFF U+DC00 = ed af bf ed b0 80 = \"􏰀\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("5.2.8 U+DBFF U+DFFF = ed af bf ed bf bf = \"􏿿\"", MOSQ_ERR_MALFORMED_UTF8); + + /* 5.3 Noncharacter code positions + + The following "noncharacters" are "reserved for internal use" by + applications, and according to older versions of the Unicode Standard + "should never be interchanged". Unicode Corrigendum #9 dropped the + latter restriction. Nevertheless, their presence in incoming UTF-8 data + can remain a potential security risk, depending on what use is made of + these codes subsequently. Examples of such internal use: + + - Some file APIs with 16-bit characters may use the integer value -1 + = U+FFFF to signal an end-of-file (EOF) or error condition. + + - In some UTF-16 receivers, code point U+FFFE might trigger a + byte-swap operation (to convert between UTF-16LE and UTF-16BE). + + With such internal use of noncharacters, it may be desirable and safer + to block those code points in UTF-8 decoders, as they should never + occur legitimately in incoming UTF-8 data, and could trigger unsafe + behaviour in subsequent processing. + + Particularly problematic noncharacters in 16-bit applications: */ + utf8_helper("5.3.1 U+FFFE = ef bf be = \"￾\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("5.3.2 U+FFFF = ef bf bf = \"ï¿¿\"", MOSQ_ERR_MALFORMED_UTF8); + + /* Other noncharacters: */ + + /* FIXME - these need splitting up into separate tests. */ + utf8_helper("5.3.3 U+FDD0 .. U+FDEF = \"ï·ï·‘﷒﷓﷔﷕﷖﷗﷘﷙﷚﷛﷜ï·ï·žï·Ÿï· ï·¡ï·¢ï·£ï·¤ï·¥ï·¦ï·§ï·¨ï·©ï·ªï·«ï·¬ï·­ï·®ï·¯\"", MOSQ_ERR_MALFORMED_UTF8); + + /* 5.3.4 U+nFFFE U+nFFFF (for n = 1..10) */ + + utf8_helper("\"🿾🿿𯿾𯿿𿿾𿿿ñ¿¾ñ¿¿ñŸ¿¾ñŸ¿¿ñ¯¿¾ñ¯¿¿ñ¿¿¾ñ¿¿¿ò¿¾ò¿¿òŸ¿¾òŸ¿¿ò¯¿¾ò¯¿¿ò¿¿¾ò¿¿¿ó¿¾ó¿¿óŸ¿¾óŸ¿¿ó¯¿¾ó¯¿¿ó¿¿¾ó¿¿¿ô¿¾ô¿¿\"", MOSQ_ERR_MALFORMED_UTF8); +} + + +/* ======================================================================== + * TEST SUITE SETUP + * ======================================================================== */ + +int init_utf8_tests(void) +{ + CU_pSuite test_suite = NULL; + + test_suite = CU_add_suite("UTF-8", NULL, NULL); + if(!test_suite){ + printf("Error adding CUnit test suite.\n"); + return 1; + } + + if(0 + || !CU_add_test(test_suite, "UTF-8 empty", TEST_utf8_empty) + || !CU_add_test(test_suite, "UTF-8 valid", TEST_utf8_valid) + || !CU_add_test(test_suite, "UTF-8 boundary conditions", TEST_utf8_boundary_conditions) + || !CU_add_test(test_suite, "UTF-8 malformed sequences", TEST_utf8_malformed_sequences) + || !CU_add_test(test_suite, "UTF-8 overlong encoding", TEST_utf8_overlong_encoding) + || !CU_add_test(test_suite, "UTF-8 illegal code positions", TEST_utf8_illegal_code_positions) + ){ + + printf("Error adding UTF-8 CUnit tests.\n"); + return 1; + } + + return 0; +} + + From ed06255847195980fc7a96345e1b175f3e3b3be0 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 3 Oct 2018 20:38:17 +0100 Subject: [PATCH 020/254] Rename to _read so _write can be separate. --- test/unit/Makefile | 4 ++-- test/unit/{datatypes.c => datatype_read.c} | 4 ++-- test/unit/test.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) rename test/unit/{datatypes.c => datatype_read.c} (99%) diff --git a/test/unit/Makefile b/test/unit/Makefile index 226d6caf47..3ae0c52652 100644 --- a/test/unit/Makefile +++ b/test/unit/Makefile @@ -7,7 +7,7 @@ TEST_LDFLAGS=-lcunit -coverage all : test -mosq_test : test.o datatypes.o utf8.o memory_mosq.o packet_datatypes.o utf8_mosq.o +mosq_test : test.o datatype_read.o utf8.o memory_mosq.o packet_datatypes.o utf8_mosq.o $(CROSS_COMPILE)$(CC) -o $@ $^ ${TEST_LDFLAGS} memory_mosq.o : ../../lib/memory_mosq.c @@ -23,7 +23,7 @@ test : mosq_test ./mosq_test clean : - -rm -f test *.o + -rm -rf mosq_test *.o *.gcda *.gcno coverage.info out/ coverage : lcov --capture --directory . --output-file coverage.info diff --git a/test/unit/datatypes.c b/test/unit/datatype_read.c similarity index 99% rename from test/unit/datatypes.c rename to test/unit/datatype_read.c index 05439e25b3..c8ebe032d4 100644 --- a/test/unit/datatypes.c +++ b/test/unit/datatype_read.c @@ -632,11 +632,11 @@ static void TEST_string_read_mqtt_1_5_4_3(void) * TEST SUITE SETUP * ======================================================================== */ -int init_datatype_tests(void) +int init_datatype_read_tests(void) { CU_pSuite test_suite = NULL; - test_suite = CU_add_suite("datatypes", NULL, NULL); + test_suite = CU_add_suite("Datatype read", NULL, NULL); if(!test_suite){ printf("Error adding CUnit test suite.\n"); return 1; diff --git a/test/unit/test.c b/test/unit/test.c index 9c23ee08b1..22a0045905 100644 --- a/test/unit/test.c +++ b/test/unit/test.c @@ -3,7 +3,7 @@ #include #include -int init_datatype_tests(void); +int init_datatype_read_tests(void); int init_utf8_tests(void); int main(int argc, char *argv[]) @@ -19,7 +19,7 @@ int main(int argc, char *argv[]) return 1; } - if(init_datatype_tests()){ + if(init_datatype_read_tests()){ CU_cleanup_registry(); return 1; } From 99e324e8606d782d551b47b6dc697a4ceab7982d Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 3 Oct 2018 20:50:39 +0100 Subject: [PATCH 021/254] Make test strings unsigned. --- test/unit/datatype_read.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/unit/datatype_read.c b/test/unit/datatype_read.c index c8ebe032d4..07a1128b87 100644 --- a/test/unit/datatype_read.c +++ b/test/unit/datatype_read.c @@ -86,18 +86,18 @@ static void string_read_helper( uint8_t *payload, int remaining_length, int rc_expected, - const char *value_expected, + const uint8_t *value_expected, int length_expected) { struct mosquitto__packet packet; - char *value = NULL; + uint8_t *value = NULL; int length = -1; int rc; memset(&packet, 0, sizeof(struct mosquitto__packet)); packet.payload = payload; packet.remaining_length = remaining_length; - rc = packet__read_string(&packet, &value, &length); + rc = packet__read_string(&packet, (char **)&value, &length); CU_ASSERT_EQUAL(rc, rc_expected); if(value_expected){ CU_ASSERT_NSTRING_EQUAL(value, value_expected, length_expected); @@ -548,7 +548,7 @@ static void TEST_string_read_empty_string(void) memset(payload, 0, sizeof(payload)); payload[0] = 0x00; payload[1] = 0x00; - string_read_helper(payload, 2, MOSQ_ERR_SUCCESS, "", 0); + string_read_helper(payload, 2, MOSQ_ERR_SUCCESS, (const uint8_t *)"", 0); } /* This tests reading a UTF-8 Encoded String from an incoming packet. @@ -574,7 +574,7 @@ static void TEST_string_read_valid_string(void) payload[10] = 'i'; payload[11] = 'n'; payload[12] = 'g'; - string_read_helper(payload, 13, MOSQ_ERR_SUCCESS, "test string", 11); + string_read_helper(payload, 13, MOSQ_ERR_SUCCESS, (const uint8_t *)"test string", 11); } From 72131c84ce0fa7f1d775c06effa18fbb9ea35ec7 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 3 Oct 2018 21:35:33 +0100 Subject: [PATCH 022/254] Binary data read functions and tests. --- lib/packet_datatypes.c | 27 +++++++++---- lib/packet_mosq.h | 1 + test/unit/Makefile | 2 +- test/unit/datatype_read.c | 82 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 8 deletions(-) diff --git a/lib/packet_datatypes.c b/lib/packet_datatypes.c index 9e31974fe1..1fce5950bc 100644 --- a/lib/packet_datatypes.c +++ b/lib/packet_datatypes.c @@ -88,7 +88,7 @@ void packet__write_bytes(struct mosquitto__packet *packet, const void *bytes, ui } -int packet__read_string(struct mosquitto__packet *packet, char **str, int *length) +int packet__read_binary(struct mosquitto__packet *packet, void **data, int *length) { uint16_t slen; int rc; @@ -99,22 +99,35 @@ int packet__read_string(struct mosquitto__packet *packet, char **str, int *lengt if(packet->pos+slen > packet->remaining_length) return MOSQ_ERR_PROTOCOL; - *str = mosquitto__malloc(slen+1); - if(*str){ - memcpy(*str, &(packet->payload[packet->pos]), slen); - (*str)[slen] = '\0'; + *data = mosquitto__malloc(slen+1); + if(*data){ + memcpy(*data, &(packet->payload[packet->pos]), slen); + ((uint8_t *)(*data))[slen] = '\0'; packet->pos += slen; }else{ return MOSQ_ERR_NOMEM; } - if(mosquitto_validate_utf8(*str, slen)){ + *length = slen; + return MOSQ_ERR_SUCCESS; +} + + +int packet__read_string(struct mosquitto__packet *packet, char **str, int *length) +{ + int rc; + int len; + + rc = packet__read_binary(packet, (void **)str, &len); + if(rc) return rc; + + if(mosquitto_validate_utf8(*str, len)){ mosquitto__free(*str); *str = NULL; return MOSQ_ERR_MALFORMED_UTF8; } - *length = slen; + *length = len; return MOSQ_ERR_SUCCESS; } diff --git a/lib/packet_mosq.h b/lib/packet_mosq.h index 5b5b5c69de..567ffcec9b 100644 --- a/lib/packet_mosq.h +++ b/lib/packet_mosq.h @@ -29,6 +29,7 @@ int packet__queue(struct mosquitto *mosq, struct mosquitto__packet *packet); int packet__read_byte(struct mosquitto__packet *packet, uint8_t *byte); int packet__read_bytes(struct mosquitto__packet *packet, void *bytes, uint32_t count); +int packet__read_binary(struct mosquitto__packet *packet, void **data, int *length); int packet__read_string(struct mosquitto__packet *packet, char **str, int *length); int packet__read_uint16(struct mosquitto__packet *packet, uint16_t *word); int packet__read_uint32(struct mosquitto__packet *packet, uint32_t *word); diff --git a/test/unit/Makefile b/test/unit/Makefile index 3ae0c52652..d67b36dbb3 100644 --- a/test/unit/Makefile +++ b/test/unit/Makefile @@ -2,7 +2,7 @@ include ../../config.mk .PHONY: all test clean coverage -CFLAGS=-I../.. -I../../lib -coverage -Wall +CFLAGS=-I../.. -I../../lib -coverage -Wall -ggdb TEST_LDFLAGS=-lcunit -coverage all : test diff --git a/test/unit/datatype_read.c b/test/unit/datatype_read.c index 07a1128b87..95654e3f1a 100644 --- a/test/unit/datatype_read.c +++ b/test/unit/datatype_read.c @@ -82,6 +82,34 @@ static void varint_read_helper( } +static void binary_read_helper( + uint8_t *payload, + int remaining_length, + int rc_expected, + const uint8_t *value_expected, + int length_expected) +{ + struct mosquitto__packet packet; + uint8_t *value = NULL; + int length = -1; + int rc; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.payload = payload; + packet.remaining_length = remaining_length; + rc = packet__read_binary(&packet, (void **)&value, &length); + CU_ASSERT_EQUAL(rc, rc_expected); + if(value_expected){ + /* FIXME - this should be a memcmp */ + CU_ASSERT_NSTRING_EQUAL(value, value_expected, length_expected); + }else{ + CU_ASSERT_EQUAL(value, NULL); + } + CU_ASSERT_EQUAL(length, length_expected); + free(value); +} + + static void string_read_helper( uint8_t *payload, int remaining_length, @@ -628,6 +656,58 @@ static void TEST_string_read_mqtt_1_5_4_3(void) } +/* ======================================================================== + * BINARY DATA TESTS + * ======================================================================== */ + +/* This tests reading Binary Data from an incoming packet. + * + * It tests: + * * Empty packet + */ +static void TEST_binary_data_read_empty(void) +{ + binary_read_helper(NULL, 0, MOSQ_ERR_PROTOCOL, NULL, -1); +} + + +/* This tests reading Binary Data from an incoming packet. + * + * It tests: + * * Truncated packets + */ +static void TEST_binary_data_read_truncated(void) +{ + uint8_t payload[20]; + + /* 1 byte packet */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0x02; + binary_read_helper(payload, 1, MOSQ_ERR_PROTOCOL, NULL, -1); + + /* 2 byte packet */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0x02; + payload[1] = 0x02; + binary_read_helper(payload, 2, MOSQ_ERR_PROTOCOL, NULL, -1); + + /* 3 byte packet */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0x00; + payload[1] = 0x02; + payload[2] = 'a'; + binary_read_helper(payload, 3, MOSQ_ERR_PROTOCOL, NULL, -1); + + /* 3 byte packet */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0x00; + payload[1] = 0x03; + payload[2] = 'a'; + payload[3] = 'b'; + binary_read_helper(payload, 4, MOSQ_ERR_PROTOCOL, NULL, -1); +} + + /* ======================================================================== * TEST SUITE SETUP * ======================================================================== */ @@ -662,6 +742,8 @@ int init_datatype_read_tests(void) || !CU_add_test(test_suite, "UTF-8 string read (valid string)", TEST_string_read_valid_string) || !CU_add_test(test_suite, "UTF-8 string read (malformed string)", TEST_string_read_malformed_string) || !CU_add_test(test_suite, "UTF-8 string read (MQTT-1.5.4-3)", TEST_string_read_mqtt_1_5_4_3) + || !CU_add_test(test_suite, "Binary Data read (empty packet)", TEST_binary_data_read_empty) + || !CU_add_test(test_suite, "Binary Data read (truncated packet)", TEST_binary_data_read_truncated) ){ printf("Error adding datatypes CUnit tests.\n"); From eec3220622b02baf3eff871a3311bf7457a2b511 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 3 Oct 2018 21:51:47 +0100 Subject: [PATCH 023/254] Byte write test. --- test/unit/datatype_write.c | 56 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 test/unit/datatype_write.c diff --git a/test/unit/datatype_write.c b/test/unit/datatype_write.c new file mode 100644 index 0000000000..a9986d4646 --- /dev/null +++ b/test/unit/datatype_write.c @@ -0,0 +1,56 @@ +#include +#include + +#include "packet_mosq.h" + +/* ======================================================================== + * BYTE TESTS + * ======================================================================== */ + +/* This tests writing a Byte to an incoming packet. */ +static void TEST_byte_write(void) +{ + uint8_t payload[260]; + struct mosquitto__packet packet; + int i; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + memset(payload, 0, sizeof(payload)); + packet.payload = payload; + packet.packet_length = 256; + + for(i=0; i<256; i++){ + packet__write_byte(&packet, 255-i); + } + + CU_ASSERT_EQUAL(packet.pos, 256); + for(i=0; i<256; i++){ + CU_ASSERT_EQUAL(payload[i], 255-i); + } +} + + +/* ======================================================================== + * TEST SUITE SETUP + * ======================================================================== */ + +int init_datatype_write_tests(void) +{ + CU_pSuite test_suite = NULL; + + test_suite = CU_add_suite("Datatype write", NULL, NULL); + if(!test_suite){ + printf("Error adding CUnit test suite.\n"); + return 1; + } + + if(0 + || !CU_add_test(test_suite, "Byte write (empty packet)", TEST_byte_write) + ){ + + printf("Error adding Datatype write CUnit tests.\n"); + return 1; + } + + return 0; +} From e701608e718dcc813f9dec0afc239cfcda1f6761 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 3 Oct 2018 22:22:42 +0100 Subject: [PATCH 024/254] Two Byte Integer write test. --- test/unit/Makefile | 2 +- test/unit/datatype_read.c | 4 ++-- test/unit/datatype_write.c | 34 +++++++++++++++++++++++++++++++++- test/unit/test.c | 10 +++++----- 4 files changed, 41 insertions(+), 9 deletions(-) diff --git a/test/unit/Makefile b/test/unit/Makefile index d67b36dbb3..038c5a230b 100644 --- a/test/unit/Makefile +++ b/test/unit/Makefile @@ -7,7 +7,7 @@ TEST_LDFLAGS=-lcunit -coverage all : test -mosq_test : test.o datatype_read.o utf8.o memory_mosq.o packet_datatypes.o utf8_mosq.o +mosq_test : test.o datatype_read.o datatype_write.o utf8.o memory_mosq.o packet_datatypes.o utf8_mosq.o $(CROSS_COMPILE)$(CC) -o $@ $^ ${TEST_LDFLAGS} memory_mosq.o : ../../lib/memory_mosq.c diff --git a/test/unit/datatype_read.c b/test/unit/datatype_read.c index 95654e3f1a..cf2b92caab 100644 --- a/test/unit/datatype_read.c +++ b/test/unit/datatype_read.c @@ -172,7 +172,7 @@ static void TEST_byte_read_success(void) payload[0] = 0x1F; byte_read_helper(payload, 1, MOSQ_ERR_SUCCESS, 0x1F); - /* 65,535 value */ + /* 255 value */ memset(payload, 0, sizeof(payload)); payload[0] = 0xFF; byte_read_helper(payload, 1, MOSQ_ERR_SUCCESS, 0xFF); @@ -746,7 +746,7 @@ int init_datatype_read_tests(void) || !CU_add_test(test_suite, "Binary Data read (truncated packet)", TEST_binary_data_read_truncated) ){ - printf("Error adding datatypes CUnit tests.\n"); + printf("Error adding Datatype read CUnit tests.\n"); return 1; } diff --git a/test/unit/datatype_write.c b/test/unit/datatype_write.c index a9986d4646..bf53499b9d 100644 --- a/test/unit/datatype_write.c +++ b/test/unit/datatype_write.c @@ -1,6 +1,8 @@ #include #include +#include + #include "packet_mosq.h" /* ======================================================================== @@ -30,6 +32,35 @@ static void TEST_byte_write(void) } +/* ======================================================================== + * TWO BYTE INTEGER TESTS + * ======================================================================== */ + +/* This tests writing a Two Byte Integer to an incoming packet. */ +static void TEST_uint16_write(void) +{ + uint8_t payload[650]; + uint16_t *payload16; + struct mosquitto__packet packet; + int i; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + memset(payload, 0, sizeof(payload)); + packet.payload = payload; + packet.packet_length = 650; + + for(i=0; i<325; i++){ + packet__write_uint16(&packet, 100*i); + } + + CU_ASSERT_EQUAL(packet.pos, 650); + payload16 = (uint16_t *)payload; + for(i=0; i<325; i++){ + CU_ASSERT_EQUAL(payload16[i], htons(100*i)); + } +} + + /* ======================================================================== * TEST SUITE SETUP * ======================================================================== */ @@ -45,7 +76,8 @@ int init_datatype_write_tests(void) } if(0 - || !CU_add_test(test_suite, "Byte write (empty packet)", TEST_byte_write) + || !CU_add_test(test_suite, "Byte write)", TEST_byte_write) + || !CU_add_test(test_suite, "Two Byte Integer write", TEST_uint16_write) ){ printf("Error adding Datatype write CUnit tests.\n"); diff --git a/test/unit/test.c b/test/unit/test.c index 22a0045905..cb25e3e3b5 100644 --- a/test/unit/test.c +++ b/test/unit/test.c @@ -14,12 +14,12 @@ int main(int argc, char *argv[]) return 1; } - if(init_utf8_tests()){ - CU_cleanup_registry(); - return 1; - } + if(0 + || init_utf8_tests() + || init_datatype_read_tests() + || init_datatype_write_tests() + ){ - if(init_datatype_read_tests()){ CU_cleanup_registry(); return 1; } From c124b07929250362f74c397516a17bcd9df6ebf2 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 3 Oct 2018 22:29:45 +0100 Subject: [PATCH 025/254] Four Byte Integer write test. --- test/unit/datatype_write.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/test/unit/datatype_write.c b/test/unit/datatype_write.c index bf53499b9d..24d5056e46 100644 --- a/test/unit/datatype_write.c +++ b/test/unit/datatype_write.c @@ -61,6 +61,40 @@ static void TEST_uint16_write(void) } +/* ======================================================================== + * FOUR BYTE INTEGER TESTS + * ======================================================================== */ + +/* This tests writing a Four Byte Integer to an incoming packet. */ +static void TEST_uint32_write(void) +{ + uint8_t *payload; + uint32_t *payload32; + struct mosquitto__packet packet; + int i; + + payload = calloc(42000, sizeof(uint32_t)); + if(!payload){ + CU_FAIL_FATAL("Out of memory"); + } + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.payload = payload; + packet.packet_length = 42000; + + for(i=0; i<10500; i++){ + packet__write_uint32(&packet, 1000*i); + } + + CU_ASSERT_EQUAL(packet.pos, 42000); + payload32 = (uint32_t *)payload; + for(i=0; i<10500; i++){ + CU_ASSERT_EQUAL(payload32[i], htonl(1000*i)); + } + free(payload); +} + + /* ======================================================================== * TEST SUITE SETUP * ======================================================================== */ @@ -78,6 +112,7 @@ int init_datatype_write_tests(void) if(0 || !CU_add_test(test_suite, "Byte write)", TEST_byte_write) || !CU_add_test(test_suite, "Two Byte Integer write", TEST_uint16_write) + || !CU_add_test(test_suite, "Four Byte Integer write", TEST_uint32_write) ){ printf("Error adding Datatype write CUnit tests.\n"); From 8c7220d7a57ad318f3e7815336b7d3c4ff02319f Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 3 Oct 2018 22:37:57 +0100 Subject: [PATCH 026/254] UTF-8 String write tests. --- test/unit/datatype_write.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/test/unit/datatype_write.c b/test/unit/datatype_write.c index 24d5056e46..ddb8d3c594 100644 --- a/test/unit/datatype_write.c +++ b/test/unit/datatype_write.c @@ -95,6 +95,36 @@ static void TEST_uint32_write(void) } +/* ======================================================================== + * UTF-8 STRING TESTS + * ======================================================================== */ + +/* This tests writing a UTF-8 String to an incoming packet. */ +static void TEST_string_write(void) +{ + uint8_t payload[100]; + struct mosquitto__packet packet; + int i; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + memset(payload, 0, 100); + + packet.payload = payload; + packet.packet_length = 100; + + packet__write_string(&packet, "first test", strlen("first test")); + packet__write_string(&packet, "second test", strlen("second test")); + + CU_ASSERT_EQUAL(packet.pos, 2+10+2+11); + CU_ASSERT_EQUAL(payload[0], 0); + CU_ASSERT_EQUAL(payload[1], 10); + CU_ASSERT_NSTRING_EQUAL(payload+2, "first test", 10); + CU_ASSERT_EQUAL(payload[2+10+0], 0); + CU_ASSERT_EQUAL(payload[2+10+1], 11); + CU_ASSERT_NSTRING_EQUAL(payload+2+10+2, "second test", 11); +} + + /* ======================================================================== * TEST SUITE SETUP * ======================================================================== */ @@ -113,6 +143,7 @@ int init_datatype_write_tests(void) || !CU_add_test(test_suite, "Byte write)", TEST_byte_write) || !CU_add_test(test_suite, "Two Byte Integer write", TEST_uint16_write) || !CU_add_test(test_suite, "Four Byte Integer write", TEST_uint32_write) + || !CU_add_test(test_suite, "UTF-8 String write", TEST_string_write) ){ printf("Error adding Datatype write CUnit tests.\n"); From c9d9ad8e72b914872d590f586ac47b6106f2e470 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 3 Oct 2018 18:42:15 +0100 Subject: [PATCH 027/254] UTF-8 validation tests and fixes. --- lib/utf8_mosq.c | 10 +++++++--- test/unit/test.c | 1 + test/unit/utf8.c | 17 +++++++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/lib/utf8_mosq.c b/lib/utf8_mosq.c index d188d3dbeb..b08c9a4366 100644 --- a/lib/utf8_mosq.c +++ b/lib/utf8_mosq.c @@ -80,9 +80,13 @@ int mosquitto_validate_utf8(const char *str, int len) } /* Check for overlong or out of range encodings */ - if(codelen == 2 && codepoint < 0x0080){ - return MOSQ_ERR_MALFORMED_UTF8; - }else if(codelen == 3 && codepoint < 0x0800){ + /* Checking codelen == 2 isn't necessary here, because it is already + * covered above in the C0 and C1 checks. + * if(codelen == 2 && codepoint < 0x0080){ + * return MOSQ_ERR_MALFORMED_UTF8; + * }else + */ + if(codelen == 3 && codepoint < 0x0800){ return MOSQ_ERR_MALFORMED_UTF8; }else if(codelen == 4 && (codepoint < 0x10000 || codepoint > 0x10FFFF)){ return MOSQ_ERR_MALFORMED_UTF8; diff --git a/test/unit/test.c b/test/unit/test.c index cb25e3e3b5..e89fa4d28b 100644 --- a/test/unit/test.c +++ b/test/unit/test.c @@ -4,6 +4,7 @@ #include int init_datatype_read_tests(void); +int init_datatype_write_tests(void); int init_utf8_tests(void); int main(int argc, char *argv[]) diff --git a/test/unit/utf8.c b/test/unit/utf8.c index 532df5193f..a96ebaeae0 100644 --- a/test/unit/utf8.c +++ b/test/unit/utf8.c @@ -35,6 +35,22 @@ static void TEST_utf8_valid(void) } +static void TEST_utf8_truncated(void) +{ + char buf[4]; + + /* As per boundary condition tests, but less one character */ + buf[0] = 0xC2; buf[1] = 0; + utf8_helper(buf, MOSQ_ERR_MALFORMED_UTF8); + + buf[0] = 0xE0; buf[1] = 0xA0; buf[2] = 0; + utf8_helper(buf, MOSQ_ERR_MALFORMED_UTF8); + + buf[0] = 0xF0; buf[1] = 0x90; buf[2] = 0x80; buf[3] = 0; + utf8_helper(buf, MOSQ_ERR_MALFORMED_UTF8); +} + + static void TEST_utf8_boundary_conditions(void) { /* 2 Boundary condition test cases */ @@ -285,6 +301,7 @@ int init_utf8_tests(void) if(0 || !CU_add_test(test_suite, "UTF-8 empty", TEST_utf8_empty) || !CU_add_test(test_suite, "UTF-8 valid", TEST_utf8_valid) + || !CU_add_test(test_suite, "UTF-8 truncated", TEST_utf8_truncated) || !CU_add_test(test_suite, "UTF-8 boundary conditions", TEST_utf8_boundary_conditions) || !CU_add_test(test_suite, "UTF-8 malformed sequences", TEST_utf8_malformed_sequences) || !CU_add_test(test_suite, "UTF-8 overlong encoding", TEST_utf8_overlong_encoding) From 1635dd3883e359626bf39d8edbc6d119e84c580b Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 4 Oct 2018 09:23:42 +0100 Subject: [PATCH 028/254] Multiple bytes read tests. --- test/unit/datatype_read.c | 73 ++++++++++++++++++++++++++++++++++++++ test/unit/datatype_write.c | 2 +- 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/test/unit/datatype_read.c b/test/unit/datatype_read.c index cf2b92caab..7697805056 100644 --- a/test/unit/datatype_read.c +++ b/test/unit/datatype_read.c @@ -137,6 +137,34 @@ static void string_read_helper( } +static void bytes_read_helper( + uint8_t *payload, + int remaining_length, + int rc_expected, + const uint8_t *value_expected, + int count) +{ + struct mosquitto__packet packet; + uint8_t value[count]; + int rc; + int i; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.payload = payload; + packet.remaining_length = remaining_length; + rc = packet__read_bytes(&packet, value, count); + CU_ASSERT_EQUAL(rc, rc_expected); + if(rc == MOSQ_ERR_SUCCESS){ + CU_ASSERT_EQUAL(packet.pos, count); + } + if(value_expected){ + for(i=0; i Date: Thu, 4 Oct 2018 09:46:51 +0100 Subject: [PATCH 029/254] Fix subscribe_multiple datatypes. --- client/sub_client.c | 2 +- lib/actions.c | 4 ++-- lib/mosquitto.h | 6 +++++- lib/send_mosq.h | 2 +- src/handle_connack.c | 2 +- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/client/sub_client.c b/client/sub_client.c index 9512d2eb96..4495849dcb 100644 --- a/client/sub_client.c +++ b/client/sub_client.c @@ -96,7 +96,7 @@ void my_connect_callback(struct mosquitto *mosq, void *obj, int result, int flag cfg = (struct mosq_config *)obj; if(!result){ - mosquitto_subscribe_multiple(mosq, NULL, cfg->topic_count, (const char **)cfg->topics, cfg->qos); + mosquitto_subscribe_multiple(mosq, NULL, cfg->topic_count, cfg->topics, cfg->qos); for(i=0; iunsub_topic_count; i++){ mosquitto_unsubscribe(mosq, NULL, cfg->unsub_topics[i]); diff --git a/lib/actions.c b/lib/actions.c index 317333bfbc..c8f966a6b7 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -105,11 +105,11 @@ int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const char *sub, int q if(mosquitto_sub_topic_check(sub)) return MOSQ_ERR_INVAL; if(mosquitto_validate_utf8(sub, strlen(sub))) return MOSQ_ERR_MALFORMED_UTF8; - return send__subscribe(mosq, mid, 1, &sub, qos); + return send__subscribe(mosq, mid, 1, (char *const *const)&sub, qos); } -int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, const char **sub, int qos) +int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, int qos) { int i; diff --git a/lib/mosquitto.h b/lib/mosquitto.h index ff99e4a36b..d1a5f207a2 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -646,6 +646,10 @@ libmosq_EXPORT int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const c * sent. * sub_count - the count of subscriptions to be made * sub - array of sub_count pointers, each pointing to a subscription string. + * The "char *const *const" datatype ensures that neither the array of + * pointers nor the strings that they point to are mutable. If you aren't + * familiar with this, just think of it as a safer "char **", + * equivalent to "const char *" for a simple string pointer. * qos - the requested Quality of Service for each subscription. * * Returns: @@ -655,7 +659,7 @@ libmosq_EXPORT int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const c * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. * MOSQ_ERR_MALFORMED_UTF8 - if a topic is not valid UTF-8 */ -int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, const char **sub, int qos); +int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, int qos); /* * Function: mosquitto_unsubscribe diff --git a/lib/send_mosq.h b/lib/send_mosq.h index c04f3c3f78..35645952dd 100644 --- a/lib/send_mosq.h +++ b/lib/send_mosq.h @@ -31,7 +31,7 @@ int send__pubcomp(struct mosquitto *mosq, uint16_t mid); int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup); int send__pubrec(struct mosquitto *mosq, uint16_t mid); int send__pubrel(struct mosquitto *mosq, uint16_t mid); -int send__subscribe(struct mosquitto *mosq, int *mid, int topic_count, const char **topic, int topic_qos); +int send__subscribe(struct mosquitto *mosq, int *mid, int topic_count, char *const *const topic, int topic_qos); int send__unsubscribe(struct mosquitto *mosq, int *mid, const char *topic); #endif diff --git a/src/handle_connack.c b/src/handle_connack.c index 48195b989c..3070e7cafc 100644 --- a/src/handle_connack.c +++ b/src/handle_connack.c @@ -76,7 +76,7 @@ int handle__connack(struct mosquitto_db *db, struct mosquitto *context) } for(i=0; ibridge->topic_count; i++){ if(context->bridge->topics[i].direction == bd_in || context->bridge->topics[i].direction == bd_both){ - if(send__subscribe(context, NULL, 1, &context->bridge->topics[i].remote_topic, &context->bridge->topics[i].qos)){ + if(send__subscribe(context, NULL, 1, &context->bridge->topics[i].remote_topic, context->bridge->topics[i].qos)){ return 1; } }else{ From 572be268e5d6ab1ea77c4dd045db4ea2cf1d3b5e Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 4 Oct 2018 09:53:30 +0100 Subject: [PATCH 030/254] Fix signedness of varint reading. --- lib/property_mosq.c | 68 +++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/lib/property_mosq.c b/lib/property_mosq.c index 73450d58cb..e8d10a4201 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -26,12 +26,14 @@ and the Eclipse Distribution License is available at #include "packet_mosq.h" #include "property_mosq.h" -int property__read(struct mosquitto__packet *packet, uint32_t *len) +int property__read(struct mosquitto__packet *packet, int32_t *len) { int rc; uint8_t byte; - uint16_t int16; - uint32_t int32; + int8_t byte_count; + uint16_t uint16; + uint32_t uint32; + int32_t varint; char *str; int slen; *len -= 14; @@ -49,72 +51,72 @@ int property__read(struct mosquitto__packet *packet, uint32_t *len) break; case PROP_MESSAGE_EXPIRY_INTERVAL: - rc = packet__read_uint32(packet, &int32); + rc = packet__read_uint32(packet, &uint32); if(rc) return rc; *len -= 4; /* uint32 */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Message expiry: %d", int32); + log__printf(NULL, MOSQ_LOG_DEBUG, "Message expiry: %d", uint32); break; case PROP_CONTENT_TYPE: rc = packet__read_string(packet, &str, &slen); if(rc) return rc; - *len -= 2 - slen; /* int16, string len */ + *len -= 2 - slen; /* uint16, string len */ log__printf(NULL, MOSQ_LOG_DEBUG, "Content type: %s", str); break; case PROP_RESPONSE_TOPIC: rc = packet__read_string(packet, &str, &slen); if(rc) return rc; - *len -= 2 - slen; /* int16, string len */ + *len -= 2 - slen; /* uint16, string len */ log__printf(NULL, MOSQ_LOG_DEBUG, "Response topic: %s", str); break; case PROP_CORRELATION_DATA: rc = packet__read_string(packet, &str, &slen); if(rc) return rc; - *len -= 2 - slen; /* int16, string len */ + *len -= 2 - slen; /* uint16, string len */ log__printf(NULL, MOSQ_LOG_DEBUG, "Correlation data: %s", str); break; case PROP_SUBSCRIPTION_IDENTIFIER: - rc = packet__read_varint(packet, &int32, &byte); - *len -= byte; + rc = packet__read_varint(packet, &varint, &byte_count); if(rc) return rc; - log__printf(NULL, MOSQ_LOG_DEBUG, "Subscription identifier: %d", int32); + *len -= byte_count; + log__printf(NULL, MOSQ_LOG_DEBUG, "Subscription identifier: %d", varint); break; case PROP_SESSION_EXPIRY_INTERVAL: - rc = packet__read_uint32(packet, &int32); + rc = packet__read_uint32(packet, &uint32); if(rc) return rc; *len -= 4; /* uint32 */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Session expiry: %d", int32); + log__printf(NULL, MOSQ_LOG_DEBUG, "Session expiry: %d", uint32); break; case PROP_ASSIGNED_CLIENT_IDENTIFIER: rc = packet__read_string(packet, &str, &slen); if(rc) return rc; - *len -= 2 - slen; /* int16, string len */ + *len -= 2 - slen; /* uint16, string len */ log__printf(NULL, MOSQ_LOG_DEBUG, "Assigned client identifier: %s", str); break; case PROP_SERVER_KEEP_ALIVE: - rc = packet__read_uint16(packet, &int16); + rc = packet__read_uint16(packet, &uint16); if(rc) return rc; *len -= 2; /* uint16 */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Session expiry: %d", int16); + log__printf(NULL, MOSQ_LOG_DEBUG, "Session expiry: %d", uint16); break; case PROP_AUTHENTICATION_METHOD: rc = packet__read_string(packet, &str, &slen); if(rc) return rc; - *len -= 2 - slen; /* int16, string len */ + *len -= 2 - slen; /* uint16, string len */ log__printf(NULL, MOSQ_LOG_DEBUG, "Authentication method: %s", str); break; case PROP_AUTHENTICATION_DATA: rc = packet__read_string(packet, &str, &slen); if(rc) return rc; - *len -= 2 - slen; /* int16, string len */ + *len -= 2 - slen; /* uint16, string len */ log__printf(NULL, MOSQ_LOG_DEBUG, "Authentication data: %s", str); break; @@ -126,10 +128,10 @@ int property__read(struct mosquitto__packet *packet, uint32_t *len) break; case PROP_WILL_DELAY_INTERVAL: - rc = packet__read_uint32(packet, &int32); + rc = packet__read_uint32(packet, &uint32); if(rc) return rc; *len -= 4; /* uint32 */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Will delay interval: %d", int32); + log__printf(NULL, MOSQ_LOG_DEBUG, "Will delay interval: %d", uint32); break; case PROP_REQUEST_RESPONSE_INFO: @@ -142,43 +144,43 @@ int property__read(struct mosquitto__packet *packet, uint32_t *len) case PROP_RESPONSE_INFO: rc = packet__read_string(packet, &str, &slen); if(rc) return rc; - *len -= 2 - slen; /* int16, string len */ + *len -= 2 - slen; /* uint16, string len */ log__printf(NULL, MOSQ_LOG_DEBUG, "Response information: %s", str); break; case PROP_SERVER_REFERENCE: rc = packet__read_string(packet, &str, &slen); if(rc) return rc; - *len -= 2 - slen; /* int16, string len */ + *len -= 2 - slen; /* uint16, string len */ log__printf(NULL, MOSQ_LOG_DEBUG, "Server reference: %s", str); break; case PROP_REASON_STRING: rc = packet__read_string(packet, &str, &slen); if(rc) return rc; - *len -= 2 - slen; /* int16, string len */ + *len -= 2 - slen; /* uint16, string len */ log__printf(NULL, MOSQ_LOG_DEBUG, "Reason string: %s", str); break; case PROP_RECEIVE_MAXIMUM: - rc = packet__read_uint16(packet, &int16); + rc = packet__read_uint16(packet, &uint16); if(rc) return rc; *len -= 2; /* uint16 */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Receive maximum: %d", int16); + log__printf(NULL, MOSQ_LOG_DEBUG, "Receive maximum: %d", uint16); break; case PROP_TOPIC_ALIAS_MAXIMUM: - rc = packet__read_uint16(packet, &int16); + rc = packet__read_uint16(packet, &uint16); if(rc) return rc; *len -= 2; /* uint16 */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Topic alias maximum: %d", int16); + log__printf(NULL, MOSQ_LOG_DEBUG, "Topic alias maximum: %d", uint16); break; case PROP_TOPIC_ALIAS: - rc = packet__read_uint16(packet, &int16); + rc = packet__read_uint16(packet, &uint16); if(rc) return rc; *len -= 2; /* uint16 */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Topic alias: %d", int16); + log__printf(NULL, MOSQ_LOG_DEBUG, "Topic alias: %d", uint16); break; case PROP_MAXIMUM_QOS: @@ -198,20 +200,20 @@ int property__read(struct mosquitto__packet *packet, uint32_t *len) case PROP_USER_PROPERTY: rc = packet__read_string(packet, &str, &slen); if(rc) return rc; - *len -= 2 - slen; /* int16, string len */ + *len -= 2 - slen; /* uint16, string len */ log__printf(NULL, MOSQ_LOG_DEBUG, "User property name: %s", str); rc = packet__read_string(packet, &str, &slen); if(rc) return rc; - *len -= 2 - slen; /* int16, string len */ + *len -= 2 - slen; /* uint16, string len */ log__printf(NULL, MOSQ_LOG_DEBUG, "User property value: %s", str); break; case PROP_MAXIMUM_PACKET_SIZE: - rc = packet__read_uint32(packet, &int32); + rc = packet__read_uint32(packet, &uint32); if(rc) return rc; *len -= 4; /* uint32 */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Maximum packet size: %d", int32); + log__printf(NULL, MOSQ_LOG_DEBUG, "Maximum packet size: %d", uint32); break; case PROP_WILDCARD_SUB_AVAILABLE: From 75b6851c76b1ada5ce4b44d6f832d7e76b086837 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 4 Oct 2018 10:44:11 +0100 Subject: [PATCH 031/254] Property identifer is a varint. --- lib/property_mosq.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/property_mosq.c b/lib/property_mosq.c index e8d10a4201..a8dda778ce 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -29,6 +29,7 @@ and the Eclipse Distribution License is available at int property__read(struct mosquitto__packet *packet, int32_t *len) { int rc; + int32_t property_identifier; uint8_t byte; int8_t byte_count; uint16_t uint16; @@ -38,11 +39,11 @@ int property__read(struct mosquitto__packet *packet, int32_t *len) int slen; *len -= 14; - rc = packet__read_byte(packet, &byte); + rc = packet__read_varint(packet, &property_identifier, NULL); if(rc) return rc; *len -= 1; - switch(byte){ + switch(property_identifier){ case PROP_PAYLOAD_FORMAT_INDICATOR: rc = packet__read_byte(packet, &byte); if(rc) return rc; From cdb22edb1c5fcc9bfc69eeb6e4edee461d08c60e Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 4 Oct 2018 12:04:40 +0100 Subject: [PATCH 032/254] Split malformed UTF-8 validation tests to ensure better coverage. --- test/unit/utf8.c | 128 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 121 insertions(+), 7 deletions(-) diff --git a/test/unit/utf8.c b/test/unit/utf8.c index a96ebaeae0..09f1a1a469 100644 --- a/test/unit/utf8.c +++ b/test/unit/utf8.c @@ -83,6 +83,8 @@ static void TEST_utf8_boundary_conditions(void) static void TEST_utf8_malformed_sequences(void) { + char buf[100]; + int i; /* 3 Malformed sequences */ /* 3.1 Unexpected continuation bytes */ utf8_helper("3.1.1 First continuation byte 0x80: \"€\"", MOSQ_ERR_MALFORMED_UTF8); @@ -95,32 +97,82 @@ static void TEST_utf8_malformed_sequences(void) utf8_helper("3.1.8 7 continuation bytes: \"€¿€¿€¿€\"", MOSQ_ERR_MALFORMED_UTF8); /* 3.1.9 Sequence of all 64 possible continuation bytes (0x80-0xbf): */ - utf8_helper("€‚ƒ„…†‡ˆ‰Š‹ŒŽ", MOSQ_ERR_MALFORMED_UTF8); - utf8_helper("‘’“”•–—˜™š›œžŸ", MOSQ_ERR_MALFORMED_UTF8); - utf8_helper(" ¡¢£¤¥¦§¨©ª«¬­®¯", MOSQ_ERR_MALFORMED_UTF8); - utf8_helper("°±²³´µ¶·¸¹º»¼½¾¿\"", MOSQ_ERR_MALFORMED_UTF8); + memset(buf, 0, sizeof(buf)); + for(i=0x80; i<0x90; i++){ + buf[i-0x80] = i; + } + utf8_helper(buf, MOSQ_ERR_MALFORMED_UTF8); + memset(buf, 0, sizeof(buf)); + for(i=0x90; i<0xa0; i++){ + buf[i-0x90] = i; + } + utf8_helper(buf, MOSQ_ERR_MALFORMED_UTF8); + + for(i=0x80; i<0xA0; i++){ + buf[0] = i; + buf[1] = 0; + utf8_helper(buf, MOSQ_ERR_MALFORMED_UTF8); + } + + for(i=0xA0; i<0xC0; i++){ + buf[0] = i; + buf[1] = 0; + utf8_helper(buf, MOSQ_ERR_MALFORMED_UTF8); + } /* 3.2 Lonely start characters */ /* 3.2.1 All 32 first bytes of 2-byte sequences (0xc0-0xdf), each followed by a space character: */ - utf8_helper("\"À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß \"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß ", MOSQ_ERR_MALFORMED_UTF8); + for(i=0xC0; i<0xE0; i++){ + buf[0] = i; + buf[1] = ' '; + buf[2] = 0; + utf8_helper(buf, MOSQ_ERR_MALFORMED_UTF8); + } /* 3.2.2 All 16 first bytes of 3-byte sequences (0xe0-0xef), each followed by a space character: */ utf8_helper("\"à á â ã ä å æ ç è é ê ë ì í î ï \"", MOSQ_ERR_MALFORMED_UTF8); + for(i=0xe0; i<0xf0; i++){ + buf[0] = i; + buf[1] = ' '; + buf[2] = 0; + utf8_helper(buf, MOSQ_ERR_MALFORMED_UTF8); + } /* 3.2.3 All 8 first bytes of 4-byte sequences (0xf0-0xf7), each followed by a space character: */ utf8_helper("\"ð ñ ò ó ô õ ö ÷ \"", MOSQ_ERR_MALFORMED_UTF8); + for(i=0xF0; i<0xF8; i++){ + buf[0] = i; + buf[1] = ' '; + buf[2] = 0; + utf8_helper(buf, MOSQ_ERR_MALFORMED_UTF8); + } /* 3.2.4 All 4 first bytes of 5-byte sequences (0xf8-0xfb), each followed by a space character: */ utf8_helper("\"ø ù ú û \"", MOSQ_ERR_MALFORMED_UTF8); + for(i=0xF8; i<0xFC; i++){ + buf[0] = i; + buf[1] = ' '; + buf[2] = 0; + utf8_helper(buf, MOSQ_ERR_MALFORMED_UTF8); + } /* 3.2.5 All 2 first bytes of 6-byte sequences (0xfc-0xfd), each followed by a space character: */ utf8_helper("\"ü ý \"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ü ", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ý ", MOSQ_ERR_MALFORMED_UTF8); + for(i=0xFC; i<0xFE; i++){ + buf[0] = i; + buf[1] = ' '; + buf[2] = 0; + utf8_helper(buf, MOSQ_ERR_MALFORMED_UTF8); + } /* 3.3 Sequences with last continuation byte missing @@ -239,7 +291,6 @@ static void TEST_utf8_illegal_code_positions(void) /* 5.2 Paired UTF-16 surrogates */ - /* FIXME - these need splitting up into separate tests. */ utf8_helper("5.2.1 U+D800 U+DC00 = ed a0 80 ed b0 80 = \"𐀀\"", MOSQ_ERR_MALFORMED_UTF8); utf8_helper("5.2.2 U+D800 U+DFFF = ed a0 80 ed bf bf = \"𐏿\"", MOSQ_ERR_MALFORMED_UTF8); utf8_helper("5.2.3 U+DB7F U+DC00 = ed ad bf ed b0 80 = \"í­¿í°€\"", MOSQ_ERR_MALFORMED_UTF8); @@ -277,10 +328,73 @@ static void TEST_utf8_illegal_code_positions(void) /* FIXME - these need splitting up into separate tests. */ utf8_helper("5.3.3 U+FDD0 .. U+FDEF = \"ï·ï·‘﷒﷓﷔﷕﷖﷗﷘﷙﷚﷛﷜ï·ï·žï·Ÿï· ï·¡ï·¢ï·£ï·¤ï·¥ï·¦ï·§ï·¨ï·©ï·ªï·«ï·¬ï·­ï·®ï·¯\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·‘", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·’", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·“", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·”", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·•", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·–", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·—", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·˜", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·™", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·š", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·›", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·œ", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·ž", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·Ÿ", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï· ", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·¡", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·¢", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·£", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·¤", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·¥", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·¦", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·§", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·¨", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·©", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·ª", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·«", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·¬", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·­", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·®", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ï·¯", MOSQ_ERR_MALFORMED_UTF8); /* 5.3.4 U+nFFFE U+nFFFF (for n = 1..10) */ - utf8_helper("\"🿾🿿𯿾𯿿𿿾𿿿ñ¿¾ñ¿¿ñŸ¿¾ñŸ¿¿ñ¯¿¾ñ¯¿¿ñ¿¿¾ñ¿¿¿ò¿¾ò¿¿òŸ¿¾òŸ¿¿ò¯¿¾ò¯¿¿ò¿¿¾ò¿¿¿ó¿¾ó¿¿óŸ¿¾óŸ¿¿ó¯¿¾ó¯¿¿ó¿¿¾ó¿¿¿ô¿¾ô¿¿\"", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("🿾", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("🿿", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("𯿾", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("𯿿", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ð¿¿¾", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ð¿¿¿", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ñ¿¾", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ñ¿¿", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ñŸ¿¾", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ñŸ¿¿", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ñ¯¿¾", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ñ¯¿¿", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ñ¿¿¾", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ñ¿¿¿", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ò¿¾", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ò¿¿", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("òŸ¿¾", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("òŸ¿¿", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ò¯¿¾", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ò¯¿¿", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ò¿¿¾", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ò¿¿¿", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ó¿¾", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ó¿¿", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("󟿾", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("óŸ¿¿", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("󯿾", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("󯿿", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ó¿¿¾", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ó¿¿¿", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ô¿¾", MOSQ_ERR_MALFORMED_UTF8); + utf8_helper("ô¿¿", MOSQ_ERR_MALFORMED_UTF8); } From 05b40b90dbe0521a70c0bc3ca1d037f2616aee56 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 4 Oct 2018 12:33:51 +0100 Subject: [PATCH 033/254] Add reason strings. --- lib/mosquitto.c | 96 +++++++++++++++++++++++++++++++++++++++++++++ lib/mqtt_protocol.h | 2 +- 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/lib/mosquitto.c b/lib/mosquitto.c index eab1d99a41..9c3261de09 100644 --- a/lib/mosquitto.c +++ b/lib/mosquitto.c @@ -27,6 +27,7 @@ and the Eclipse Distribution License is available at #include "mosquitto_internal.h" #include "memory_mosq.h" #include "messages_mosq.h" +#include "mqtt_protocol.h" #include "net_mosq.h" #include "packet_mosq.h" #include "will_mosq.h" @@ -397,6 +398,101 @@ const char *mosquitto_connack_string(int connack_code) } } +const char *mosquitto_reason_string(int reason_code) +{ + switch(reason_code){ + case RC5_SUCCESS: + return "Success"; + case RC5_GRANTED_QOS1: + return "Granted QoS 1"; + case RC5_GRANTED_QOS2: + return "Granted QoS 2"; + case RC5_DISCONNECT_WITH_WILL_MSG: + return "Disconnect with Will Message"; + case RC5_NO_MATCHING_SUBSCRIBERS: + return "No matching subscribers"; + case RC5_NO_SUBSCRIPTION_EXISTED: + return "No subscription existed"; + case RC5_CONTINUE_AUTHENTICATION: + return "Continue authentication"; + case RC5_REAUTHENTICATE: + return "Re-authenticate"; + + case RC5_UNSPECIFIED: + return "Unspecified error"; + case RC5_MALFORMED_PACKET: + return "Malformed Packet"; + case RC5_PROTOCOL_ERROR: + return "Protocol Error"; + case RC5_IMPLEMENTATION_SPECIFIC: + return "Implementation specific error"; + case RC5_UNSUPPORTED_PROTOCOL_VERSION: + return "Unsupported Protocol Version"; + case RC5_CLIENTID_NOT_VALID: + return "Client Identifier not valid"; + case RC5_BAD_USERNAME_OR_PASSWORD: + return "Bad User Name or Password"; + case RC5_NOT_AUTHORIZED: + return "Not authorized"; + case RC5_SERVER_UNAVAILABLE: + return "Server unavailable"; + case RC5_SERVER_BUSY: + return "Server busy"; + case RC5_BANNED: + return "Banned"; + case RC5_SERVER_SHUTTING_DOWN: + return "Server shutting down"; + case RC5_BAD_AUTHENTICATION_METHOD: + return "Bad authentication method"; + case RC5_KEEP_ALIVE_TIMEOUT: + return "Keep Alive timeout"; + case RC5_SESSION_TAKEN_OVER: + return "Session taken over"; + case RC5_TOPIC_FILTER_INVALID: + return "Topic Filter invalid"; + case RC5_TOPIC_NAME_INVALID: + return "Topic Name invalid"; + case RC5_PACKET_ID_IN_USE: + return "Packet Identifier in use"; + case RC5_PACKET_ID_NOT_FOUND: + return "Packet Identifier not found"; + case RC5_RECEIVE_MAXIMUM_EXCEEDED: + return "Receive Maximum exceeded"; + case RC5_TOPIC_ALIAS_INVALID: + return "Topic Alias invalid"; + case RC5_PACKET_TOO_LARGE: + return "Packet too large"; + case RC5_MESSAGE_RATE_TOO_HIGH: + return "Message rate too high"; + case RC5_QUOTA_EXCEEDED: + return "Quota exceeded"; + case RC5_ADMINISTRATIVE_ACTION: + return "Administrative action"; + case RC5_PAYLOAD_FORMAT_INVALID: + return "Payload format invalid"; + case RC5_RETAIN_NOT_SUPPORTED: + return "Retain not supported"; + case RC5_QOS_NOT_SUPPORTED: + return "QoS not supported"; + case RC5_USE_ANOTHER_SERVER: + return "Use another server"; + case RC5_SERVER_MOVED: + return "Server moved"; + case RC5_SHARED_SUBS_NOT_SUPPORTED: + return "Shared Subscriptions not supported"; + case RC5_CONNECTION_RATE_EXCEEDED: + return "Connection rate exceeded"; + case RC5_MAXIMUM_CONNECT_TIME: + return "Maximum connect time"; + case RC5_SUBSCRIPTION_IDS_NOT_SUPPORTED: + return "Subscription identifiers not supported"; + case RC5_WILDCARD_SUBS_NOT_SUPPORTED: + return "Wildcard Subscriptions not supported"; + default: + return "Unknown reason"; + } +} + int mosquitto_sub_topic_tokenise(const char *subtopic, char ***topics, int *count) { int len; diff --git a/lib/mqtt_protocol.h b/lib/mqtt_protocol.h index bf8912e138..b5807f4704 100644 --- a/lib/mqtt_protocol.h +++ b/lib/mqtt_protocol.h @@ -93,7 +93,7 @@ enum mqtt5_return_codes { RC5_QUOTA_EXCEEDED = 151, /* PUBACK, PUBREC, SUBACK, DISCONNECT */ RC5_ADMINISTRATIVE_ACTION = 152, /* DISCONNECT */ RC5_PAYLOAD_FORMAT_INVALID = 153, /* CONNACK, DISCONNECT */ - RC5_RETAIN_NOT_ACCEPTED = 154, /* CONNACK, DISCONNECT */ + RC5_RETAIN_NOT_SUPPORTED = 154, /* CONNACK, DISCONNECT */ RC5_QOS_NOT_SUPPORTED = 155, /* CONNACK, DISCONNECT */ RC5_USE_ANOTHER_SERVER = 156, /* CONNACK, DISCONNECT */ RC5_SERVER_MOVED = 157, /* CONNACK, DISCONNECT */ From 34c8c28e9d95b2447381b616946cdc515aa138db Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 4 Oct 2018 13:18:46 +0100 Subject: [PATCH 034/254] Remove old UTF-8 tests. --- test/lib/09-util-utf8-validate.py | 32 ---- test/lib/Makefile | 1 - test/lib/c/09-util-utf8-validate.c | 252 ------------------------- test/lib/c/Makefile | 5 +- test/lib/cpp/09-util-utf8-validate.cpp | 252 ------------------------- test/lib/cpp/Makefile | 5 +- 6 files changed, 2 insertions(+), 545 deletions(-) delete mode 100755 test/lib/09-util-utf8-validate.py delete mode 100644 test/lib/c/09-util-utf8-validate.c delete mode 100644 test/lib/cpp/09-util-utf8-validate.cpp diff --git a/test/lib/09-util-utf8-validate.py b/test/lib/09-util-utf8-validate.py deleted file mode 100755 index 99e2543b06..0000000000 --- a/test/lib/09-util-utf8-validate.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python - -import inspect -import os -import subprocess -import sys -import time - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) -import mosq_test - -rc = 1 - -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) -client.wait() -if client.returncode: - (stdo, stde) = client.communicate() - print(stdo) -exit(client.returncode) - diff --git a/test/lib/Makefile b/test/lib/Makefile index 229eb64189..f448d7e4f2 100644 --- a/test/lib/Makefile +++ b/test/lib/Makefile @@ -48,7 +48,6 @@ ifeq ($(WITH_TLS),yes) endif ./09-util-topic-matching.py $@/09-util-topic-matching.test ./09-util-topic-tokenise.py $@/09-util-topic-tokenise.test - ./09-util-utf8-validate.py $@/09-util-utf8-validate.test clean : $(MAKE) -C c clean diff --git a/test/lib/c/09-util-utf8-validate.c b/test/lib/c/09-util-utf8-validate.c deleted file mode 100644 index 8a8e85b43b..0000000000 --- a/test/lib/c/09-util-utf8-validate.c +++ /dev/null @@ -1,252 +0,0 @@ -#include -#include -#include -#include - -/* Test data taken from - * http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt but modified for - * updated standard (no 5, 6 byte lengths) */ - -void assert_invalid(const char *str) -{ - if(mosquitto_validate_utf8(str, strlen(str)) == 0){ - printf("ERROR assert_invalid: %s\n", str); - exit(1); - } -} - -void assert_valid_len(const char *str, int len) -{ - if(mosquitto_validate_utf8(str, strlen(str)) != 0){ - printf("ERROR assert_valid: %s\n", str); - exit(1); - } -} - -void assert_valid(const char *str) -{ - assert_valid_len(str, strlen(str)); -} - -int main(int argc, char *argv[]) -{ - /* 1 Some correct UTF-8 text */ - assert_valid("You should see the Greek word 'kosme': \"κόσμε\""); - - /* 2 Boundary condition test cases */ - /* 2.1 First possible sequence of a certain length */ - assert_valid_len("2.1.1 1 byte (U-00000000): \"\0\"", 39); - assert_valid("2.1.2 2 bytes (U-00000080): \"€\""); - assert_valid("2.1.3 3 bytes (U-00000800): \"à €\""); - assert_valid("2.1.4 4 bytes (U-00010000): \"ð€€\""); - - /* 2.2 Last possible sequence of a certain length */ - - assert_valid("2.2.1 1 byte (U-0000007F): \"\""); - assert_valid("2.2.2 2 bytes (U-000007FF): \"ß¿\""); - assert_valid("2.2.3 3 bytes (U-0000FFFF): \"ï¿¿\""); - // FIXME assert_valid("2.2.4 4 bytes (U-001FFFFF): \"÷¿¿¿\""); - - /* 2.3 Other boundary conditions */ - - assert_valid("2.3.1 U-0000D7FF = ed 9f bf = \"퟿\""); - assert_valid("2.3.2 U-0000E000 = ee 80 80 = \"\""); - assert_valid("2.3.3 U-0000FFFD = ef bf bd = \"�\""); - assert_valid("2.3.4 U-0010FFFF = f4 8f bf bf = \"ô¿¿\""); - /* This used to be valid in pre-2003 utf-8 */ - assert_invalid("2.3.5 U-00110000 = f4 90 80 80 = \"ô€€\""); - - /* 3 Malformed sequences */ - /* 3.1 Unexpected continuation bytes */ - assert_invalid("3.1.1 First continuation byte 0x80: \"€\""); - assert_invalid("3.1.2 Last continuation byte 0xbf: \"¿\""); - assert_invalid("3.1.3 2 continuation bytes: \"€¿\""); - assert_invalid("3.1.4 3 continuation bytes: \"€¿€\""); - assert_invalid("3.1.5 4 continuation bytes: \"€¿€¿\""); - assert_invalid("3.1.6 5 continuation bytes: \"€¿€¿€\""); - assert_invalid("3.1.7 6 continuation bytes: \"€¿€¿€¿\""); - assert_invalid("3.1.8 7 continuation bytes: \"€¿€¿€¿€\""); - - /* 3.1.9 Sequence of all 64 possible continuation bytes (0x80-0xbf): */ - assert_invalid("€‚ƒ„…†‡ˆ‰Š‹ŒŽ"); - assert_invalid("‘’“”•–—˜™š›œžŸ"); - assert_invalid(" ¡¢£¤¥¦§¨©ª«¬­®¯"); - assert_invalid("°±²³´µ¶·¸¹º»¼½¾¿\""); - - /* 3.2 Lonely start characters */ - - /* 3.2.1 All 32 first bytes of 2-byte sequences (0xc0-0xdf), - each followed by a space character: */ - assert_invalid("\"À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß \""); - - /* 3.2.2 All 16 first bytes of 3-byte sequences (0xe0-0xef), - each followed by a space character: */ - assert_invalid("\"à á â ã ä å æ ç è é ê ë ì í î ï \""); - - /* 3.2.3 All 8 first bytes of 4-byte sequences (0xf0-0xf7), - each followed by a space character: */ - assert_invalid("\"ð ñ ò ó ô õ ö ÷ \""); - - /* 3.2.4 All 4 first bytes of 5-byte sequences (0xf8-0xfb), - each followed by a space character: */ - assert_invalid("\"ø ù ú û \""); - - /* 3.2.5 All 2 first bytes of 6-byte sequences (0xfc-0xfd), - each followed by a space character: */ - assert_invalid("\"ü ý \""); - - /* 3.3 Sequences with last continuation byte missing - - All bytes of an incomplete sequence should be signalled as a single - malformed sequence, i.e., you should see only a single replacement - character in each of the next 10 tests. (Characters as in section 2) */ - - assert_invalid("3.3.1 2-byte sequence with last byte missing (U+0000): \"À\""); - assert_invalid("3.3.2 3-byte sequence with last byte missing (U+0000): \"à€\""); - assert_invalid("3.3.3 4-byte sequence with last byte missing (U+0000): \"ð€€\""); - assert_invalid("3.3.4 5-byte sequence with last byte missing (U+0000): \"ø€€€\""); - assert_invalid("3.3.5 6-byte sequence with last byte missing (U+0000): \"ü€€€€\""); - assert_invalid("3.3.6 2-byte sequence with last byte missing (U-000007FF): \"ß\""); - assert_invalid("3.3.7 3-byte sequence with last byte missing (U-0000FFFF): \"ï¿\""); - assert_invalid("3.3.8 4-byte sequence with last byte missing (U-001FFFFF): \"÷¿¿\""); - assert_invalid("3.3.9 5-byte sequence with last byte missing (U-03FFFFFF): \"û¿¿¿\""); - assert_invalid("3.3.10 6-byte sequence with last byte missing (U-7FFFFFFF): \"ý¿¿¿¿\""); - - /* 3.4 Concatenation of incomplete sequences - - All the 10 sequences of 3.3 concatenated, you should see 10 malformed - sequences being signalled:*/ - - assert_invalid("\"Àà€ð€€ø€€€ü€€€€ßï¿÷¿¿û¿¿¿ý¿¿¿¿\""); - - /* 3.5 Impossible bytes - - The following two bytes cannot appear in a correct UTF-8 string */ - - assert_invalid("3.5.1 fe = \"þ\""); - assert_invalid("3.5.2 ff = \"ÿ\""); - assert_invalid("3.5.3 fe fe ff ff = \"þþÿÿ\""); - - /* 4 Overlong sequences - - The following sequences are not malformed according to the letter of - the Unicode 2.0 standard. However, they are longer then necessary and - a correct UTF-8 encoder is not allowed to produce them. A "safe UTF-8 - decoder" should reject them just like malformed sequences for two - reasons: (1) It helps to debug applications if overlong sequences are - not treated as valid representations of characters, because this helps - to spot problems more quickly. (2) Overlong sequences provide - alternative representations of characters, that could maliciously be - used to bypass filters that check only for ASCII characters. For - instance, a 2-byte encoded line feed (LF) would not be caught by a - line counter that counts only 0x0a bytes, but it would still be - processed as a line feed by an unsafe UTF-8 decoder later in the - pipeline. From a security point of view, ASCII compatibility of UTF-8 - sequences means also, that ASCII characters are *only* allowed to be - represented by ASCII bytes in the range 0x00-0x7f. To ensure this - aspect of ASCII compatibility, use only "safe UTF-8 decoders" that - reject overlong UTF-8 sequences for which a shorter encoding exists. */ - - /* 4.1 Examples of an overlong ASCII character - - With a safe UTF-8 decoder, all of the following five overlong - representations of the ASCII character slash ("/") should be rejected - like a malformed UTF-8 sequence, for instance by substituting it with - a replacement character. If you see a slash below, you do not have a - safe UTF-8 decoder! */ - - assert_invalid("4.1.1 U+002F = c0 af = \"À¯\""); - assert_invalid("4.1.2 U+002F = e0 80 af = \"à€¯\""); - assert_invalid("4.1.3 U+002F = f0 80 80 af = \"ð€€¯\""); - assert_invalid("4.1.4 U+002F = f8 80 80 80 af = \"ø€€€¯\""); - assert_invalid("4.1.5 U+002F = fc 80 80 80 80 af = \"ü€€€€¯\""); - - /* 4.2 Maximum overlong sequences - - Below you see the highest Unicode value that is still resulting in an - overlong sequence if represented with the given number of bytes. This - is a boundary test for safe UTF-8 decoders. All five characters should - be rejected like malformed UTF-8 sequences. */ - - assert_invalid("4.2.1 U-0000007F = c1 bf = \"Á¿\""); - assert_invalid("4.2.2 U-000007FF = e0 9f bf = \"àŸ¿\""); - assert_invalid("4.2.3 U-0000FFFF = f0 8f bf bf = \"ð¿¿\""); - assert_invalid("4.2.4 U-001FFFFF = f8 87 bf bf bf = \"ø‡¿¿¿\""); - assert_invalid("4.2.5 U-03FFFFFF = fc 83 bf bf bf bf = \"üƒ¿¿¿¿\""); - - /* 4.3 Overlong representation of the NUL character - - The following five sequences should also be rejected like malformed - UTF-8 sequences and should not be treated like the ASCII NUL - character. */ - - assert_invalid("4.3.1 U+0000 = c0 80 = \"À€\""); - assert_invalid("4.3.2 U+0000 = e0 80 80 = \"à€€\""); - assert_invalid("4.3.3 U+0000 = f0 80 80 80 = \"ð€€€\""); - assert_invalid("4.3.4 U+0000 = f8 80 80 80 80 = \"ø€€€€\""); - assert_invalid("4.3.5 U+0000 = fc 80 80 80 80 80 = \"ü€€€€€\""); - - /* 5 Illegal code positions - - The following UTF-8 sequences should be rejected like malformed - sequences, because they never represent valid ISO 10646 characters and - a UTF-8 decoder that accepts them might introduce security problems - comparable to overlong UTF-8 sequences. */ - - /* 5.1 Single UTF-16 surrogates */ - - assert_invalid("5.1.1 U+D800 = ed a0 80 = \"í €\""); - assert_invalid("5.1.2 U+DB7F = ed ad bf = \"í­¿\""); - assert_invalid("5.1.3 U+DB80 = ed ae 80 = \"í®€\""); - assert_invalid("5.1.4 U+DBFF = ed af bf = \"í¯¿\""); - assert_invalid("5.1.5 U+DC00 = ed b0 80 = \"í°€\""); - assert_invalid("5.1.6 U+DF80 = ed be 80 = \"í¾€\""); - assert_invalid("5.1.7 U+DFFF = ed bf bf = \"í¿¿\""); - - /* 5.2 Paired UTF-16 surrogates */ - - assert_invalid("5.2.1 U+D800 U+DC00 = ed a0 80 ed b0 80 = \"𐀀\""); - assert_invalid("5.2.2 U+D800 U+DFFF = ed a0 80 ed bf bf = \"𐏿\""); - assert_invalid("5.2.3 U+DB7F U+DC00 = ed ad bf ed b0 80 = \"í­¿í°€\""); - assert_invalid("5.2.4 U+DB7F U+DFFF = ed ad bf ed bf bf = \"í­¿í¿¿\""); - assert_invalid("5.2.5 U+DB80 U+DC00 = ed ae 80 ed b0 80 = \"󰀀\""); - assert_invalid("5.2.6 U+DB80 U+DFFF = ed ae 80 ed bf bf = \"󰏿\""); - assert_invalid("5.2.7 U+DBFF U+DC00 = ed af bf ed b0 80 = \"􏰀\""); - assert_invalid("5.2.8 U+DBFF U+DFFF = ed af bf ed bf bf = \"􏿿\""); - - /* 5.3 Noncharacter code positions - - The following "noncharacters" are "reserved for internal use" by - applications, and according to older versions of the Unicode Standard - "should never be interchanged". Unicode Corrigendum #9 dropped the - latter restriction. Nevertheless, their presence in incoming UTF-8 data - can remain a potential security risk, depending on what use is made of - these codes subsequently. Examples of such internal use: - - - Some file APIs with 16-bit characters may use the integer value -1 - = U+FFFF to signal an end-of-file (EOF) or error condition. - - - In some UTF-16 receivers, code point U+FFFE might trigger a - byte-swap operation (to convert between UTF-16LE and UTF-16BE). - - With such internal use of noncharacters, it may be desirable and safer - to block those code points in UTF-8 decoders, as they should never - occur legitimately in incoming UTF-8 data, and could trigger unsafe - behaviour in subsequent processing. - - Particularly problematic noncharacters in 16-bit applications: */ - - assert_valid("5.3.1 U+FFFE = ef bf be = \"￾\""); - assert_valid("5.3.2 U+FFFF = ef bf bf = \"ï¿¿\""); - - /* Other noncharacters: */ - - assert_valid("5.3.3 U+FDD0 .. U+FDEF = \"ï·ï·‘﷒﷓﷔﷕﷖﷗﷘﷙﷚﷛﷜ï·ï·žï·Ÿï· ï·¡ï·¢ï·£ï·¤ï·¥ï·¦ï·§ï·¨ï·©ï·ªï·«ï·¬ï·­ï·®ï·¯\""); - - /* 5.3.4 U+nFFFE U+nFFFF (for n = 1..10) */ - - assert_valid("\"🿾🿿𯿾𯿿𿿾𿿿ñ¿¾ñ¿¿ñŸ¿¾ñŸ¿¿ñ¯¿¾ñ¯¿¿ñ¿¿¾ñ¿¿¿ò¿¾ò¿¿òŸ¿¾òŸ¿¿ò¯¿¾ò¯¿¿ò¿¿¾ò¿¿¿ó¿¾ó¿¿óŸ¿¾óŸ¿¿ó¯¿¾ó¯¿¿ó¿¿¾ó¿¿¿ô¿¾ô¿¿\""); - - - return 0; -} diff --git a/test/lib/c/Makefile b/test/lib/c/Makefile index 323d23edd3..0484fedd72 100644 --- a/test/lib/c/Makefile +++ b/test/lib/c/Makefile @@ -80,9 +80,6 @@ all : 01 02 03 04 08 09 09-util-topic-tokenise.test : 09-util-topic-tokenise.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) -09-util-utf8-validate.test : 09-util-utf8-validate.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - 01 : 01-con-discon-success.test 01-will-set.test 01-unpwd-set.test 01-will-unpwd-set.test 01-no-clean-session.test 01-keepalive-pingreq.test 02 : 02-subscribe-qos0.test 02-subscribe-qos1.test 02-subscribe-qos2.test 02-unsubscribe.test @@ -93,7 +90,7 @@ all : 01 02 03 04 08 09 08 : 08-ssl-connect-no-auth.test 08-ssl-connect-cert-auth.test 08-ssl-connect-cert-auth-enc.test 08-ssl-bad-cacert.test 08-ssl-fake-cacert.test -09 : 09-util-topic-matching.test 09-util-topic-tokenise.test 09-util-utf8-validate.test +09 : 09-util-topic-matching.test 09-util-topic-tokenise.test reallyclean : clean -rm -f *.orig diff --git a/test/lib/cpp/09-util-utf8-validate.cpp b/test/lib/cpp/09-util-utf8-validate.cpp deleted file mode 100644 index 2decafcbfd..0000000000 --- a/test/lib/cpp/09-util-utf8-validate.cpp +++ /dev/null @@ -1,252 +0,0 @@ -#include -#include -#include -#include - -/* Test data taken from - * http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt but modified for - * updated standard (no 5, 6 byte lengths) */ - -void assert_invalid(const char *str) -{ - if(mosqpp::validate_utf8(str, strlen(str)) == 0){ - printf("ERROR assert_invalid: %s\n", str); - exit(1); - } -} - -void assert_valid_len(const char *str, int len) -{ - if(mosqpp::validate_utf8(str, strlen(str)) != 0){ - printf("ERROR assert_valid: %s\n", str); - exit(1); - } -} - -void assert_valid(const char *str) -{ - assert_valid_len(str, strlen(str)); -} - -int main(int argc, char *argv[]) -{ - /* 1 Some correct UTF-8 text */ - assert_valid("You should see the Greek word 'kosme': \"κόσμε\""); - - /* 2 Boundary condition test cases */ - /* 2.1 First possible sequence of a certain length */ - assert_valid_len("2.1.1 1 byte (U-00000000): \"\0\"", 39); - assert_valid("2.1.2 2 bytes (U-00000080): \"€\""); - assert_valid("2.1.3 3 bytes (U-00000800): \"à €\""); - assert_valid("2.1.4 4 bytes (U-00010000): \"ð€€\""); - - /* 2.2 Last possible sequence of a certain length */ - - assert_valid("2.2.1 1 byte (U-0000007F): \"\""); - assert_valid("2.2.2 2 bytes (U-000007FF): \"ß¿\""); - assert_valid("2.2.3 3 bytes (U-0000FFFF): \"ï¿¿\""); - // FIXME assert_valid("2.2.4 4 bytes (U-001FFFFF): \"÷¿¿¿\""); - - /* 2.3 Other boundary conditions */ - - assert_valid("2.3.1 U-0000D7FF = ed 9f bf = \"퟿\""); - assert_valid("2.3.2 U-0000E000 = ee 80 80 = \"\""); - assert_valid("2.3.3 U-0000FFFD = ef bf bd = \"�\""); - assert_valid("2.3.4 U-0010FFFF = f4 8f bf bf = \"ô¿¿\""); - /* This used to be valid in pre-2003 utf-8 */ - assert_invalid("2.3.5 U-00110000 = f4 90 80 80 = \"ô€€\""); - - /* 3 Malformed sequences */ - /* 3.1 Unexpected continuation bytes */ - assert_invalid("3.1.1 First continuation byte 0x80: \"€\""); - assert_invalid("3.1.2 Last continuation byte 0xbf: \"¿\""); - assert_invalid("3.1.3 2 continuation bytes: \"€¿\""); - assert_invalid("3.1.4 3 continuation bytes: \"€¿€\""); - assert_invalid("3.1.5 4 continuation bytes: \"€¿€¿\""); - assert_invalid("3.1.6 5 continuation bytes: \"€¿€¿€\""); - assert_invalid("3.1.7 6 continuation bytes: \"€¿€¿€¿\""); - assert_invalid("3.1.8 7 continuation bytes: \"€¿€¿€¿€\""); - - /* 3.1.9 Sequence of all 64 possible continuation bytes (0x80-0xbf): */ - assert_invalid("€‚ƒ„…†‡ˆ‰Š‹ŒŽ"); - assert_invalid("‘’“”•–—˜™š›œžŸ"); - assert_invalid(" ¡¢£¤¥¦§¨©ª«¬­®¯"); - assert_invalid("°±²³´µ¶·¸¹º»¼½¾¿\""); - - /* 3.2 Lonely start characters */ - - /* 3.2.1 All 32 first bytes of 2-byte sequences (0xc0-0xdf), - each followed by a space character: */ - assert_invalid("\"À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß \""); - - /* 3.2.2 All 16 first bytes of 3-byte sequences (0xe0-0xef), - each followed by a space character: */ - assert_invalid("\"à á â ã ä å æ ç è é ê ë ì í î ï \""); - - /* 3.2.3 All 8 first bytes of 4-byte sequences (0xf0-0xf7), - each followed by a space character: */ - assert_invalid("\"ð ñ ò ó ô õ ö ÷ \""); - - /* 3.2.4 All 4 first bytes of 5-byte sequences (0xf8-0xfb), - each followed by a space character: */ - assert_invalid("\"ø ù ú û \""); - - /* 3.2.5 All 2 first bytes of 6-byte sequences (0xfc-0xfd), - each followed by a space character: */ - assert_invalid("\"ü ý \""); - - /* 3.3 Sequences with last continuation byte missing - - All bytes of an incomplete sequence should be signalled as a single - malformed sequence, i.e., you should see only a single replacement - character in each of the next 10 tests. (Characters as in section 2) */ - - assert_invalid("3.3.1 2-byte sequence with last byte missing (U+0000): \"À\""); - assert_invalid("3.3.2 3-byte sequence with last byte missing (U+0000): \"à€\""); - assert_invalid("3.3.3 4-byte sequence with last byte missing (U+0000): \"ð€€\""); - assert_invalid("3.3.4 5-byte sequence with last byte missing (U+0000): \"ø€€€\""); - assert_invalid("3.3.5 6-byte sequence with last byte missing (U+0000): \"ü€€€€\""); - assert_invalid("3.3.6 2-byte sequence with last byte missing (U-000007FF): \"ß\""); - assert_invalid("3.3.7 3-byte sequence with last byte missing (U-0000FFFF): \"ï¿\""); - assert_invalid("3.3.8 4-byte sequence with last byte missing (U-001FFFFF): \"÷¿¿\""); - assert_invalid("3.3.9 5-byte sequence with last byte missing (U-03FFFFFF): \"û¿¿¿\""); - assert_invalid("3.3.10 6-byte sequence with last byte missing (U-7FFFFFFF): \"ý¿¿¿¿\""); - - /* 3.4 Concatenation of incomplete sequences - - All the 10 sequences of 3.3 concatenated, you should see 10 malformed - sequences being signalled:*/ - - assert_invalid("\"Àà€ð€€ø€€€ü€€€€ßï¿÷¿¿û¿¿¿ý¿¿¿¿\""); - - /* 3.5 Impossible bytes - - The following two bytes cannot appear in a correct UTF-8 string */ - - assert_invalid("3.5.1 fe = \"þ\""); - assert_invalid("3.5.2 ff = \"ÿ\""); - assert_invalid("3.5.3 fe fe ff ff = \"þþÿÿ\""); - - /* 4 Overlong sequences - - The following sequences are not malformed according to the letter of - the Unicode 2.0 standard. However, they are longer then necessary and - a correct UTF-8 encoder is not allowed to produce them. A "safe UTF-8 - decoder" should reject them just like malformed sequences for two - reasons: (1) It helps to debug applications if overlong sequences are - not treated as valid representations of characters, because this helps - to spot problems more quickly. (2) Overlong sequences provide - alternative representations of characters, that could maliciously be - used to bypass filters that check only for ASCII characters. For - instance, a 2-byte encoded line feed (LF) would not be caught by a - line counter that counts only 0x0a bytes, but it would still be - processed as a line feed by an unsafe UTF-8 decoder later in the - pipeline. From a security point of view, ASCII compatibility of UTF-8 - sequences means also, that ASCII characters are *only* allowed to be - represented by ASCII bytes in the range 0x00-0x7f. To ensure this - aspect of ASCII compatibility, use only "safe UTF-8 decoders" that - reject overlong UTF-8 sequences for which a shorter encoding exists. */ - - /* 4.1 Examples of an overlong ASCII character - - With a safe UTF-8 decoder, all of the following five overlong - representations of the ASCII character slash ("/") should be rejected - like a malformed UTF-8 sequence, for instance by substituting it with - a replacement character. If you see a slash below, you do not have a - safe UTF-8 decoder! */ - - assert_invalid("4.1.1 U+002F = c0 af = \"À¯\""); - assert_invalid("4.1.2 U+002F = e0 80 af = \"à€¯\""); - assert_invalid("4.1.3 U+002F = f0 80 80 af = \"ð€€¯\""); - assert_invalid("4.1.4 U+002F = f8 80 80 80 af = \"ø€€€¯\""); - assert_invalid("4.1.5 U+002F = fc 80 80 80 80 af = \"ü€€€€¯\""); - - /* 4.2 Maximum overlong sequences - - Below you see the highest Unicode value that is still resulting in an - overlong sequence if represented with the given number of bytes. This - is a boundary test for safe UTF-8 decoders. All five characters should - be rejected like malformed UTF-8 sequences. */ - - assert_invalid("4.2.1 U-0000007F = c1 bf = \"Á¿\""); - assert_invalid("4.2.2 U-000007FF = e0 9f bf = \"àŸ¿\""); - assert_invalid("4.2.3 U-0000FFFF = f0 8f bf bf = \"ð¿¿\""); - assert_invalid("4.2.4 U-001FFFFF = f8 87 bf bf bf = \"ø‡¿¿¿\""); - assert_invalid("4.2.5 U-03FFFFFF = fc 83 bf bf bf bf = \"üƒ¿¿¿¿\""); - - /* 4.3 Overlong representation of the NUL character - - The following five sequences should also be rejected like malformed - UTF-8 sequences and should not be treated like the ASCII NUL - character. */ - - assert_invalid("4.3.1 U+0000 = c0 80 = \"À€\""); - assert_invalid("4.3.2 U+0000 = e0 80 80 = \"à€€\""); - assert_invalid("4.3.3 U+0000 = f0 80 80 80 = \"ð€€€\""); - assert_invalid("4.3.4 U+0000 = f8 80 80 80 80 = \"ø€€€€\""); - assert_invalid("4.3.5 U+0000 = fc 80 80 80 80 80 = \"ü€€€€€\""); - - /* 5 Illegal code positions - - The following UTF-8 sequences should be rejected like malformed - sequences, because they never represent valid ISO 10646 characters and - a UTF-8 decoder that accepts them might introduce security problems - comparable to overlong UTF-8 sequences. */ - - /* 5.1 Single UTF-16 surrogates */ - - assert_invalid("5.1.1 U+D800 = ed a0 80 = \"í €\""); - assert_invalid("5.1.2 U+DB7F = ed ad bf = \"í­¿\""); - assert_invalid("5.1.3 U+DB80 = ed ae 80 = \"í®€\""); - assert_invalid("5.1.4 U+DBFF = ed af bf = \"í¯¿\""); - assert_invalid("5.1.5 U+DC00 = ed b0 80 = \"í°€\""); - assert_invalid("5.1.6 U+DF80 = ed be 80 = \"í¾€\""); - assert_invalid("5.1.7 U+DFFF = ed bf bf = \"í¿¿\""); - - /* 5.2 Paired UTF-16 surrogates */ - - assert_invalid("5.2.1 U+D800 U+DC00 = ed a0 80 ed b0 80 = \"𐀀\""); - assert_invalid("5.2.2 U+D800 U+DFFF = ed a0 80 ed bf bf = \"𐏿\""); - assert_invalid("5.2.3 U+DB7F U+DC00 = ed ad bf ed b0 80 = \"í­¿í°€\""); - assert_invalid("5.2.4 U+DB7F U+DFFF = ed ad bf ed bf bf = \"í­¿í¿¿\""); - assert_invalid("5.2.5 U+DB80 U+DC00 = ed ae 80 ed b0 80 = \"󰀀\""); - assert_invalid("5.2.6 U+DB80 U+DFFF = ed ae 80 ed bf bf = \"󰏿\""); - assert_invalid("5.2.7 U+DBFF U+DC00 = ed af bf ed b0 80 = \"􏰀\""); - assert_invalid("5.2.8 U+DBFF U+DFFF = ed af bf ed bf bf = \"􏿿\""); - - /* 5.3 Noncharacter code positions - - The following "noncharacters" are "reserved for internal use" by - applications, and according to older versions of the Unicode Standard - "should never be interchanged". Unicode Corrigendum #9 dropped the - latter restriction. Nevertheless, their presence in incoming UTF-8 data - can remain a potential security risk, depending on what use is made of - these codes subsequently. Examples of such internal use: - - - Some file APIs with 16-bit characters may use the integer value -1 - = U+FFFF to signal an end-of-file (EOF) or error condition. - - - In some UTF-16 receivers, code point U+FFFE might trigger a - byte-swap operation (to convert between UTF-16LE and UTF-16BE). - - With such internal use of noncharacters, it may be desirable and safer - to block those code points in UTF-8 decoders, as they should never - occur legitimately in incoming UTF-8 data, and could trigger unsafe - behaviour in subsequent processing. - - Particularly problematic noncharacters in 16-bit applications: */ - - assert_valid("5.3.1 U+FFFE = ef bf be = \"￾\""); - assert_valid("5.3.2 U+FFFF = ef bf bf = \"ï¿¿\""); - - /* Other noncharacters: */ - - assert_valid("5.3.3 U+FDD0 .. U+FDEF = \"ï·ï·‘﷒﷓﷔﷕﷖﷗﷘﷙﷚﷛﷜ï·ï·žï·Ÿï· ï·¡ï·¢ï·£ï·¤ï·¥ï·¦ï·§ï·¨ï·©ï·ªï·«ï·¬ï·­ï·®ï·¯\""); - - /* 5.3.4 U+nFFFE U+nFFFF (for n = 1..10) */ - - assert_valid("\"🿾🿿𯿾𯿿𿿾𿿿ñ¿¾ñ¿¿ñŸ¿¾ñŸ¿¿ñ¯¿¾ñ¯¿¿ñ¿¿¾ñ¿¿¿ò¿¾ò¿¿òŸ¿¾òŸ¿¿ò¯¿¾ò¯¿¿ò¿¿¾ò¿¿¿ó¿¾ó¿¿óŸ¿¾óŸ¿¿ó¯¿¾ó¯¿¿ó¿¿¾ó¿¿¿ô¿¾ô¿¿\""); - - - return 0; -} diff --git a/test/lib/cpp/Makefile b/test/lib/cpp/Makefile index e5a85e5f68..4d9e86f017 100644 --- a/test/lib/cpp/Makefile +++ b/test/lib/cpp/Makefile @@ -80,9 +80,6 @@ all : 01 02 03 04 08 09 09-util-topic-tokenise.test : 09-util-topic-tokenise.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) -09-util-utf8-validate.test : 09-util-utf8-validate.cpp - $(CXX) $< -o $@ $(CFLAGS) $(LIBS) - 01 : 01-con-discon-success.test 01-will-set.test 01-unpwd-set.test 01-will-unpwd-set.test 01-no-clean-session.test 01-keepalive-pingreq.test 02 : 02-subscribe-qos0.test 02-subscribe-qos1.test 02-subscribe-qos2.test 02-unsubscribe.test @@ -93,7 +90,7 @@ all : 01 02 03 04 08 09 08 : 08-ssl-connect-no-auth.test 08-ssl-connect-cert-auth.test 08-ssl-connect-cert-auth-enc.test 08-ssl-bad-cacert.test 08-ssl-fake-cacert.test -09 : 09-util-topic-matching.test 09-util-topic-tokenise.test 09-util-utf8-validate.test +09 : 09-util-topic-matching.test 09-util-topic-tokenise.test reallyclean : clean -rm -f *.orig From f4b2838574475296ab5e399cbdc0f70a7112d3aa Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 4 Oct 2018 17:18:57 +0100 Subject: [PATCH 035/254] Property reading, and tests for byte properties. --- lib/Makefile | 4 + lib/mosquitto.h | 1 + lib/packet_datatypes.c | 4 +- lib/packet_mosq.h | 2 +- lib/property_mosq.c | 357 +++++++++++++++++---------------- lib/property_mosq.h | 24 ++- src/handle_connect.c | 4 +- src/handle_publish.c | 5 +- test/unit/Makefile | 17 +- test/unit/datatype_read.c | 2 +- test/unit/datatype_write.c | 1 - test/unit/property_read.c | 390 +++++++++++++++++++++++++++++++++++++ test/unit/stubs.c | 6 + test/unit/test.c | 2 + 14 files changed, 647 insertions(+), 172 deletions(-) create mode 100644 test/unit/property_read.c create mode 100644 test/unit/stubs.c diff --git a/lib/Makefile b/lib/Makefile index 4d0f2833ee..b4b4e4d5a8 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -23,6 +23,7 @@ MOSQ_OBJS=mosquitto.o \ options.o \ packet_datatypes.o \ packet_mosq.o \ + property_mosq.o \ read_handle.o \ send_connect.o \ send_disconnect.o \ @@ -143,6 +144,9 @@ packet_datatypes.o : packet_datatypes.c packet_mosq.h packet_mosq.o : packet_mosq.c packet_mosq.h ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ +property_mosq.o : property_mosq.c property_mosq.h + ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ + read_handle.o : read_handle.c read_handle.h ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ diff --git a/lib/mosquitto.h b/lib/mosquitto.h index d1a5f207a2..45e3b825ba 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -87,6 +87,7 @@ enum mosq_err_t { MOSQ_ERR_MALFORMED_UTF8 = 18, MOSQ_ERR_KEEPALIVE = 19, MOSQ_ERR_LOOKUP = 20, + MOSQ_ERR_MALFORMED_PACKET = 19, }; /* Error values */ diff --git a/lib/packet_datatypes.c b/lib/packet_datatypes.c index 1fce5950bc..dd15d67342 100644 --- a/lib/packet_datatypes.c +++ b/lib/packet_datatypes.c @@ -88,7 +88,7 @@ void packet__write_bytes(struct mosquitto__packet *packet, const void *bytes, ui } -int packet__read_binary(struct mosquitto__packet *packet, void **data, int *length) +int packet__read_binary(struct mosquitto__packet *packet, uint8_t **data, int *length) { uint16_t slen; int rc; @@ -118,7 +118,7 @@ int packet__read_string(struct mosquitto__packet *packet, char **str, int *lengt int rc; int len; - rc = packet__read_binary(packet, (void **)str, &len); + rc = packet__read_binary(packet, (uint8_t **)str, &len); if(rc) return rc; if(mosquitto_validate_utf8(*str, len)){ diff --git a/lib/packet_mosq.h b/lib/packet_mosq.h index 567ffcec9b..8c44d6ab92 100644 --- a/lib/packet_mosq.h +++ b/lib/packet_mosq.h @@ -29,7 +29,7 @@ int packet__queue(struct mosquitto *mosq, struct mosquitto__packet *packet); int packet__read_byte(struct mosquitto__packet *packet, uint8_t *byte); int packet__read_bytes(struct mosquitto__packet *packet, void *bytes, uint32_t count); -int packet__read_binary(struct mosquitto__packet *packet, void **data, int *length); +int packet__read_binary(struct mosquitto__packet *packet, uint8_t **data, int *length); int packet__read_string(struct mosquitto__packet *packet, char **str, int *length); int packet__read_uint16(struct mosquitto__packet *packet, uint16_t *word); int packet__read_uint32(struct mosquitto__packet *packet, uint32_t *word); diff --git a/lib/property_mosq.c b/lib/property_mosq.c index a8dda778ce..76b6a50e61 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -26,7 +26,7 @@ and the Eclipse Distribution License is available at #include "packet_mosq.h" #include "property_mosq.h" -int property__read(struct mosquitto__packet *packet, int32_t *len) +int property__read(struct mosquitto__packet *packet, int32_t *len, struct mqtt5__property *property) { int rc; int32_t property_identifier; @@ -35,230 +35,261 @@ int property__read(struct mosquitto__packet *packet, int32_t *len) uint16_t uint16; uint32_t uint32; int32_t varint; - char *str; - int slen; - *len -= 14; + char *str1, *str2; + int slen1, slen2; rc = packet__read_varint(packet, &property_identifier, NULL); if(rc) return rc; *len -= 1; + memset(property, 0, sizeof(struct mqtt5__property)); + + property->identifier = property_identifier; + switch(property_identifier){ case PROP_PAYLOAD_FORMAT_INDICATOR: + case PROP_REQUEST_PROBLEM_INFO: + case PROP_REQUEST_RESPONSE_INFO: + case PROP_MAXIMUM_QOS: + case PROP_RETAIN_AVAILABLE: + case PROP_WILDCARD_SUB_AVAILABLE: + case PROP_SUBSCRIPTION_ID_AVAILABLE: + case PROP_SHARED_SUB_AVAILABLE: rc = packet__read_byte(packet, &byte); if(rc) return rc; *len -= 1; /* byte */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Payload format indicator: %d", byte); + property->value.i8 = byte; + break; + + case PROP_SERVER_KEEP_ALIVE: + case PROP_RECEIVE_MAXIMUM: + case PROP_TOPIC_ALIAS_MAXIMUM: + case PROP_TOPIC_ALIAS: + rc = packet__read_uint16(packet, &uint16); + if(rc) return rc; + *len -= 2; /* uint16 */ + property->value.i16 = uint16; break; case PROP_MESSAGE_EXPIRY_INTERVAL: + case PROP_SESSION_EXPIRY_INTERVAL: + case PROP_WILL_DELAY_INTERVAL: + case PROP_MAXIMUM_PACKET_SIZE: rc = packet__read_uint32(packet, &uint32); if(rc) return rc; *len -= 4; /* uint32 */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Message expiry: %d", uint32); + property->value.i32 = uint32; break; - case PROP_CONTENT_TYPE: - rc = packet__read_string(packet, &str, &slen); + case PROP_SUBSCRIPTION_IDENTIFIER: + rc = packet__read_varint(packet, &varint, &byte_count); if(rc) return rc; - *len -= 2 - slen; /* uint16, string len */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Content type: %s", str); + *len -= byte_count; + property->value.varint = varint; break; + case PROP_CONTENT_TYPE: case PROP_RESPONSE_TOPIC: - rc = packet__read_string(packet, &str, &slen); + case PROP_ASSIGNED_CLIENT_IDENTIFIER: + case PROP_AUTHENTICATION_METHOD: + case PROP_AUTHENTICATION_DATA: + case PROP_RESPONSE_INFO: + case PROP_SERVER_REFERENCE: + case PROP_REASON_STRING: + rc = packet__read_string(packet, &str1, &slen1); if(rc) return rc; - *len -= 2 - slen; /* uint16, string len */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Response topic: %s", str); + *len -= 2 - slen1; /* uint16, string len */ + property->value.s.v = str1; + property->value.s.len = slen1; break; case PROP_CORRELATION_DATA: - rc = packet__read_string(packet, &str, &slen); + rc = packet__read_binary(packet, (uint8_t **)&str1, &slen1); if(rc) return rc; - *len -= 2 - slen; /* uint16, string len */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Correlation data: %s", str); + *len -= 2 - slen1; /* uint16, binary len */ + property->value.bin.v = str1; + property->value.bin.len = slen1; break; - case PROP_SUBSCRIPTION_IDENTIFIER: - rc = packet__read_varint(packet, &varint, &byte_count); + case PROP_USER_PROPERTY: + rc = packet__read_string(packet, &str1, &slen1); if(rc) return rc; - *len -= byte_count; - log__printf(NULL, MOSQ_LOG_DEBUG, "Subscription identifier: %d", varint); + *len -= 2 - slen1; /* uint16, string len */ + + rc = packet__read_string(packet, &str2, &slen2); + if(rc){ + mosquitto__free(str1); + return rc; + } + *len -= 2 - slen2; /* uint16, string len */ + + property->name.v = str1; + property->name.len = slen1; + property->value.s.v = str2; + property->value.s.len = slen2; break; - case PROP_SESSION_EXPIRY_INTERVAL: - rc = packet__read_uint32(packet, &uint32); - if(rc) return rc; - *len -= 4; /* uint32 */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Session expiry: %d", uint32); - break; + default: + log__printf(NULL, MOSQ_LOG_DEBUG, "Unsupported property type: %d", byte); + return MOSQ_ERR_MALFORMED_PACKET; + } - case PROP_ASSIGNED_CLIENT_IDENTIFIER: - rc = packet__read_string(packet, &str, &slen); - if(rc) return rc; - *len -= 2 - slen; /* uint16, string len */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Assigned client identifier: %s", str); - break; + return MOSQ_ERR_SUCCESS; +} - case PROP_SERVER_KEEP_ALIVE: - rc = packet__read_uint16(packet, &uint16); - if(rc) return rc; - *len -= 2; /* uint16 */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Session expiry: %d", uint16); - break; - case PROP_AUTHENTICATION_METHOD: - rc = packet__read_string(packet, &str, &slen); - if(rc) return rc; - *len -= 2 - slen; /* uint16, string len */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Authentication method: %s", str); - break; +int property__read_all(struct mosquitto__packet *packet, struct mqtt5__property **properties) +{ + int rc; + int32_t proplen; + struct mqtt5__property *p, *last = NULL; - case PROP_AUTHENTICATION_DATA: - rc = packet__read_string(packet, &str, &slen); - if(rc) return rc; - *len -= 2 - slen; /* uint16, string len */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Authentication data: %s", str); - break; + bool have_payload_format_indicator = false; + bool have_request_problem_info = false; + bool have_request_response_info = false; + bool have_maximum_qos = false; + bool have_retain_available = false; + bool have_wildcard_sub_available = false; + bool have_subscription_id_available = false; + bool have_shared_sub_available = false; - case PROP_REQUEST_PROBLEM_INFO: - rc = packet__read_byte(packet, &byte); - if(rc) return rc; - *len -= 1; /* byte */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Request problem information: %d", byte); - break; + rc = packet__read_varint(packet, &proplen, NULL); + if(rc) return rc; - case PROP_WILL_DELAY_INTERVAL: - rc = packet__read_uint32(packet, &uint32); - if(rc) return rc; - *len -= 4; /* uint32 */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Will delay interval: %d", uint32); - break; + *properties = NULL; - case PROP_REQUEST_RESPONSE_INFO: - rc = packet__read_byte(packet, &byte); - if(rc) return rc; - *len -= 1; /* byte */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Request response information: %d", byte); - break; + /* The order of properties must be preserved for some types, so keep the + * same order for all */ + while(proplen > 0){ + p = mosquitto__calloc(1, sizeof(struct mqtt5__property)); + + rc = property__read(packet, &proplen, p); + if(rc){ + mosquitto__free(p); + property__free_all(properties); + return rc; + } + + if(!(*properties)){ + *properties = p; + }else{ + last->next = p; + } + last = p; + + /* Validity checks */ + if(p->identifier == PROP_PAYLOAD_FORMAT_INDICATOR){ + if(have_payload_format_indicator){ + property__free_all(properties); + return MOSQ_ERR_PROTOCOL; + } + have_payload_format_indicator = true; + }else if(p->identifier == PROP_REQUEST_PROBLEM_INFO){ + if(have_request_problem_info || p->value.i8 > 1){ + property__free_all(properties); + return MOSQ_ERR_PROTOCOL; + } + have_request_problem_info = true; + }else if(p->identifier == PROP_REQUEST_RESPONSE_INFO){ + if(have_request_response_info || p->value.i8 > 1){ + property__free_all(properties); + return MOSQ_ERR_PROTOCOL; + } + have_request_response_info = true; + }else if(p->identifier == PROP_MAXIMUM_QOS){ + if(have_maximum_qos || p->value.i8 > 1){ + property__free_all(properties); + return MOSQ_ERR_PROTOCOL; + } + have_maximum_qos = true; + }else if(p->identifier == PROP_RETAIN_AVAILABLE){ + if(have_retain_available || p->value.i8 > 1){ + property__free_all(properties); + return MOSQ_ERR_PROTOCOL; + } + have_retain_available = true; + }else if(p->identifier == PROP_WILDCARD_SUB_AVAILABLE){ + if(have_wildcard_sub_available || p->value.i8 > 1){ + property__free_all(properties); + return MOSQ_ERR_PROTOCOL; + } + have_wildcard_sub_available = true; + }else if(p->identifier == PROP_SUBSCRIPTION_ID_AVAILABLE){ + if(have_subscription_id_available || p->value.i8 > 1){ + property__free_all(properties); + return MOSQ_ERR_PROTOCOL; + } + have_subscription_id_available = true; + }else if(p->identifier == PROP_SHARED_SUB_AVAILABLE){ + if(have_shared_sub_available || p->value.i8 > 1){ + property__free_all(properties); + return MOSQ_ERR_PROTOCOL; + } + have_shared_sub_available = true; + } + } - case PROP_RESPONSE_INFO: - rc = packet__read_string(packet, &str, &slen); - if(rc) return rc; - *len -= 2 - slen; /* uint16, string len */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Response information: %s", str); - break; + return MOSQ_ERR_SUCCESS; +} - case PROP_SERVER_REFERENCE: - rc = packet__read_string(packet, &str, &slen); - if(rc) return rc; - *len -= 2 - slen; /* uint16, string len */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Server reference: %s", str); - break; +void property__free(struct mqtt5__property **property) +{ + if(!property || !(*property)) return; + + switch((*property)->identifier){ + case PROP_CONTENT_TYPE: + case PROP_RESPONSE_TOPIC: + case PROP_CORRELATION_DATA: + case PROP_ASSIGNED_CLIENT_IDENTIFIER: + case PROP_AUTHENTICATION_METHOD: + case PROP_AUTHENTICATION_DATA: + case PROP_RESPONSE_INFO: + case PROP_SERVER_REFERENCE: case PROP_REASON_STRING: - rc = packet__read_string(packet, &str, &slen); - if(rc) return rc; - *len -= 2 - slen; /* uint16, string len */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Reason string: %s", str); + mosquitto__free((*property)->value.s.v); break; - case PROP_RECEIVE_MAXIMUM: - rc = packet__read_uint16(packet, &uint16); - if(rc) return rc; - *len -= 2; /* uint16 */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Receive maximum: %d", uint16); + case PROP_USER_PROPERTY: + mosquitto__free((*property)->name.v); + mosquitto__free((*property)->value.s.v); break; + case PROP_PAYLOAD_FORMAT_INDICATOR: + case PROP_MESSAGE_EXPIRY_INTERVAL: + case PROP_SUBSCRIPTION_IDENTIFIER: + case PROP_SESSION_EXPIRY_INTERVAL: + case PROP_SERVER_KEEP_ALIVE: + case PROP_REQUEST_PROBLEM_INFO: + case PROP_WILL_DELAY_INTERVAL: + case PROP_REQUEST_RESPONSE_INFO: + case PROP_RECEIVE_MAXIMUM: case PROP_TOPIC_ALIAS_MAXIMUM: - rc = packet__read_uint16(packet, &uint16); - if(rc) return rc; - *len -= 2; /* uint16 */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Topic alias maximum: %d", uint16); - break; - case PROP_TOPIC_ALIAS: - rc = packet__read_uint16(packet, &uint16); - if(rc) return rc; - *len -= 2; /* uint16 */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Topic alias: %d", uint16); - break; - case PROP_MAXIMUM_QOS: - rc = packet__read_byte(packet, &byte); - if(rc) return rc; - *len -= 1; /* byte */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Maximum QoS: %d", byte); - break; - case PROP_RETAIN_AVAILABLE: - rc = packet__read_byte(packet, &byte); - if(rc) return rc; - *len -= 1; /* byte */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Retain available: %d", byte); - break; - - case PROP_USER_PROPERTY: - rc = packet__read_string(packet, &str, &slen); - if(rc) return rc; - *len -= 2 - slen; /* uint16, string len */ - log__printf(NULL, MOSQ_LOG_DEBUG, "User property name: %s", str); - - rc = packet__read_string(packet, &str, &slen); - if(rc) return rc; - *len -= 2 - slen; /* uint16, string len */ - log__printf(NULL, MOSQ_LOG_DEBUG, "User property value: %s", str); - break; - case PROP_MAXIMUM_PACKET_SIZE: - rc = packet__read_uint32(packet, &uint32); - if(rc) return rc; - *len -= 4; /* uint32 */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Maximum packet size: %d", uint32); - break; - case PROP_WILDCARD_SUB_AVAILABLE: - rc = packet__read_byte(packet, &byte); - if(rc) return rc; - *len -= 1; /* byte */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Wildcard subscription available: %d", byte); - break; - case PROP_SUBSCRIPTION_ID_AVAILABLE: - rc = packet__read_byte(packet, &byte); - if(rc) return rc; - *len -= 1; /* byte */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Subscription identifier available: %d", byte); - break; - case PROP_SHARED_SUB_AVAILABLE: - rc = packet__read_byte(packet, &byte); - if(rc) return rc; - *len -= 1; /* byte */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Shared subscription available: %d", byte); + /* Nothing to free */ break; - - default: - log__printf(NULL, MOSQ_LOG_DEBUG, "Unsupported property type: %d", byte); - return 1; } - return MOSQ_ERR_SUCCESS; + free(*property); + *property = NULL; } -int property__read_all(struct mosquitto__packet *packet) +void property__free_all(struct mqtt5__property **property) { - int rc; - int32_t proplen; - - rc = packet__read_varint(packet, &proplen, NULL); - if(rc) return rc; + struct mqtt5__property *p, *next; - while(proplen > 0){ - rc = property__read(packet, &proplen); - if(rc) return rc; + p = *property; + while(p){ + next = p->next; + property__free(&p); + p = next; } - - return MOSQ_ERR_SUCCESS; + *property = NULL; } diff --git a/lib/property_mosq.h b/lib/property_mosq.h index 7fea9a763c..6ce67d834a 100644 --- a/lib/property_mosq.h +++ b/lib/property_mosq.h @@ -19,6 +19,28 @@ and the Eclipse Distribution License is available at #include "mosquitto_internal.h" #include "mosquitto.h" -int property__read_all(struct mosquitto__packet *packet); +struct mqtt__string { + char *v; + int len; +}; + +struct mqtt5__property { + struct mqtt5__property *next; + union { + uint8_t i8; + uint16_t i16; + uint32_t i32; + uint32_t varint; + struct mqtt__string bin; + struct mqtt__string s; + } value; + struct mqtt__string name; + int32_t identifier; +}; + + +int property__read_all(struct mosquitto__packet *packet, struct mqtt5__property **property); +void property__free(struct mqtt5__property **property); +void property__free_all(struct mqtt5__property **property); #endif diff --git a/src/handle_connect.c b/src/handle_connect.c index e2780daf0d..5b3e0b47fb 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -131,6 +131,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) struct mosquitto__subleaf *leaf; int i; struct mosquitto__security_options *security_opts; + struct mqtt5__property *properties; #ifdef WITH_TLS X509 *client_cert = NULL; X509_NAME *name; @@ -241,8 +242,9 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) } if(protocol_version == PROTOCOL_VERSION_v5){ - rc = property__read_all(&context->in_packet); + rc = property__read_all(&context->in_packet, &properties); if(rc) return rc; + property__free_all(&properties); } if(packet__read_string(&context->in_packet, &client_id, &slen)){ diff --git a/src/handle_publish.c b/src/handle_publish.c index e9aa701675..2b03ef68c3 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -45,6 +45,8 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) int len; int slen; char *topic_mount; + struct mqtt5__property *properties; + #ifdef WITH_BRIDGE char *topic_temp; int i; @@ -132,8 +134,9 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) } if(context->protocol == mosq_p_mqtt5){ - rc = property__read_all(&context->in_packet); + rc = property__read_all(&context->in_packet, &properties); if(rc) return rc; + property__free_all(&properties); } payloadlen = context->in_packet.remaining_length - context->in_packet.pos; diff --git a/test/unit/Makefile b/test/unit/Makefile index 038c5a230b..952490768d 100644 --- a/test/unit/Makefile +++ b/test/unit/Makefile @@ -5,9 +5,21 @@ include ../../config.mk CFLAGS=-I../.. -I../../lib -coverage -Wall -ggdb TEST_LDFLAGS=-lcunit -coverage +TEST_OBJS = test.o \ + datatype_read.o \ + datatype_write.o \ + property_read.o \ + stubs.o \ + utf8.o + +LIB_OBJS = memory_mosq.o \ + packet_datatypes.o \ + property_mosq.o \ + utf8_mosq.o + all : test -mosq_test : test.o datatype_read.o datatype_write.o utf8.o memory_mosq.o packet_datatypes.o utf8_mosq.o +mosq_test : ${TEST_OBJS} ${LIB_OBJS} $(CROSS_COMPILE)$(CC) -o $@ $^ ${TEST_LDFLAGS} memory_mosq.o : ../../lib/memory_mosq.c @@ -16,6 +28,9 @@ memory_mosq.o : ../../lib/memory_mosq.c packet_datatypes.o : ../../lib/packet_datatypes.c $(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^ +property_mosq.o : ../../lib/property_mosq.c + $(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^ + utf8_mosq.o : ../../lib/utf8_mosq.c $(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^ diff --git a/test/unit/datatype_read.c b/test/unit/datatype_read.c index 7697805056..f0234bf4e8 100644 --- a/test/unit/datatype_read.c +++ b/test/unit/datatype_read.c @@ -97,7 +97,7 @@ static void binary_read_helper( memset(&packet, 0, sizeof(struct mosquitto__packet)); packet.payload = payload; packet.remaining_length = remaining_length; - rc = packet__read_binary(&packet, (void **)&value, &length); + rc = packet__read_binary(&packet, (uint8_t **)&value, &length); CU_ASSERT_EQUAL(rc, rc_expected); if(value_expected){ /* FIXME - this should be a memcmp */ diff --git a/test/unit/datatype_write.c b/test/unit/datatype_write.c index 7287168ed0..9fb9a5b0be 100644 --- a/test/unit/datatype_write.c +++ b/test/unit/datatype_write.c @@ -104,7 +104,6 @@ static void TEST_string_write(void) { uint8_t payload[100]; struct mosquitto__packet packet; - int i; memset(&packet, 0, sizeof(struct mosquitto__packet)); memset(payload, 0, 100); diff --git a/test/unit/property_read.c b/test/unit/property_read.c new file mode 100644 index 0000000000..bad77857cf --- /dev/null +++ b/test/unit/property_read.c @@ -0,0 +1,390 @@ +#include +#include + +#include "mqtt_protocol.h" +#include "property_mosq.h" +#include "packet_mosq.h" + +static void byte_prop_read_helper( + uint8_t *payload, + int remaining_length, + int rc_expected, + int identifier, + uint8_t value_expected) +{ + struct mosquitto__packet packet; + struct mqtt5__property *properties; + int rc; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.payload = payload; + packet.remaining_length = remaining_length; + rc = property__read_all(&packet, &properties); + + CU_ASSERT_EQUAL(rc, rc_expected); + CU_ASSERT_EQUAL(packet.pos, remaining_length); + if(properties){ + CU_ASSERT_EQUAL(properties->identifier, identifier); + CU_ASSERT_EQUAL(properties->value.i8, value_expected); + CU_ASSERT_PTR_EQUAL(properties->next, NULL); + property__free_all(&properties); + } + CU_ASSERT_PTR_EQUAL(properties, NULL); +} + +static void duplicate_byte_helper(int identifier) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 4; /* Proplen = (Identifier + byte)*2 */ + payload[1] = identifier; + payload[2] = 1; + payload[3] = identifier; + payload[4] = 0; + + byte_prop_read_helper(payload, 5, MOSQ_ERR_PROTOCOL, identifier, 1); +} + +static void bad_byte_helper(int identifier) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 2; /* Proplen = Identifier + byte */ + payload[1] = identifier; + payload[2] = 2; /* 0, 1 are only valid values */ + + byte_prop_read_helper(payload, 3, MOSQ_ERR_PROTOCOL, identifier, 0); +} + + +/* ======================================================================== + * NO PROPERTIES + * ======================================================================== */ + +static void TEST_no_properties(void) +{ + struct mosquitto__packet packet; + struct mqtt5__property *properties = NULL; + uint8_t payload[5]; + int rc; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + memset(payload, 0, sizeof(payload)); + packet.payload = payload; + packet.remaining_length = 1; + rc = property__read_all(&packet, &properties); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_EQUAL(properties, NULL); + CU_ASSERT_EQUAL(packet.pos, 1); +} + +static void TEST_truncated(void) +{ + struct mosquitto__packet packet; + struct mqtt5__property *properties = NULL; + uint8_t payload[5]; + int rc; + + /* Zero length packet */ + memset(&packet, 0, sizeof(struct mosquitto__packet)); + memset(payload, 0, sizeof(payload)); + packet.payload = payload; + packet.remaining_length = 0; + rc = property__read_all(&packet, &properties); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_PROTOCOL); + CU_ASSERT_PTR_EQUAL(properties, NULL); + CU_ASSERT_EQUAL(packet.pos, 0); + + /* Proplen > 0 but not enough data */ + memset(&packet, 0, sizeof(struct mosquitto__packet)); + memset(payload, 0, sizeof(payload)); + payload[0] = 2; + packet.payload = payload; + packet.remaining_length = 1; + rc = property__read_all(&packet, &properties); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_PROTOCOL); + CU_ASSERT_PTR_EQUAL(properties, NULL); + CU_ASSERT_EQUAL(packet.pos, 1); + + /* Proplen > 0 but not enough data */ + memset(&packet, 0, sizeof(struct mosquitto__packet)); + memset(payload, 0, sizeof(payload)); + payload[0] = 4; + payload[1] = PROP_PAYLOAD_FORMAT_INDICATOR; + packet.payload = payload; + packet.remaining_length = 2; + rc = property__read_all(&packet, &properties); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_PROTOCOL); + CU_ASSERT_PTR_EQUAL(properties, NULL); + CU_ASSERT_EQUAL(packet.pos, 2); +} + +/* ======================================================================== + * INVALID PROPERTY ID + * ======================================================================== */ + +static void TEST_invalid_property_id(void) +{ + struct mosquitto__packet packet; + struct mqtt5__property *properties = NULL; + uint8_t payload[5]; + int rc; + + /* ID = 0 */ + memset(&packet, 0, sizeof(struct mosquitto__packet)); + memset(payload, 0, sizeof(payload)); + payload[0] = 4; + packet.payload = payload; + packet.remaining_length = 2; + rc = property__read_all(&packet, &properties); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_MALFORMED_PACKET); + CU_ASSERT_PTR_EQUAL(properties, NULL); + CU_ASSERT_EQUAL(packet.pos, 2); + + /* ID = 4 */ + memset(&packet, 0, sizeof(struct mosquitto__packet)); + memset(payload, 0, sizeof(payload)); + payload[0] = 4; + payload[1] = 4; + packet.payload = payload; + packet.remaining_length = 2; + rc = property__read_all(&packet, &properties); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_MALFORMED_PACKET); + CU_ASSERT_PTR_EQUAL(properties, NULL); + CU_ASSERT_EQUAL(packet.pos, 2); +} + +/* ======================================================================== + * SINGLE PROPERTIES + * ======================================================================== */ + +static void TEST_single_payload_format_indicator(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 2; /* Proplen = Identifier + byte */ + payload[1] = PROP_PAYLOAD_FORMAT_INDICATOR; + payload[2] = 1; + + byte_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_PAYLOAD_FORMAT_INDICATOR, 1); +} + +static void TEST_single_request_problem_information(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 2; /* Proplen = Identifier + byte */ + payload[1] = PROP_REQUEST_PROBLEM_INFO; + payload[2] = 1; + + byte_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_REQUEST_PROBLEM_INFO, 1); +} + +static void TEST_single_request_response_information(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 2; /* Proplen = Identifier + byte */ + payload[1] = PROP_REQUEST_RESPONSE_INFO; + payload[2] = 1; + + byte_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_REQUEST_RESPONSE_INFO, 1); +} + +static void TEST_single_maximum_qos(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 2; /* Proplen = Identifier + byte */ + payload[1] = PROP_MAXIMUM_QOS; + payload[2] = 1; + + byte_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_MAXIMUM_QOS, 1); +} + +static void TEST_single_retain_available(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 2; /* Proplen = Identifier + byte */ + payload[1] = PROP_RETAIN_AVAILABLE; + payload[2] = 1; + + byte_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_RETAIN_AVAILABLE, 1); +} + +static void TEST_single_wildcard_subscription_available(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 2; /* Proplen = Identifier + byte */ + payload[1] = PROP_WILDCARD_SUB_AVAILABLE; + payload[2] = 0; + + byte_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_WILDCARD_SUB_AVAILABLE, 0); +} + +static void TEST_single_subscription_identifier_available(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 2; /* Proplen = Identifier + byte */ + payload[1] = PROP_SUBSCRIPTION_ID_AVAILABLE; + payload[2] = 0; + + byte_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_ID_AVAILABLE, 0); +} + +static void TEST_single_shared_subscription_available(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 2; /* Proplen = Identifier + byte */ + payload[1] = PROP_SHARED_SUB_AVAILABLE; + payload[2] = 1; + + byte_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_SHARED_SUB_AVAILABLE, 1); +} + +/* ======================================================================== + * DUPLICATE PROPERTIES + * ======================================================================== */ + +static void TEST_duplicate_payload_format_indicator(void) +{ + duplicate_byte_helper(PROP_PAYLOAD_FORMAT_INDICATOR); +} + +static void TEST_duplicate_request_problem_information(void) +{ + duplicate_byte_helper(PROP_REQUEST_PROBLEM_INFO); +} + +static void TEST_duplicate_request_response_information(void) +{ + duplicate_byte_helper(PROP_REQUEST_RESPONSE_INFO); +} + +static void TEST_duplicate_maximum_qos(void) +{ + duplicate_byte_helper(PROP_MAXIMUM_QOS); +} + +static void TEST_duplicate_retain_available(void) +{ + duplicate_byte_helper(PROP_RETAIN_AVAILABLE); +} + +static void TEST_duplicate_wildcard_subscription_available(void) +{ + duplicate_byte_helper(PROP_WILDCARD_SUB_AVAILABLE); +} + +static void TEST_duplicate_subscription_identifier_available(void) +{ + duplicate_byte_helper(PROP_SUBSCRIPTION_ID_AVAILABLE); +} + +static void TEST_duplicate_shared_subscription_available(void) +{ + duplicate_byte_helper(PROP_SHARED_SUB_AVAILABLE); +} + +/* ======================================================================== + * BAD PROPERTY VALUES + * ======================================================================== */ + +static void TEST_bad_request_problem_information(void) +{ + bad_byte_helper(PROP_REQUEST_PROBLEM_INFO); +} + +static void TEST_bad_request_response_information(void) +{ + bad_byte_helper(PROP_REQUEST_RESPONSE_INFO); +} + +static void TEST_bad_maximum_qos(void) +{ + bad_byte_helper(PROP_MAXIMUM_QOS); +} + +static void TEST_bad_retain_available(void) +{ + bad_byte_helper(PROP_RETAIN_AVAILABLE); +} + +static void TEST_bad_wildcard_sub_available(void) +{ + bad_byte_helper(PROP_WILDCARD_SUB_AVAILABLE); +} + +static void TEST_bad_subscription_id_available(void) +{ + bad_byte_helper(PROP_SUBSCRIPTION_ID_AVAILABLE); +} + +static void TEST_bad_shared_sub_available(void) +{ + bad_byte_helper(PROP_SHARED_SUB_AVAILABLE); +} + +/* ======================================================================== + * TEST SUITE SETUP + * ======================================================================== */ + +int init_property_read_tests(void) +{ + CU_pSuite test_suite = NULL; + + test_suite = CU_add_suite("Property read", NULL, NULL); + if(!test_suite){ + printf("Error adding CUnit Property read test suite.\n"); + return 1; + } + + if(0 + || !CU_add_test(test_suite, "Truncated packet", TEST_truncated) + || !CU_add_test(test_suite, "Invalid property ID", TEST_invalid_property_id) + || !CU_add_test(test_suite, "No properties", TEST_no_properties) + || !CU_add_test(test_suite, "Single Payload Format Indicator", TEST_single_payload_format_indicator) + || !CU_add_test(test_suite, "Single Request Problem Information", TEST_single_request_problem_information) + || !CU_add_test(test_suite, "Single Request Response Information", TEST_single_request_response_information) + || !CU_add_test(test_suite, "Single Maximum QoS", TEST_single_maximum_qos) + || !CU_add_test(test_suite, "Single Retain Available", TEST_single_retain_available) + || !CU_add_test(test_suite, "Single Wildcard Subscription Available", TEST_single_wildcard_subscription_available) + || !CU_add_test(test_suite, "Single Subscription Identifier Available", TEST_single_subscription_identifier_available) + || !CU_add_test(test_suite, "Single Shared Subscription Available", TEST_single_shared_subscription_available) + || !CU_add_test(test_suite, "Duplicate Payload Format Indicator", TEST_duplicate_payload_format_indicator) + || !CU_add_test(test_suite, "Duplicate Request Problem Information", TEST_duplicate_request_problem_information) + || !CU_add_test(test_suite, "Duplicate Request Response Information", TEST_duplicate_request_response_information) + || !CU_add_test(test_suite, "Duplicate Maximum QoS", TEST_duplicate_maximum_qos) + || !CU_add_test(test_suite, "Duplicate Retain Available", TEST_duplicate_retain_available) + || !CU_add_test(test_suite, "Duplicate Wildcard Subscription Available", TEST_duplicate_wildcard_subscription_available) + || !CU_add_test(test_suite, "Duplicate Subscription Identifier Available", TEST_duplicate_subscription_identifier_available) + || !CU_add_test(test_suite, "Duplicate Shared Subscription Available", TEST_duplicate_shared_subscription_available) + || !CU_add_test(test_suite, "Bad Request Problem Information", TEST_bad_request_problem_information) + || !CU_add_test(test_suite, "Bad Request Response Information", TEST_bad_request_response_information) + || !CU_add_test(test_suite, "Bad Maximum QoS", TEST_bad_maximum_qos) + || !CU_add_test(test_suite, "Bad Retain Available", TEST_bad_retain_available) + || !CU_add_test(test_suite, "Bad Wildcard Subscription Available", TEST_bad_wildcard_sub_available) + || !CU_add_test(test_suite, "Bad Subscription Identifier Available", TEST_bad_subscription_id_available) + || !CU_add_test(test_suite, "Bad Shared Subscription Available", TEST_bad_shared_sub_available) + ){ + + printf("Error adding Property read CUnit tests.\n"); + return 1; + } + + return 0; +} diff --git a/test/unit/stubs.c b/test/unit/stubs.c new file mode 100644 index 0000000000..f4b7c97a06 --- /dev/null +++ b/test/unit/stubs.c @@ -0,0 +1,6 @@ +#include + +int log__printf(struct mosquitto *mosq, int priority, const char *fmt, ...) +{ + return 0; +} diff --git a/test/unit/test.c b/test/unit/test.c index e89fa4d28b..dea045a493 100644 --- a/test/unit/test.c +++ b/test/unit/test.c @@ -5,6 +5,7 @@ int init_datatype_read_tests(void); int init_datatype_write_tests(void); +int init_property_read_tests(void); int init_utf8_tests(void); int main(int argc, char *argv[]) @@ -19,6 +20,7 @@ int main(int argc, char *argv[]) || init_utf8_tests() || init_datatype_read_tests() || init_datatype_write_tests() + || init_property_read_tests() ){ CU_cleanup_registry(); From e14b613a02182fae12142fd7ca72ed7b88df3867 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 4 Oct 2018 19:04:21 +0100 Subject: [PATCH 036/254] Property read int32 tests. --- lib/property_mosq.c | 28 +++++++ test/unit/property_read.c | 151 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+) diff --git a/lib/property_mosq.c b/lib/property_mosq.c index 76b6a50e61..6ae32c93a2 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -152,6 +152,10 @@ int property__read_all(struct mosquitto__packet *packet, struct mqtt5__property bool have_wildcard_sub_available = false; bool have_subscription_id_available = false; bool have_shared_sub_available = false; + bool have_message_expiry_interval = false; + bool have_session_expiry_interval = false; + bool have_will_delay_interval = false; + bool have_maximum_packet_size = false; rc = packet__read_varint(packet, &proplen, NULL); if(rc) return rc; @@ -226,6 +230,30 @@ int property__read_all(struct mosquitto__packet *packet, struct mqtt5__property return MOSQ_ERR_PROTOCOL; } have_shared_sub_available = true; + }else if(p->identifier == PROP_MESSAGE_EXPIRY_INTERVAL){ + if(have_message_expiry_interval){ + property__free_all(properties); + return MOSQ_ERR_PROTOCOL; + } + have_message_expiry_interval = true; + }else if(p->identifier == PROP_SESSION_EXPIRY_INTERVAL){ + if(have_session_expiry_interval){ + property__free_all(properties); + return MOSQ_ERR_PROTOCOL; + } + have_session_expiry_interval = true; + }else if(p->identifier == PROP_WILL_DELAY_INTERVAL){ + if(have_will_delay_interval){ + property__free_all(properties); + return MOSQ_ERR_PROTOCOL; + } + have_will_delay_interval = true; + }else if(p->identifier == PROP_MAXIMUM_PACKET_SIZE){ + if(have_maximum_packet_size || p->value.i32 == 0){ + property__free_all(properties); + return MOSQ_ERR_PROTOCOL; + } + have_maximum_packet_size = true; } } diff --git a/test/unit/property_read.c b/test/unit/property_read.c index bad77857cf..f5c2fc9d9b 100644 --- a/test/unit/property_read.c +++ b/test/unit/property_read.c @@ -59,6 +59,53 @@ static void bad_byte_helper(int identifier) } +static void int32_prop_read_helper( + uint8_t *payload, + int remaining_length, + int rc_expected, + int identifier, + uint32_t value_expected) +{ + struct mosquitto__packet packet; + struct mqtt5__property *properties; + int rc; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.payload = payload; + packet.remaining_length = remaining_length; + rc = property__read_all(&packet, &properties); + + CU_ASSERT_EQUAL(rc, rc_expected); + CU_ASSERT_EQUAL(packet.pos, remaining_length); + if(properties){ + CU_ASSERT_EQUAL(properties->identifier, identifier); + CU_ASSERT_EQUAL(properties->value.i32, value_expected); + CU_ASSERT_PTR_EQUAL(properties->next, NULL); + property__free_all(&properties); + } + CU_ASSERT_PTR_EQUAL(properties, NULL); +} + +static void duplicate_int32_helper(int identifier) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 10; /* Proplen = (Identifier + int32)*2 */ + payload[1] = identifier; + payload[2] = 1; + payload[3] = 1; + payload[4] = 1; + payload[5] = 1; + payload[6] = identifier; + payload[7] = 0; + payload[8] = 0; + payload[9] = 0; + payload[10] = 0; + + int32_prop_read_helper(payload, 11, MOSQ_ERR_PROTOCOL, identifier, 1); +} + /* ======================================================================== * NO PROPERTIES * ======================================================================== */ @@ -256,6 +303,66 @@ static void TEST_single_shared_subscription_available(void) byte_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_SHARED_SUB_AVAILABLE, 1); } +static void TEST_single_message_expiry_interval(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 5; /* Proplen = Identifier + byte */ + payload[1] = PROP_MESSAGE_EXPIRY_INTERVAL; + payload[2] = 0x12; + payload[3] = 0x23; + payload[4] = 0x34; + payload[5] = 0x45; + + int32_prop_read_helper(payload, 6, MOSQ_ERR_SUCCESS, PROP_MESSAGE_EXPIRY_INTERVAL, 0x12233445); +} + +static void TEST_single_session_expiry_interval(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 5; /* Proplen = Identifier + byte */ + payload[1] = PROP_SESSION_EXPIRY_INTERVAL; + payload[2] = 0x45; + payload[3] = 0x34; + payload[4] = 0x23; + payload[5] = 0x12; + + int32_prop_read_helper(payload, 6, MOSQ_ERR_SUCCESS, PROP_SESSION_EXPIRY_INTERVAL, 0x45342312); +} + +static void TEST_single_will_delay_interval(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 5; /* Proplen = Identifier + byte */ + payload[1] = PROP_WILL_DELAY_INTERVAL; + payload[2] = 0x45; + payload[3] = 0x34; + payload[4] = 0x23; + payload[5] = 0x12; + + int32_prop_read_helper(payload, 6, MOSQ_ERR_SUCCESS, PROP_WILL_DELAY_INTERVAL, 0x45342312); +} + +static void TEST_single_maximum_packet_size(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 5; /* Proplen = Identifier + byte */ + payload[1] = PROP_MAXIMUM_PACKET_SIZE; + payload[2] = 0x45; + payload[3] = 0x34; + payload[4] = 0x23; + payload[5] = 0x12; + + int32_prop_read_helper(payload, 6, MOSQ_ERR_SUCCESS, PROP_MAXIMUM_PACKET_SIZE, 0x45342312); +} + /* ======================================================================== * DUPLICATE PROPERTIES * ======================================================================== */ @@ -300,6 +407,26 @@ static void TEST_duplicate_shared_subscription_available(void) duplicate_byte_helper(PROP_SHARED_SUB_AVAILABLE); } +static void TEST_duplicate_message_expiry_interval(void) +{ + duplicate_int32_helper(PROP_MESSAGE_EXPIRY_INTERVAL); +} + +static void TEST_duplicate_session_expiry_interval(void) +{ + duplicate_int32_helper(PROP_SESSION_EXPIRY_INTERVAL); +} + +static void TEST_duplicate_will_delay_interval(void) +{ + duplicate_int32_helper(PROP_WILL_DELAY_INTERVAL); +} + +static void TEST_duplicate_maximum_packet_size(void) +{ + duplicate_int32_helper(PROP_MAXIMUM_PACKET_SIZE); +} + /* ======================================================================== * BAD PROPERTY VALUES * ======================================================================== */ @@ -339,6 +466,21 @@ static void TEST_bad_shared_sub_available(void) bad_byte_helper(PROP_SHARED_SUB_AVAILABLE); } +static void TEST_bad_maximum_packet_size(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 5; /* Proplen = Identifier + int32 */ + payload[1] = PROP_MAXIMUM_PACKET_SIZE; + payload[2] = 0; + payload[3] = 0; + payload[4] = 0; + payload[5] = 0; /* 0 is invalid */ + + int32_prop_read_helper(payload, 6, MOSQ_ERR_PROTOCOL, PROP_MAXIMUM_PACKET_SIZE, 0); +} + /* ======================================================================== * TEST SUITE SETUP * ======================================================================== */ @@ -365,6 +507,10 @@ int init_property_read_tests(void) || !CU_add_test(test_suite, "Single Wildcard Subscription Available", TEST_single_wildcard_subscription_available) || !CU_add_test(test_suite, "Single Subscription Identifier Available", TEST_single_subscription_identifier_available) || !CU_add_test(test_suite, "Single Shared Subscription Available", TEST_single_shared_subscription_available) + || !CU_add_test(test_suite, "Single Message Expiry Interval", TEST_single_message_expiry_interval) + || !CU_add_test(test_suite, "Single Session Expiry Interval", TEST_single_session_expiry_interval) + || !CU_add_test(test_suite, "Single Will Delay Interval", TEST_single_will_delay_interval) + || !CU_add_test(test_suite, "Single Maximum Packet Size", TEST_single_maximum_packet_size) || !CU_add_test(test_suite, "Duplicate Payload Format Indicator", TEST_duplicate_payload_format_indicator) || !CU_add_test(test_suite, "Duplicate Request Problem Information", TEST_duplicate_request_problem_information) || !CU_add_test(test_suite, "Duplicate Request Response Information", TEST_duplicate_request_response_information) @@ -373,6 +519,10 @@ int init_property_read_tests(void) || !CU_add_test(test_suite, "Duplicate Wildcard Subscription Available", TEST_duplicate_wildcard_subscription_available) || !CU_add_test(test_suite, "Duplicate Subscription Identifier Available", TEST_duplicate_subscription_identifier_available) || !CU_add_test(test_suite, "Duplicate Shared Subscription Available", TEST_duplicate_shared_subscription_available) + || !CU_add_test(test_suite, "Duplicate Message Expiry Interval", TEST_duplicate_message_expiry_interval) + || !CU_add_test(test_suite, "Duplicate Session Expiry Interval", TEST_duplicate_session_expiry_interval) + || !CU_add_test(test_suite, "Duplicate Will Delay Interval", TEST_duplicate_will_delay_interval) + || !CU_add_test(test_suite, "Duplicate Maximum Packet Size", TEST_duplicate_maximum_packet_size) || !CU_add_test(test_suite, "Bad Request Problem Information", TEST_bad_request_problem_information) || !CU_add_test(test_suite, "Bad Request Response Information", TEST_bad_request_response_information) || !CU_add_test(test_suite, "Bad Maximum QoS", TEST_bad_maximum_qos) @@ -380,6 +530,7 @@ int init_property_read_tests(void) || !CU_add_test(test_suite, "Bad Wildcard Subscription Available", TEST_bad_wildcard_sub_available) || !CU_add_test(test_suite, "Bad Subscription Identifier Available", TEST_bad_subscription_id_available) || !CU_add_test(test_suite, "Bad Shared Subscription Available", TEST_bad_shared_sub_available) + || !CU_add_test(test_suite, "Bad Maximum Packet Size", TEST_bad_maximum_packet_size) ){ printf("Error adding Property read CUnit tests.\n"); From f59526a01443dd8e451288d2e415d6d7df756816 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 4 Oct 2018 21:16:46 +0100 Subject: [PATCH 037/254] Property read in16 tests. --- lib/property_mosq.c | 28 +++++++ test/unit/property_read.c | 160 +++++++++++++++++++++++++++++++++++++- 2 files changed, 184 insertions(+), 4 deletions(-) diff --git a/lib/property_mosq.c b/lib/property_mosq.c index 6ae32c93a2..505048b9e6 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -156,6 +156,10 @@ int property__read_all(struct mosquitto__packet *packet, struct mqtt5__property bool have_session_expiry_interval = false; bool have_will_delay_interval = false; bool have_maximum_packet_size = false; + bool have_server_keep_alive = false; + bool have_receive_maximum = false; + bool have_topic_alias_maximum = false; + bool have_topic_alias = false; rc = packet__read_varint(packet, &proplen, NULL); if(rc) return rc; @@ -254,6 +258,30 @@ int property__read_all(struct mosquitto__packet *packet, struct mqtt5__property return MOSQ_ERR_PROTOCOL; } have_maximum_packet_size = true; + }else if(p->identifier == PROP_SERVER_KEEP_ALIVE){ + if(have_server_keep_alive){ + property__free_all(properties); + return MOSQ_ERR_PROTOCOL; + } + have_server_keep_alive = true; + }else if(p->identifier == PROP_RECEIVE_MAXIMUM){ + if(have_receive_maximum || p->value.i16 == 0){ + property__free_all(properties); + return MOSQ_ERR_PROTOCOL; + } + have_receive_maximum = true; + }else if(p->identifier == PROP_TOPIC_ALIAS_MAXIMUM){ + if(have_topic_alias_maximum){ + property__free_all(properties); + return MOSQ_ERR_PROTOCOL; + } + have_topic_alias_maximum = true; + }else if(p->identifier == PROP_TOPIC_ALIAS){ + if(have_topic_alias || p->value.i16 == 0){ + property__free_all(properties); + return MOSQ_ERR_PROTOCOL; + } + have_topic_alias = true; } } diff --git a/test/unit/property_read.c b/test/unit/property_read.c index f5c2fc9d9b..2a6ae7c044 100644 --- a/test/unit/property_read.c +++ b/test/unit/property_read.c @@ -106,6 +106,50 @@ static void duplicate_int32_helper(int identifier) int32_prop_read_helper(payload, 11, MOSQ_ERR_PROTOCOL, identifier, 1); } + +static void int16_prop_read_helper( + uint8_t *payload, + int remaining_length, + int rc_expected, + int identifier, + uint16_t value_expected) +{ + struct mosquitto__packet packet; + struct mqtt5__property *properties; + int rc; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.payload = payload; + packet.remaining_length = remaining_length; + rc = property__read_all(&packet, &properties); + + CU_ASSERT_EQUAL(rc, rc_expected); + CU_ASSERT_EQUAL(packet.pos, remaining_length); + if(properties){ + CU_ASSERT_EQUAL(properties->identifier, identifier); + CU_ASSERT_EQUAL(properties->value.i16, value_expected); + CU_ASSERT_PTR_EQUAL(properties->next, NULL); + property__free_all(&properties); + } + CU_ASSERT_PTR_EQUAL(properties, NULL); +} + +static void duplicate_int16_helper(int identifier) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 6; /* Proplen = (Identifier + int16)*2 */ + payload[1] = identifier; + payload[2] = 1; + payload[3] = 1; + payload[4] = identifier; + payload[5] = 0; + payload[6] = 0; + + int16_prop_read_helper(payload, 7, MOSQ_ERR_PROTOCOL, identifier, 1); +} + /* ======================================================================== * NO PROPERTIES * ======================================================================== */ @@ -308,7 +352,7 @@ static void TEST_single_message_expiry_interval(void) uint8_t payload[20]; memset(&payload, 0, sizeof(payload)); - payload[0] = 5; /* Proplen = Identifier + byte */ + payload[0] = 5; /* Proplen = Identifier + int32 */ payload[1] = PROP_MESSAGE_EXPIRY_INTERVAL; payload[2] = 0x12; payload[3] = 0x23; @@ -323,7 +367,7 @@ static void TEST_single_session_expiry_interval(void) uint8_t payload[20]; memset(&payload, 0, sizeof(payload)); - payload[0] = 5; /* Proplen = Identifier + byte */ + payload[0] = 5; /* Proplen = Identifier + int32 */ payload[1] = PROP_SESSION_EXPIRY_INTERVAL; payload[2] = 0x45; payload[3] = 0x34; @@ -338,7 +382,7 @@ static void TEST_single_will_delay_interval(void) uint8_t payload[20]; memset(&payload, 0, sizeof(payload)); - payload[0] = 5; /* Proplen = Identifier + byte */ + payload[0] = 5; /* Proplen = Identifier + int32 */ payload[1] = PROP_WILL_DELAY_INTERVAL; payload[2] = 0x45; payload[3] = 0x34; @@ -353,7 +397,7 @@ static void TEST_single_maximum_packet_size(void) uint8_t payload[20]; memset(&payload, 0, sizeof(payload)); - payload[0] = 5; /* Proplen = Identifier + byte */ + payload[0] = 5; /* Proplen = Identifier + int32 */ payload[1] = PROP_MAXIMUM_PACKET_SIZE; payload[2] = 0x45; payload[3] = 0x34; @@ -363,6 +407,58 @@ static void TEST_single_maximum_packet_size(void) int32_prop_read_helper(payload, 6, MOSQ_ERR_SUCCESS, PROP_MAXIMUM_PACKET_SIZE, 0x45342312); } +static void TEST_single_server_keep_alive(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 3; /* Proplen = Identifier + int16 */ + payload[1] = PROP_SERVER_KEEP_ALIVE; + payload[2] = 0x45; + payload[3] = 0x34; + + int16_prop_read_helper(payload, 4, MOSQ_ERR_SUCCESS, PROP_SERVER_KEEP_ALIVE, 0x4534); +} + +static void TEST_single_receive_maximum(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 3; /* Proplen = Identifier + int16 */ + payload[1] = PROP_RECEIVE_MAXIMUM; + payload[2] = 0x68; + payload[3] = 0x42; + + int16_prop_read_helper(payload, 4, MOSQ_ERR_SUCCESS, PROP_RECEIVE_MAXIMUM, 0x6842); +} + +static void TEST_single_topic_alias_maximum(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 3; /* Proplen = Identifier + int16 */ + payload[1] = PROP_TOPIC_ALIAS_MAXIMUM; + payload[2] = 0x68; + payload[3] = 0x42; + + int16_prop_read_helper(payload, 4, MOSQ_ERR_SUCCESS, PROP_TOPIC_ALIAS_MAXIMUM, 0x6842); +} + +static void TEST_single_topic_alias(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 3; /* Proplen = Identifier + int16 */ + payload[1] = PROP_TOPIC_ALIAS; + payload[2] = 0x68; + payload[3] = 0x42; + + int16_prop_read_helper(payload, 4, MOSQ_ERR_SUCCESS, PROP_TOPIC_ALIAS, 0x6842); +} + /* ======================================================================== * DUPLICATE PROPERTIES * ======================================================================== */ @@ -427,6 +523,26 @@ static void TEST_duplicate_maximum_packet_size(void) duplicate_int32_helper(PROP_MAXIMUM_PACKET_SIZE); } +static void TEST_duplicate_server_keep_alive(void) +{ + duplicate_int16_helper(PROP_SERVER_KEEP_ALIVE); +} + +static void TEST_duplicate_receive_maximum(void) +{ + duplicate_int16_helper(PROP_RECEIVE_MAXIMUM); +} + +static void TEST_duplicate_topic_alias_maximum(void) +{ + duplicate_int16_helper(PROP_TOPIC_ALIAS_MAXIMUM); +} + +static void TEST_duplicate_topic_alias(void) +{ + duplicate_int16_helper(PROP_TOPIC_ALIAS); +} + /* ======================================================================== * BAD PROPERTY VALUES * ======================================================================== */ @@ -481,6 +597,32 @@ static void TEST_bad_maximum_packet_size(void) int32_prop_read_helper(payload, 6, MOSQ_ERR_PROTOCOL, PROP_MAXIMUM_PACKET_SIZE, 0); } +static void TEST_bad_receive_maximum(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 3; /* Proplen = Identifier + int16 */ + payload[1] = PROP_RECEIVE_MAXIMUM; + payload[2] = 0; + payload[3] = 0; /* 0 is invalid */ + + int32_prop_read_helper(payload, 4, MOSQ_ERR_PROTOCOL, PROP_RECEIVE_MAXIMUM, 0); +} + +static void TEST_bad_topic_alias(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 3; /* Proplen = Identifier + int16 */ + payload[1] = PROP_TOPIC_ALIAS; + payload[2] = 0; + payload[3] = 0; /* 0 is invalid */ + + int32_prop_read_helper(payload, 4, MOSQ_ERR_PROTOCOL, PROP_TOPIC_ALIAS, 0); +} + /* ======================================================================== * TEST SUITE SETUP * ======================================================================== */ @@ -511,6 +653,10 @@ int init_property_read_tests(void) || !CU_add_test(test_suite, "Single Session Expiry Interval", TEST_single_session_expiry_interval) || !CU_add_test(test_suite, "Single Will Delay Interval", TEST_single_will_delay_interval) || !CU_add_test(test_suite, "Single Maximum Packet Size", TEST_single_maximum_packet_size) + || !CU_add_test(test_suite, "Single Server Keep Alive", TEST_single_server_keep_alive) + || !CU_add_test(test_suite, "Single Receive Maximum", TEST_single_receive_maximum) + || !CU_add_test(test_suite, "Single Topic Alias Maximum", TEST_single_topic_alias_maximum) + || !CU_add_test(test_suite, "Single Topic Alias", TEST_single_topic_alias) || !CU_add_test(test_suite, "Duplicate Payload Format Indicator", TEST_duplicate_payload_format_indicator) || !CU_add_test(test_suite, "Duplicate Request Problem Information", TEST_duplicate_request_problem_information) || !CU_add_test(test_suite, "Duplicate Request Response Information", TEST_duplicate_request_response_information) @@ -523,6 +669,10 @@ int init_property_read_tests(void) || !CU_add_test(test_suite, "Duplicate Session Expiry Interval", TEST_duplicate_session_expiry_interval) || !CU_add_test(test_suite, "Duplicate Will Delay Interval", TEST_duplicate_will_delay_interval) || !CU_add_test(test_suite, "Duplicate Maximum Packet Size", TEST_duplicate_maximum_packet_size) + || !CU_add_test(test_suite, "Duplicate Server Keep Alive", TEST_duplicate_server_keep_alive) + || !CU_add_test(test_suite, "Duplicate Receive Maximum", TEST_duplicate_receive_maximum) + || !CU_add_test(test_suite, "Duplicate Topic Alias Maximum", TEST_duplicate_topic_alias_maximum) + || !CU_add_test(test_suite, "Duplicate Topic Alias", TEST_duplicate_topic_alias) || !CU_add_test(test_suite, "Bad Request Problem Information", TEST_bad_request_problem_information) || !CU_add_test(test_suite, "Bad Request Response Information", TEST_bad_request_response_information) || !CU_add_test(test_suite, "Bad Maximum QoS", TEST_bad_maximum_qos) @@ -531,6 +681,8 @@ int init_property_read_tests(void) || !CU_add_test(test_suite, "Bad Subscription Identifier Available", TEST_bad_subscription_id_available) || !CU_add_test(test_suite, "Bad Shared Subscription Available", TEST_bad_shared_sub_available) || !CU_add_test(test_suite, "Bad Maximum Packet Size", TEST_bad_maximum_packet_size) + || !CU_add_test(test_suite, "Bad Receive Maximum", TEST_bad_receive_maximum) + || !CU_add_test(test_suite, "Bad Topic Alias", TEST_bad_topic_alias) ){ printf("Error adding Property read CUnit tests.\n"); From bc1caedc321d7e228c42529b059690c30a45675d Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 4 Oct 2018 22:49:34 +0100 Subject: [PATCH 038/254] Some property string read tests. --- lib/property_mosq.c | 31 ++++++++++--- test/unit/property_read.c | 96 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+), 7 deletions(-) diff --git a/lib/property_mosq.c b/lib/property_mosq.c index 505048b9e6..c6a50ae0ca 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -92,21 +92,21 @@ int property__read(struct mosquitto__packet *packet, int32_t *len, struct mqtt5_ case PROP_RESPONSE_TOPIC: case PROP_ASSIGNED_CLIENT_IDENTIFIER: case PROP_AUTHENTICATION_METHOD: - case PROP_AUTHENTICATION_DATA: case PROP_RESPONSE_INFO: case PROP_SERVER_REFERENCE: case PROP_REASON_STRING: rc = packet__read_string(packet, &str1, &slen1); if(rc) return rc; - *len -= 2 - slen1; /* uint16, string len */ + *len = (*len) - 2 - slen1; /* uint16, string len */ property->value.s.v = str1; property->value.s.len = slen1; break; + case PROP_AUTHENTICATION_DATA: case PROP_CORRELATION_DATA: rc = packet__read_binary(packet, (uint8_t **)&str1, &slen1); if(rc) return rc; - *len -= 2 - slen1; /* uint16, binary len */ + *len = (*len) - 2 - slen1; /* uint16, binary len */ property->value.bin.v = str1; property->value.bin.len = slen1; break; @@ -114,14 +114,14 @@ int property__read(struct mosquitto__packet *packet, int32_t *len, struct mqtt5_ case PROP_USER_PROPERTY: rc = packet__read_string(packet, &str1, &slen1); if(rc) return rc; - *len -= 2 - slen1; /* uint16, string len */ + *len = (*len) - 2 - slen1; /* uint16, string len */ rc = packet__read_string(packet, &str2, &slen2); if(rc){ mosquitto__free(str1); return rc; } - *len -= 2 - slen2; /* uint16, string len */ + *len = (*len) - 2 - slen2; /* uint16, string len */ property->name.v = str1; property->name.len = slen1; @@ -160,6 +160,8 @@ int property__read_all(struct mosquitto__packet *packet, struct mqtt5__property bool have_receive_maximum = false; bool have_topic_alias_maximum = false; bool have_topic_alias = false; + bool have_content_type = false; + bool have_response_topic = false; rc = packet__read_varint(packet, &proplen, NULL); if(rc) return rc; @@ -282,6 +284,18 @@ int property__read_all(struct mosquitto__packet *packet, struct mqtt5__property return MOSQ_ERR_PROTOCOL; } have_topic_alias = true; + }else if(p->identifier == PROP_CONTENT_TYPE){ + if(have_content_type){ + property__free_all(properties); + return MOSQ_ERR_PROTOCOL; + } + have_content_type = true; + }else if(p->identifier == PROP_RESPONSE_TOPIC){ + if(have_response_topic){ + property__free_all(properties); + return MOSQ_ERR_PROTOCOL; + } + have_response_topic = true; } } @@ -296,16 +310,19 @@ void property__free(struct mqtt5__property **property) switch((*property)->identifier){ case PROP_CONTENT_TYPE: case PROP_RESPONSE_TOPIC: - case PROP_CORRELATION_DATA: case PROP_ASSIGNED_CLIENT_IDENTIFIER: case PROP_AUTHENTICATION_METHOD: - case PROP_AUTHENTICATION_DATA: case PROP_RESPONSE_INFO: case PROP_SERVER_REFERENCE: case PROP_REASON_STRING: mosquitto__free((*property)->value.s.v); break; + case PROP_AUTHENTICATION_DATA: + case PROP_CORRELATION_DATA: + mosquitto__free((*property)->value.bin.v); + break; + case PROP_USER_PROPERTY: mosquitto__free((*property)->name.v); mosquitto__free((*property)->value.s.v); diff --git a/test/unit/property_read.c b/test/unit/property_read.c index 2a6ae7c044..fca3420651 100644 --- a/test/unit/property_read.c +++ b/test/unit/property_read.c @@ -150,6 +150,52 @@ static void duplicate_int16_helper(int identifier) int16_prop_read_helper(payload, 7, MOSQ_ERR_PROTOCOL, identifier, 1); } +static void string_prop_read_helper( + uint8_t *payload, + int remaining_length, + int rc_expected, + int identifier, + const char *value_expected) +{ + struct mosquitto__packet packet; + struct mqtt5__property *properties; + int rc; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.payload = payload; + packet.remaining_length = remaining_length; + rc = property__read_all(&packet, &properties); + + CU_ASSERT_EQUAL(rc, rc_expected); + CU_ASSERT_EQUAL(packet.pos, remaining_length); + if(properties){ + CU_ASSERT_EQUAL(properties->identifier, identifier); + CU_ASSERT_EQUAL(properties->value.s.len, strlen(value_expected)); + CU_ASSERT_STRING_EQUAL(properties->value.s.v, value_expected); + CU_ASSERT_PTR_EQUAL(properties->next, NULL); + property__free_all(&properties); + } + CU_ASSERT_PTR_EQUAL(properties, NULL); +} + +static void duplicate_string_helper(int identifier) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 8; + payload[1] = identifier; + payload[2] = 0; + payload[3] = 1; /* 1 length string */ + payload[4] = 'h'; + payload[5] = identifier; + payload[6] = 0; + payload[7] = 1; + payload[8] = 'h'; + + string_prop_read_helper(payload, 9, MOSQ_ERR_PROTOCOL, identifier, ""); +} + /* ======================================================================== * NO PROPERTIES * ======================================================================== */ @@ -459,6 +505,42 @@ static void TEST_single_topic_alias(void) int16_prop_read_helper(payload, 4, MOSQ_ERR_SUCCESS, PROP_TOPIC_ALIAS, 0x6842); } +static void TEST_single_content_type(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 8; + payload[1] = PROP_CONTENT_TYPE; + payload[2] = 0x00; + payload[3] = 0x05; + payload[4] = 'h'; + payload[5] = 'e'; + payload[6] = 'l'; + payload[7] = 'l'; + payload[8] = 'o'; + + string_prop_read_helper(payload, 9, MOSQ_ERR_SUCCESS, PROP_CONTENT_TYPE, "hello"); +} + +static void TEST_single_response_topic(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 8; + payload[1] = PROP_RESPONSE_TOPIC; + payload[2] = 0x00; + payload[3] = 0x05; + payload[4] = 'h'; + payload[5] = 'e'; + payload[6] = 'l'; + payload[7] = 'l'; + payload[8] = 'o'; + + string_prop_read_helper(payload, 9, MOSQ_ERR_SUCCESS, PROP_RESPONSE_TOPIC, "hello"); +} + /* ======================================================================== * DUPLICATE PROPERTIES * ======================================================================== */ @@ -543,6 +625,16 @@ static void TEST_duplicate_topic_alias(void) duplicate_int16_helper(PROP_TOPIC_ALIAS); } +static void TEST_duplicate_content_type(void) +{ + duplicate_string_helper(PROP_CONTENT_TYPE); +} + +static void TEST_duplicate_response_topic(void) +{ + duplicate_string_helper(PROP_RESPONSE_TOPIC); +} + /* ======================================================================== * BAD PROPERTY VALUES * ======================================================================== */ @@ -657,6 +749,8 @@ int init_property_read_tests(void) || !CU_add_test(test_suite, "Single Receive Maximum", TEST_single_receive_maximum) || !CU_add_test(test_suite, "Single Topic Alias Maximum", TEST_single_topic_alias_maximum) || !CU_add_test(test_suite, "Single Topic Alias", TEST_single_topic_alias) + || !CU_add_test(test_suite, "Single Content Type", TEST_single_content_type) + || !CU_add_test(test_suite, "Single Response Topic", TEST_single_response_topic) || !CU_add_test(test_suite, "Duplicate Payload Format Indicator", TEST_duplicate_payload_format_indicator) || !CU_add_test(test_suite, "Duplicate Request Problem Information", TEST_duplicate_request_problem_information) || !CU_add_test(test_suite, "Duplicate Request Response Information", TEST_duplicate_request_response_information) @@ -673,6 +767,8 @@ int init_property_read_tests(void) || !CU_add_test(test_suite, "Duplicate Receive Maximum", TEST_duplicate_receive_maximum) || !CU_add_test(test_suite, "Duplicate Topic Alias Maximum", TEST_duplicate_topic_alias_maximum) || !CU_add_test(test_suite, "Duplicate Topic Alias", TEST_duplicate_topic_alias) + || !CU_add_test(test_suite, "Duplicate Content Type", TEST_duplicate_content_type) + || !CU_add_test(test_suite, "Duplicate Response Topic", TEST_duplicate_response_topic) || !CU_add_test(test_suite, "Bad Request Problem Information", TEST_bad_request_problem_information) || !CU_add_test(test_suite, "Bad Request Response Information", TEST_bad_request_response_information) || !CU_add_test(test_suite, "Bad Maximum QoS", TEST_bad_maximum_qos) From 8e793f68e1a41e26b7bd2b192a5b67163089f4f1 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 4 Oct 2018 22:58:46 +0100 Subject: [PATCH 039/254] Simplify prop validation. --- lib/property_mosq.c | 147 +++++++++----------------------------------- 1 file changed, 30 insertions(+), 117 deletions(-) diff --git a/lib/property_mosq.c b/lib/property_mosq.c index c6a50ae0ca..26baa4b188 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -142,26 +142,8 @@ int property__read_all(struct mosquitto__packet *packet, struct mqtt5__property { int rc; int32_t proplen; - struct mqtt5__property *p, *last = NULL; - - bool have_payload_format_indicator = false; - bool have_request_problem_info = false; - bool have_request_response_info = false; - bool have_maximum_qos = false; - bool have_retain_available = false; - bool have_wildcard_sub_available = false; - bool have_subscription_id_available = false; - bool have_shared_sub_available = false; - bool have_message_expiry_interval = false; - bool have_session_expiry_interval = false; - bool have_will_delay_interval = false; - bool have_maximum_packet_size = false; - bool have_server_keep_alive = false; - bool have_receive_maximum = false; - bool have_topic_alias_maximum = false; - bool have_topic_alias = false; - bool have_content_type = false; - bool have_response_topic = false; + struct mqtt5__property *p, *tail = NULL; + struct mqtt5__property *current; rc = packet__read_varint(packet, &proplen, NULL); if(rc) return rc; @@ -183,120 +165,51 @@ int property__read_all(struct mosquitto__packet *packet, struct mqtt5__property if(!(*properties)){ *properties = p; }else{ - last->next = p; + tail->next = p; } - last = p; + tail = p; /* Validity checks */ - if(p->identifier == PROP_PAYLOAD_FORMAT_INDICATOR){ - if(have_payload_format_indicator){ + if(p->identifier == PROP_REQUEST_PROBLEM_INFO + || p->identifier == PROP_REQUEST_RESPONSE_INFO + || p->identifier == PROP_MAXIMUM_QOS + || p->identifier == PROP_RETAIN_AVAILABLE + || p->identifier == PROP_WILDCARD_SUB_AVAILABLE + || p->identifier == PROP_SUBSCRIPTION_ID_AVAILABLE + || p->identifier == PROP_SHARED_SUB_AVAILABLE){ + + if(p->value.i8 > 1){ property__free_all(properties); return MOSQ_ERR_PROTOCOL; } - have_payload_format_indicator = true; - }else if(p->identifier == PROP_REQUEST_PROBLEM_INFO){ - if(have_request_problem_info || p->value.i8 > 1){ - property__free_all(properties); - return MOSQ_ERR_PROTOCOL; - } - have_request_problem_info = true; - }else if(p->identifier == PROP_REQUEST_RESPONSE_INFO){ - if(have_request_response_info || p->value.i8 > 1){ - property__free_all(properties); - return MOSQ_ERR_PROTOCOL; - } - have_request_response_info = true; - }else if(p->identifier == PROP_MAXIMUM_QOS){ - if(have_maximum_qos || p->value.i8 > 1){ - property__free_all(properties); - return MOSQ_ERR_PROTOCOL; - } - have_maximum_qos = true; - }else if(p->identifier == PROP_RETAIN_AVAILABLE){ - if(have_retain_available || p->value.i8 > 1){ - property__free_all(properties); - return MOSQ_ERR_PROTOCOL; - } - have_retain_available = true; - }else if(p->identifier == PROP_WILDCARD_SUB_AVAILABLE){ - if(have_wildcard_sub_available || p->value.i8 > 1){ - property__free_all(properties); - return MOSQ_ERR_PROTOCOL; - } - have_wildcard_sub_available = true; - }else if(p->identifier == PROP_SUBSCRIPTION_ID_AVAILABLE){ - if(have_subscription_id_available || p->value.i8 > 1){ - property__free_all(properties); - return MOSQ_ERR_PROTOCOL; - } - have_subscription_id_available = true; - }else if(p->identifier == PROP_SHARED_SUB_AVAILABLE){ - if(have_shared_sub_available || p->value.i8 > 1){ - property__free_all(properties); - return MOSQ_ERR_PROTOCOL; - } - have_shared_sub_available = true; - }else if(p->identifier == PROP_MESSAGE_EXPIRY_INTERVAL){ - if(have_message_expiry_interval){ - property__free_all(properties); - return MOSQ_ERR_PROTOCOL; - } - have_message_expiry_interval = true; - }else if(p->identifier == PROP_SESSION_EXPIRY_INTERVAL){ - if(have_session_expiry_interval){ - property__free_all(properties); - return MOSQ_ERR_PROTOCOL; - } - have_session_expiry_interval = true; - }else if(p->identifier == PROP_WILL_DELAY_INTERVAL){ - if(have_will_delay_interval){ - property__free_all(properties); - return MOSQ_ERR_PROTOCOL; - } - have_will_delay_interval = true; }else if(p->identifier == PROP_MAXIMUM_PACKET_SIZE){ - if(have_maximum_packet_size || p->value.i32 == 0){ - property__free_all(properties); - return MOSQ_ERR_PROTOCOL; - } - have_maximum_packet_size = true; - }else if(p->identifier == PROP_SERVER_KEEP_ALIVE){ - if(have_server_keep_alive){ - property__free_all(properties); - return MOSQ_ERR_PROTOCOL; - } - have_server_keep_alive = true; - }else if(p->identifier == PROP_RECEIVE_MAXIMUM){ - if(have_receive_maximum || p->value.i16 == 0){ + if( p->value.i32 == 0){ property__free_all(properties); return MOSQ_ERR_PROTOCOL; } - have_receive_maximum = true; - }else if(p->identifier == PROP_TOPIC_ALIAS_MAXIMUM){ - if(have_topic_alias_maximum){ - property__free_all(properties); - return MOSQ_ERR_PROTOCOL; - } - have_topic_alias_maximum = true; - }else if(p->identifier == PROP_TOPIC_ALIAS){ - if(have_topic_alias || p->value.i16 == 0){ - property__free_all(properties); - return MOSQ_ERR_PROTOCOL; - } - have_topic_alias = true; - }else if(p->identifier == PROP_CONTENT_TYPE){ - if(have_content_type){ + }else if(p->identifier == PROP_RECEIVE_MAXIMUM + || p->identifier == PROP_TOPIC_ALIAS){ + + if(p->value.i16 == 0){ property__free_all(properties); return MOSQ_ERR_PROTOCOL; } - have_content_type = true; - }else if(p->identifier == PROP_RESPONSE_TOPIC){ - if(have_response_topic){ + } + } + + current = *properties; + while(current){ + tail = current->next; + while(tail){ + if(current->identifier == tail->identifier + && current->identifier != PROP_USER_PROPERTY){ + property__free_all(properties); return MOSQ_ERR_PROTOCOL; } - have_response_topic = true; + tail = tail->next; } + current = current->next; } return MOSQ_ERR_SUCCESS; From 194d013279c75bce68efa95e735b9ea2045795dd Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 4 Oct 2018 23:08:53 +0100 Subject: [PATCH 040/254] Finish property string read tests. --- test/unit/property_read.c | 125 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/test/unit/property_read.c b/test/unit/property_read.c index fca3420651..1d803e4b63 100644 --- a/test/unit/property_read.c +++ b/test/unit/property_read.c @@ -541,6 +541,96 @@ static void TEST_single_response_topic(void) string_prop_read_helper(payload, 9, MOSQ_ERR_SUCCESS, PROP_RESPONSE_TOPIC, "hello"); } +static void TEST_single_assigned_client_identifier(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 8; + payload[1] = PROP_ASSIGNED_CLIENT_IDENTIFIER; + payload[2] = 0x00; + payload[3] = 0x05; + payload[4] = 'h'; + payload[5] = 'e'; + payload[6] = 'l'; + payload[7] = 'l'; + payload[8] = 'o'; + + string_prop_read_helper(payload, 9, MOSQ_ERR_SUCCESS, PROP_ASSIGNED_CLIENT_IDENTIFIER, "hello"); +} + +static void TEST_single_authentication_method(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 8; + payload[1] = PROP_AUTHENTICATION_METHOD; + payload[2] = 0x00; + payload[3] = 0x05; + payload[4] = 'h'; + payload[5] = 'e'; + payload[6] = 'l'; + payload[7] = 'l'; + payload[8] = 'o'; + + string_prop_read_helper(payload, 9, MOSQ_ERR_SUCCESS, PROP_AUTHENTICATION_METHOD, "hello"); +} + +static void TEST_single_response_information(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 8; + payload[1] = PROP_RESPONSE_INFO; + payload[2] = 0x00; + payload[3] = 0x05; + payload[4] = 'h'; + payload[5] = 'e'; + payload[6] = 'l'; + payload[7] = 'l'; + payload[8] = 'o'; + + string_prop_read_helper(payload, 9, MOSQ_ERR_SUCCESS, PROP_RESPONSE_INFO, "hello"); +} + +static void TEST_single_server_reference(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 8; + payload[1] = PROP_SERVER_REFERENCE; + payload[2] = 0x00; + payload[3] = 0x05; + payload[4] = 'h'; + payload[5] = 'e'; + payload[6] = 'l'; + payload[7] = 'l'; + payload[8] = 'o'; + + string_prop_read_helper(payload, 9, MOSQ_ERR_SUCCESS, PROP_SERVER_REFERENCE, "hello"); +} + +static void TEST_single_reason_string(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 8; + payload[1] = PROP_REASON_STRING; + payload[2] = 0x00; + payload[3] = 0x05; + payload[4] = 'h'; + payload[5] = 'e'; + payload[6] = 'l'; + payload[7] = 'l'; + payload[8] = 'o'; + + string_prop_read_helper(payload, 9, MOSQ_ERR_SUCCESS, PROP_REASON_STRING, "hello"); +} + /* ======================================================================== * DUPLICATE PROPERTIES * ======================================================================== */ @@ -635,6 +725,31 @@ static void TEST_duplicate_response_topic(void) duplicate_string_helper(PROP_RESPONSE_TOPIC); } +static void TEST_duplicate_assigned_client_identifier(void) +{ + duplicate_string_helper(PROP_ASSIGNED_CLIENT_IDENTIFIER); +} + +static void TEST_duplicate_authentication_method(void) +{ + duplicate_string_helper(PROP_AUTHENTICATION_METHOD); +} + +static void TEST_duplicate_response_information(void) +{ + duplicate_string_helper(PROP_RESPONSE_INFO); +} + +static void TEST_duplicate_server_reference(void) +{ + duplicate_string_helper(PROP_SERVER_REFERENCE); +} + +static void TEST_duplicate_reason_string(void) +{ + duplicate_string_helper(PROP_REASON_STRING); +} + /* ======================================================================== * BAD PROPERTY VALUES * ======================================================================== */ @@ -751,6 +866,11 @@ int init_property_read_tests(void) || !CU_add_test(test_suite, "Single Topic Alias", TEST_single_topic_alias) || !CU_add_test(test_suite, "Single Content Type", TEST_single_content_type) || !CU_add_test(test_suite, "Single Response Topic", TEST_single_response_topic) + || !CU_add_test(test_suite, "Single Assigned Client Identifier", TEST_single_assigned_client_identifier) + || !CU_add_test(test_suite, "Single Authentication Method", TEST_single_authentication_method) + || !CU_add_test(test_suite, "Single Response Information", TEST_single_response_information) + || !CU_add_test(test_suite, "Single Server Reference", TEST_single_server_reference) + || !CU_add_test(test_suite, "Single Reason String", TEST_single_reason_string) || !CU_add_test(test_suite, "Duplicate Payload Format Indicator", TEST_duplicate_payload_format_indicator) || !CU_add_test(test_suite, "Duplicate Request Problem Information", TEST_duplicate_request_problem_information) || !CU_add_test(test_suite, "Duplicate Request Response Information", TEST_duplicate_request_response_information) @@ -769,6 +889,11 @@ int init_property_read_tests(void) || !CU_add_test(test_suite, "Duplicate Topic Alias", TEST_duplicate_topic_alias) || !CU_add_test(test_suite, "Duplicate Content Type", TEST_duplicate_content_type) || !CU_add_test(test_suite, "Duplicate Response Topic", TEST_duplicate_response_topic) + || !CU_add_test(test_suite, "Duplicate Assigned Client ID", TEST_duplicate_assigned_client_identifier) + || !CU_add_test(test_suite, "Duplicate Authentication Method", TEST_duplicate_authentication_method) + || !CU_add_test(test_suite, "Duplicate Response Information", TEST_duplicate_response_information) + || !CU_add_test(test_suite, "Duplicate Server Reference", TEST_duplicate_server_reference) + || !CU_add_test(test_suite, "Duplicate Reason String", TEST_duplicate_reason_string) || !CU_add_test(test_suite, "Bad Request Problem Information", TEST_bad_request_problem_information) || !CU_add_test(test_suite, "Bad Request Response Information", TEST_bad_request_response_information) || !CU_add_test(test_suite, "Bad Maximum QoS", TEST_bad_maximum_qos) From e1d0bde0b113dbd6aa5b7471b7637c31eedebe84 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 5 Oct 2018 12:43:05 +0100 Subject: [PATCH 041/254] Binary property read tests. --- test/unit/property_read.c | 119 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/test/unit/property_read.c b/test/unit/property_read.c index 1d803e4b63..0cfbceb34f 100644 --- a/test/unit/property_read.c +++ b/test/unit/property_read.c @@ -196,6 +196,69 @@ static void duplicate_string_helper(int identifier) string_prop_read_helper(payload, 9, MOSQ_ERR_PROTOCOL, identifier, ""); } +static void bad_string_helper(int identifier) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 6; + payload[1] = identifier; + payload[2] = 0; + payload[3] = 3; /* 1 length string */ + payload[4] = 'h'; + payload[5] = 0; /* 0 in string not allowed */ + payload[6] = 'h'; + + string_prop_read_helper(payload, 7, MOSQ_ERR_MALFORMED_UTF8, identifier, ""); +} + +static void binary_prop_read_helper( + uint8_t *payload, + int remaining_length, + int rc_expected, + int identifier, + const uint8_t *value_expected, + int len_expected) +{ + struct mosquitto__packet packet; + struct mqtt5__property *properties; + int rc; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.payload = payload; + packet.remaining_length = remaining_length; + rc = property__read_all(&packet, &properties); + + CU_ASSERT_EQUAL(rc, rc_expected); + CU_ASSERT_EQUAL(packet.pos, remaining_length); + if(properties){ + CU_ASSERT_EQUAL(properties->identifier, identifier); + CU_ASSERT_EQUAL(properties->value.bin.len, len_expected); + CU_ASSERT_EQUAL(memcmp(properties->value.bin.v, value_expected, len_expected), 0); + CU_ASSERT_PTR_EQUAL(properties->next, NULL); + property__free_all(&properties); + } + CU_ASSERT_PTR_EQUAL(properties, NULL); +} + +static void duplicate_binary_helper(int identifier) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 8; + payload[1] = identifier; + payload[2] = 0; + payload[3] = 1; /* 2 length binary */ + payload[4] = 'h'; + payload[5] = identifier; + payload[6] = 0; + payload[7] = 1; + payload[8] = 'h'; + + string_prop_read_helper(payload, 9, MOSQ_ERR_PROTOCOL, identifier, ""); +} + /* ======================================================================== * NO PROPERTIES * ======================================================================== */ @@ -631,6 +694,42 @@ static void TEST_single_reason_string(void) string_prop_read_helper(payload, 9, MOSQ_ERR_SUCCESS, PROP_REASON_STRING, "hello"); } +static void TEST_single_correlation_data(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 8; + payload[1] = PROP_CORRELATION_DATA; + payload[2] = 0x00; + payload[3] = 0x05; + payload[4] = 1; + payload[5] = 'e'; + payload[6] = 0; + payload[7] = 'l'; + payload[8] = 9; + + binary_prop_read_helper(payload, 9, MOSQ_ERR_SUCCESS, PROP_CORRELATION_DATA, &payload[4], 5); +} + +static void TEST_single_authentication_data(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 8; + payload[1] = PROP_AUTHENTICATION_DATA; + payload[2] = 0x00; + payload[3] = 0x05; + payload[4] = 1; + payload[5] = 'e'; + payload[6] = 0; + payload[7] = 'l'; + payload[8] = 9; + + binary_prop_read_helper(payload, 9, MOSQ_ERR_SUCCESS, PROP_AUTHENTICATION_DATA, &payload[4], 5); +} + /* ======================================================================== * DUPLICATE PROPERTIES * ======================================================================== */ @@ -750,6 +849,16 @@ static void TEST_duplicate_reason_string(void) duplicate_string_helper(PROP_REASON_STRING); } +static void TEST_duplicate_correlation_data(void) +{ + duplicate_binary_helper(PROP_CORRELATION_DATA); +} + +static void TEST_duplicate_authentication_data(void) +{ + duplicate_binary_helper(PROP_AUTHENTICATION_DATA); +} + /* ======================================================================== * BAD PROPERTY VALUES * ======================================================================== */ @@ -830,6 +939,11 @@ static void TEST_bad_topic_alias(void) int32_prop_read_helper(payload, 4, MOSQ_ERR_PROTOCOL, PROP_TOPIC_ALIAS, 0); } +static void TEST_bad_content_type(void) +{ + bad_string_helper(PROP_CONTENT_TYPE); +} + /* ======================================================================== * TEST SUITE SETUP * ======================================================================== */ @@ -871,6 +985,8 @@ int init_property_read_tests(void) || !CU_add_test(test_suite, "Single Response Information", TEST_single_response_information) || !CU_add_test(test_suite, "Single Server Reference", TEST_single_server_reference) || !CU_add_test(test_suite, "Single Reason String", TEST_single_reason_string) + || !CU_add_test(test_suite, "Single Correlation Data", TEST_single_correlation_data) + || !CU_add_test(test_suite, "Single Authentication Data", TEST_single_authentication_data) || !CU_add_test(test_suite, "Duplicate Payload Format Indicator", TEST_duplicate_payload_format_indicator) || !CU_add_test(test_suite, "Duplicate Request Problem Information", TEST_duplicate_request_problem_information) || !CU_add_test(test_suite, "Duplicate Request Response Information", TEST_duplicate_request_response_information) @@ -894,6 +1010,8 @@ int init_property_read_tests(void) || !CU_add_test(test_suite, "Duplicate Response Information", TEST_duplicate_response_information) || !CU_add_test(test_suite, "Duplicate Server Reference", TEST_duplicate_server_reference) || !CU_add_test(test_suite, "Duplicate Reason String", TEST_duplicate_reason_string) + || !CU_add_test(test_suite, "Duplicate Correlation Data", TEST_duplicate_correlation_data) + || !CU_add_test(test_suite, "Duplicate Authentication Data", TEST_duplicate_authentication_data) || !CU_add_test(test_suite, "Bad Request Problem Information", TEST_bad_request_problem_information) || !CU_add_test(test_suite, "Bad Request Response Information", TEST_bad_request_response_information) || !CU_add_test(test_suite, "Bad Maximum QoS", TEST_bad_maximum_qos) @@ -904,6 +1022,7 @@ int init_property_read_tests(void) || !CU_add_test(test_suite, "Bad Maximum Packet Size", TEST_bad_maximum_packet_size) || !CU_add_test(test_suite, "Bad Receive Maximum", TEST_bad_receive_maximum) || !CU_add_test(test_suite, "Bad Topic Alias", TEST_bad_topic_alias) + || !CU_add_test(test_suite, "Bad Content Type", TEST_bad_content_type) ){ printf("Error adding Property read CUnit tests.\n"); From abb3fee1f864f55c1cde431d55006947d4fcb247 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sat, 6 Oct 2018 21:56:48 +0100 Subject: [PATCH 042/254] Coverage reporting for whole broker. --- Makefile | 3 +++ client/Makefile | 2 +- lib/Makefile | 2 +- src/Makefile | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index c2c2bcf8e4..9a9f556245 100644 --- a/Makefile +++ b/Makefile @@ -81,3 +81,6 @@ copy : sign cd dist; scp *.html mosquitto:site/mosquitto.org/man/ scp ChangeLog.txt mosquitto:site/mosquitto.org/ +coverage : + lcov --capture --directory . --output-file coverage.info + genhtml coverage.info --output-directory out diff --git a/client/Makefile b/client/Makefile index 844bc6e0c2..02ac608726 100644 --- a/client/Makefile +++ b/client/Makefile @@ -50,4 +50,4 @@ uninstall : reallyclean : clean clean : - -rm -f *.o mosquitto_pub mosquitto_sub + -rm -f *.o mosquitto_pub mosquitto_sub *.gcda *.gcno diff --git a/lib/Makefile b/lib/Makefile index b4b4e4d5a8..d9304c32bf 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -72,7 +72,7 @@ uninstall : reallyclean : clean clean : - -rm -f *.o libmosquitto.so.${SOVERSION} libmosquitto.so libmosquitto.a + -rm -f *.o libmosquitto.so.${SOVERSION} libmosquitto.so libmosquitto.a *.gcno *.gcda $(MAKE) -C cpp clean libmosquitto.so.${SOVERSION} : ${MOSQ_OBJS} diff --git a/src/Makefile b/src/Makefile index f981e2e255..e9bf16a1c0 100644 --- a/src/Makefile +++ b/src/Makefile @@ -231,7 +231,7 @@ uninstall : -rm -f "${DESTDIR}${prefix}/bin/mosquitto_passwd" clean : - -rm -f *.o mosquitto mosquitto_passwd + -rm -f *.o mosquitto mosquitto_passwd *.gcda *.gcno reallyclean : clean -rm -rf *.orig *.db From a17dcb4e8f8cc65444dbf4813f74ef4d68c29d7e Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sun, 7 Oct 2018 00:37:38 +0100 Subject: [PATCH 043/254] Property string pair, varint and more complicated packet tests. --- test/unit/property_read.c | 735 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 735 insertions(+) diff --git a/test/unit/property_read.c b/test/unit/property_read.c index 0cfbceb34f..9022e7346c 100644 --- a/test/unit/property_read.c +++ b/test/unit/property_read.c @@ -259,6 +259,103 @@ static void duplicate_binary_helper(int identifier) string_prop_read_helper(payload, 9, MOSQ_ERR_PROTOCOL, identifier, ""); } +static void string_pair_prop_read_helper( + uint8_t *payload, + int remaining_length, + int rc_expected, + int identifier, + const char *name_expected, + const char *value_expected, + bool expect_multiple) +{ + struct mosquitto__packet packet; + struct mqtt5__property *properties; + int rc; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.payload = payload; + packet.remaining_length = remaining_length; + rc = property__read_all(&packet, &properties); + + CU_ASSERT_EQUAL(rc, rc_expected); + CU_ASSERT_EQUAL(packet.pos, remaining_length); + if(properties){ + CU_ASSERT_EQUAL(properties->identifier, identifier); + CU_ASSERT_EQUAL(properties->name.len, strlen(name_expected)); + CU_ASSERT_EQUAL(properties->value.s.len, strlen(value_expected)); + CU_ASSERT_STRING_EQUAL(properties->name.v, name_expected); + CU_ASSERT_STRING_EQUAL(properties->value.s.v, value_expected); + if(expect_multiple){ + CU_ASSERT_PTR_NOT_NULL(properties->next); + }else{ + CU_ASSERT_PTR_NULL(properties->next); + } + property__free_all(&properties); + } + CU_ASSERT_PTR_NULL(properties); +} + +static void varint_prop_read_helper( + uint8_t *payload, + int remaining_length, + int rc_expected, + int identifier, + uint32_t value_expected) +{ + struct mosquitto__packet packet; + struct mqtt5__property *properties; + int rc; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.payload = payload; + packet.remaining_length = remaining_length; + rc = property__read_all(&packet, &properties); + + CU_ASSERT_EQUAL(rc, rc_expected); + if(properties){ + CU_ASSERT_EQUAL(properties->identifier, identifier); + CU_ASSERT_EQUAL(properties->value.varint, value_expected); + CU_ASSERT_PTR_NULL(properties->next); + property__free_all(&properties); + } + CU_ASSERT_PTR_NULL(properties); +} + +void packet_helper_reason_string_user_property(void) +{ + uint8_t payload[24] = {23, + PROP_REASON_STRING, 0, 6, 'r', 'e', 'a', 's', 'o', 'n', + PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e'}; + + struct mosquitto__packet packet; + struct mqtt5__property *properties, *p; + int rc; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.payload = payload; + packet.remaining_length = sizeof(payload);; + rc = property__read_all(&packet, &properties); + + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(properties->next); + p = properties; + + CU_ASSERT_EQUAL(p->identifier, PROP_REASON_STRING); + CU_ASSERT_STRING_EQUAL(p->value.s.v, "reason"); + CU_ASSERT_EQUAL(p->value.s.len, strlen("reason")); + + p = p->next; + CU_ASSERT_PTR_NULL(p->next); + + CU_ASSERT_EQUAL(p->identifier, PROP_USER_PROPERTY); + CU_ASSERT_STRING_EQUAL(p->value.s.v, "value"); + CU_ASSERT_EQUAL(p->value.s.len, strlen("value")); + CU_ASSERT_STRING_EQUAL(p->name.v, "name"); + CU_ASSERT_EQUAL(p->name.len, strlen("name")); + + property__free_all(&properties); +} + /* ======================================================================== * NO PROPERTIES * ======================================================================== */ @@ -730,6 +827,82 @@ static void TEST_single_authentication_data(void) binary_prop_read_helper(payload, 9, MOSQ_ERR_SUCCESS, PROP_AUTHENTICATION_DATA, &payload[4], 5); } +static void TEST_single_user_property(void) +{ + uint8_t payload[20]; + + payload[0] = 9; + payload[1] = PROP_USER_PROPERTY; + payload[2] = 0; + payload[3] = 2; + payload[4] = 'z'; + payload[5] = 'a'; + payload[6] = 0; + payload[7] = 2; + payload[8] = 'b'; + payload[9] = 'c'; + + string_pair_prop_read_helper(payload, 10, MOSQ_ERR_SUCCESS, PROP_USER_PROPERTY, "za", "bc", false); +} + +static void TEST_single_subscription_identifier(void) +{ + uint8_t payload[20]; + + payload[0] = 2; + payload[1] = PROP_SUBSCRIPTION_IDENTIFIER; + payload[2] = 0; + varint_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 0); + + payload[0] = 2; + payload[1] = PROP_SUBSCRIPTION_IDENTIFIER; + payload[2] = 0x7F; + varint_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 127); + + payload[0] = 3; + payload[1] = PROP_SUBSCRIPTION_IDENTIFIER; + payload[2] = 0x80; + payload[3] = 0x01; + varint_prop_read_helper(payload, 4, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 128); + + payload[0] = 3; + payload[1] = PROP_SUBSCRIPTION_IDENTIFIER; + payload[2] = 0xFF; + payload[3] = 0x7F; + varint_prop_read_helper(payload, 4, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 16383); + + payload[0] = 4; + payload[1] = PROP_SUBSCRIPTION_IDENTIFIER; + payload[2] = 0x80; + payload[3] = 0x80; + payload[4] = 0x01; + varint_prop_read_helper(payload, 5, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 16384); + + payload[0] = 4; + payload[1] = PROP_SUBSCRIPTION_IDENTIFIER; + payload[2] = 0xFF; + payload[3] = 0xFF; + payload[4] = 0x7F; + varint_prop_read_helper(payload, 5, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 2097151); + + payload[0] = 5; + payload[1] = PROP_SUBSCRIPTION_IDENTIFIER; + payload[2] = 0x80; + payload[3] = 0x80; + payload[4] = 0x80; + payload[5] = 0x01; + varint_prop_read_helper(payload, 6, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 2097152); + + + payload[0] = 5; + payload[1] = PROP_SUBSCRIPTION_IDENTIFIER; + payload[2] = 0xFF; + payload[3] = 0xFF; + payload[4] = 0xFF; + payload[5] = 0x7F; + varint_prop_read_helper(payload, 6, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 268435455); +} + /* ======================================================================== * DUPLICATE PROPERTIES * ======================================================================== */ @@ -859,6 +1032,49 @@ static void TEST_duplicate_authentication_data(void) duplicate_binary_helper(PROP_AUTHENTICATION_DATA); } +static void TEST_duplicate_user_property(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 18; /* Proplen = (Identifier + byte)*2 */ + payload[1] = PROP_USER_PROPERTY; + payload[2] = 0; + payload[3] = 2; + payload[4] = 'a'; + payload[5] = 'b'; + payload[6] = 0; + payload[7] = 2; + payload[8] = 'g'; + payload[9] = 'h'; + payload[10] = PROP_USER_PROPERTY; + payload[11] = 0; + payload[12] = 2; + payload[13] = 'c'; + payload[14] = 'd'; + payload[15] = 0; + payload[16] = 2; + payload[17] = 'e'; + payload[18] = 'f'; + + string_pair_prop_read_helper(payload, 19, MOSQ_ERR_SUCCESS, PROP_USER_PROPERTY, "ab", "gh", true); +} + +static void TEST_duplicate_subscription_identifier(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 4; /* Proplen = (Identifier + byte)*2 */ + payload[1] = PROP_SUBSCRIPTION_IDENTIFIER; + payload[2] = 0x80; + payload[3] = 0x02; + payload[4] = PROP_SUBSCRIPTION_IDENTIFIER; + payload[5] = 0x04; + + varint_prop_read_helper(payload, 5, MOSQ_ERR_PROTOCOL, PROP_SUBSCRIPTION_IDENTIFIER, 0); +} + /* ======================================================================== * BAD PROPERTY VALUES * ======================================================================== */ @@ -944,6 +1160,507 @@ static void TEST_bad_content_type(void) bad_string_helper(PROP_CONTENT_TYPE); } +static void TEST_bad_subscription_identifier(void) +{ + uint8_t payload[20]; + + memset(&payload, 0, sizeof(payload)); + payload[0] = 6; + payload[1] = PROP_SUBSCRIPTION_IDENTIFIER; + payload[2] = 0xFF; + payload[3] = 0xFF; + payload[4] = 0xFF; + payload[5] = 0xFF; + payload[6] = 0x01; + + varint_prop_read_helper(payload, 7, MOSQ_ERR_PROTOCOL, PROP_SUBSCRIPTION_IDENTIFIER, 0); +} + +/* ======================================================================== + * CONTROL PACKET TESTS + * ======================================================================== */ + +static void TEST_packet_connect(void) +{ + uint8_t payload[] = {0, + PROP_SESSION_EXPIRY_INTERVAL, 0x12, 0x45, 0x00, 0x00, + PROP_RECEIVE_MAXIMUM, 0x00, 0x05, + PROP_MAXIMUM_PACKET_SIZE, 0x12, 0x45, 0x00, 0x00, + PROP_TOPIC_ALIAS_MAXIMUM, 0x00, 0x02, + PROP_REQUEST_PROBLEM_INFO, 1, + PROP_REQUEST_RESPONSE_INFO, 1, + PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e', + PROP_AUTHENTICATION_METHOD, 0x00, 0x04, 'n', 'o', 'n', 'e', + PROP_AUTHENTICATION_DATA, 0x00, 0x02, 1, 2}; + + struct mosquitto__packet packet; + struct mqtt5__property *properties, *p; + int rc; + + payload[0] = sizeof(payload)-1; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.payload = payload; + packet.remaining_length = sizeof(payload);; + rc = property__read_all(&packet, &properties); + + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(properties->next); + p = properties; + + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_SESSION_EXPIRY_INTERVAL); + CU_ASSERT_EQUAL(p->value.i32, 0x12450000); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_RECEIVE_MAXIMUM); + CU_ASSERT_EQUAL(p->value.i16, 0x0005); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_MAXIMUM_PACKET_SIZE); + CU_ASSERT_EQUAL(p->value.i32, 0x12450000); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_TOPIC_ALIAS_MAXIMUM); + CU_ASSERT_EQUAL(p->value.i16, 0x0002); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_REQUEST_PROBLEM_INFO); + CU_ASSERT_EQUAL(p->value.i8, 1); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_REQUEST_RESPONSE_INFO); + CU_ASSERT_EQUAL(p->value.i8, 1); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_USER_PROPERTY); + CU_ASSERT_STRING_EQUAL(p->value.s.v, "value"); + CU_ASSERT_EQUAL(p->value.s.len, strlen("value")); + CU_ASSERT_STRING_EQUAL(p->name.v, "name"); + CU_ASSERT_EQUAL(p->name.len, strlen("name")); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_AUTHENTICATION_METHOD); + CU_ASSERT_STRING_EQUAL(p->value.s.v, "none"); + CU_ASSERT_EQUAL(p->value.s.len, strlen("none")); + + p = p->next; + CU_ASSERT_PTR_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_AUTHENTICATION_DATA); + CU_ASSERT_EQUAL(p->value.bin.v[0], 1); + CU_ASSERT_EQUAL(p->value.bin.v[1], 2); + CU_ASSERT_EQUAL(p->value.s.len, 2); + + property__free_all(&properties); +} + +static void TEST_packet_connack(void) +{ + uint8_t payload[] = {0, + PROP_SESSION_EXPIRY_INTERVAL, 0x12, 0x45, 0x00, 0x00, + PROP_RECEIVE_MAXIMUM, 0x00, 0x05, + PROP_MAXIMUM_QOS, 1, + PROP_RETAIN_AVAILABLE, 0, + PROP_MAXIMUM_PACKET_SIZE, 0x12, 0x45, 0x00, 0x00, + PROP_ASSIGNED_CLIENT_IDENTIFIER, 0x00, 0x02, 'a', 'b', + PROP_TOPIC_ALIAS_MAXIMUM, 0x00, 0x02, + PROP_REASON_STRING, 0, 6, 'r', 'e', 'a', 's', 'o', 'n', + PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e', + PROP_WILDCARD_SUB_AVAILABLE, 0, + PROP_SUBSCRIPTION_ID_AVAILABLE, 0, + PROP_SHARED_SUB_AVAILABLE, 0, + PROP_SERVER_KEEP_ALIVE, 0x00, 0xFF, + PROP_RESPONSE_INFO, 0x00, 0x03, 'r', 's', 'p', + PROP_SERVER_REFERENCE, 0x00, 0x04, 's', 'e', 'r', 'v', + PROP_AUTHENTICATION_METHOD, 0x00, 0x04, 'n', 'o', 'n', 'e', + PROP_AUTHENTICATION_DATA, 0x00, 0x02, 1, 2}; + + struct mosquitto__packet packet; + struct mqtt5__property *properties, *p; + int rc; + + payload[0] = sizeof(payload)-1; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.payload = payload; + packet.remaining_length = sizeof(payload);; + rc = property__read_all(&packet, &properties); + + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(properties->next); + p = properties; + + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_SESSION_EXPIRY_INTERVAL); + CU_ASSERT_EQUAL(p->value.i32, 0x12450000); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_RECEIVE_MAXIMUM); + CU_ASSERT_EQUAL(p->value.i16, 0x0005); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_MAXIMUM_QOS); + CU_ASSERT_EQUAL(p->value.i8, 1); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_RETAIN_AVAILABLE); + CU_ASSERT_EQUAL(p->value.i8, 0); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_MAXIMUM_PACKET_SIZE); + CU_ASSERT_EQUAL(p->value.i32, 0x12450000); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_ASSIGNED_CLIENT_IDENTIFIER); + CU_ASSERT_STRING_EQUAL(p->value.s.v, "ab"); + CU_ASSERT_EQUAL(p->value.s.len, strlen("ab")); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_TOPIC_ALIAS_MAXIMUM); + CU_ASSERT_EQUAL(p->value.i16, 0x0002); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_REASON_STRING); + CU_ASSERT_STRING_EQUAL(p->value.s.v, "reason"); + CU_ASSERT_EQUAL(p->value.s.len, strlen("reason")); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_USER_PROPERTY); + CU_ASSERT_STRING_EQUAL(p->value.s.v, "value"); + CU_ASSERT_EQUAL(p->value.s.len, strlen("value")); + CU_ASSERT_STRING_EQUAL(p->name.v, "name"); + CU_ASSERT_EQUAL(p->name.len, strlen("name")); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_WILDCARD_SUB_AVAILABLE); + CU_ASSERT_EQUAL(p->value.i8, 0); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_SUBSCRIPTION_ID_AVAILABLE); + CU_ASSERT_EQUAL(p->value.i8, 0); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_SHARED_SUB_AVAILABLE); + CU_ASSERT_EQUAL(p->value.i8, 0); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_SERVER_KEEP_ALIVE); + CU_ASSERT_EQUAL(p->value.i16, 0x00FF); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_RESPONSE_INFO); + CU_ASSERT_STRING_EQUAL(p->value.s.v, "rsp"); + CU_ASSERT_EQUAL(p->value.s.len, strlen("rsp")); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_SERVER_REFERENCE); + CU_ASSERT_STRING_EQUAL(p->value.s.v, "serv"); + CU_ASSERT_EQUAL(p->value.s.len, strlen("serv")); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_AUTHENTICATION_METHOD); + CU_ASSERT_STRING_EQUAL(p->value.s.v, "none"); + CU_ASSERT_EQUAL(p->value.s.len, strlen("none")); + + p = p->next; + CU_ASSERT_PTR_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_AUTHENTICATION_DATA); + CU_ASSERT_EQUAL(p->value.bin.v[0], 1); + CU_ASSERT_EQUAL(p->value.bin.v[1], 2); + CU_ASSERT_EQUAL(p->value.s.len, 2); + + property__free_all(&properties); +} + +static void TEST_packet_publish(void) +{ + uint8_t payload[] = {0, + PROP_PAYLOAD_FORMAT_INDICATOR, 1, + PROP_MESSAGE_EXPIRY_INTERVAL, 0x12, 0x45, 0x00, 0x00, + PROP_TOPIC_ALIAS, 0x00, 0x02, + PROP_RESPONSE_TOPIC, 0, 6, 'r', 'e', 's', 'p', 'o', 'n', + PROP_CORRELATION_DATA, 0x00, 0x02, 1, 2, + PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e', + PROP_SUBSCRIPTION_IDENTIFIER, 0x04, + PROP_CONTENT_TYPE, 0, 5, 'e', 'm', 'p', 't', 'y'}; + + struct mosquitto__packet packet; + struct mqtt5__property *properties, *p; + int rc; + + payload[0] = sizeof(payload)-1; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.payload = payload; + packet.remaining_length = sizeof(payload);; + rc = property__read_all(&packet, &properties); + + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(properties->next); + p = properties; + + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_PAYLOAD_FORMAT_INDICATOR); + CU_ASSERT_EQUAL(p->value.i8, 1); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_MESSAGE_EXPIRY_INTERVAL); + CU_ASSERT_EQUAL(p->value.i32, 0x12450000); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_TOPIC_ALIAS); + CU_ASSERT_EQUAL(p->value.i16, 0x0002); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_RESPONSE_TOPIC); + CU_ASSERT_STRING_EQUAL(p->value.s.v, "respon"); + CU_ASSERT_EQUAL(p->value.s.len, strlen("respon")); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_CORRELATION_DATA); + CU_ASSERT_EQUAL(p->value.bin.v[0], 1); + CU_ASSERT_EQUAL(p->value.bin.v[1], 2); + CU_ASSERT_EQUAL(p->value.bin.len, 2); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_USER_PROPERTY); + CU_ASSERT_STRING_EQUAL(p->value.s.v, "value"); + CU_ASSERT_EQUAL(p->value.s.len, strlen("value")); + CU_ASSERT_STRING_EQUAL(p->name.v, "name"); + CU_ASSERT_EQUAL(p->name.len, strlen("name")); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_SUBSCRIPTION_IDENTIFIER); + CU_ASSERT_EQUAL(p->value.varint, 0x00000004); + + p = p->next; + CU_ASSERT_PTR_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_CONTENT_TYPE); + CU_ASSERT_STRING_EQUAL(p->value.s.v, "empty"); + CU_ASSERT_EQUAL(p->value.s.len, strlen("empty")); + + property__free_all(&properties); +} + +static void TEST_packet_puback(void) +{ + packet_helper_reason_string_user_property(); +} + +static void TEST_packet_pubrec(void) +{ + packet_helper_reason_string_user_property(); +} + +static void TEST_packet_pubrel(void) +{ + packet_helper_reason_string_user_property(); +} + +static void TEST_packet_pubcomp(void) +{ + packet_helper_reason_string_user_property(); +} + +static void TEST_packet_subscribe(void) +{ + uint8_t payload[] = {0, + PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e', + PROP_SUBSCRIPTION_IDENTIFIER, 0x04}; + + struct mosquitto__packet packet; + struct mqtt5__property *properties, *p; + int rc; + + payload[0] = sizeof(payload)-1; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.payload = payload; + packet.remaining_length = sizeof(payload);; + rc = property__read_all(&packet, &properties); + + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(properties->next); + p = properties; + + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_USER_PROPERTY); + CU_ASSERT_STRING_EQUAL(p->value.s.v, "value"); + CU_ASSERT_EQUAL(p->value.s.len, strlen("value")); + CU_ASSERT_STRING_EQUAL(p->name.v, "name"); + CU_ASSERT_EQUAL(p->name.len, strlen("name")); + + p = p->next; + CU_ASSERT_PTR_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_SUBSCRIPTION_IDENTIFIER); + CU_ASSERT_EQUAL(p->value.varint, 0x00000004); + + property__free_all(&properties); +} + +static void TEST_packet_suback(void) +{ + packet_helper_reason_string_user_property(); +} + +static void TEST_packet_unsubscribe(void) +{ + uint8_t payload[] = {0, + PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e'}; + + struct mosquitto__packet packet; + struct mqtt5__property *properties, *p; + int rc; + + payload[0] = sizeof(payload)-1; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.payload = payload; + packet.remaining_length = sizeof(payload);; + rc = property__read_all(&packet, &properties); + + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + p = properties; + + CU_ASSERT_PTR_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_USER_PROPERTY); + CU_ASSERT_STRING_EQUAL(p->value.s.v, "value"); + CU_ASSERT_EQUAL(p->value.s.len, strlen("value")); + CU_ASSERT_STRING_EQUAL(p->name.v, "name"); + CU_ASSERT_EQUAL(p->name.len, strlen("name")); + + property__free_all(&properties); +} + +static void TEST_packet_unsuback(void) +{ + packet_helper_reason_string_user_property(); +} + +static void TEST_packet_disconnect(void) +{ + uint8_t payload[] = {0, + PROP_SESSION_EXPIRY_INTERVAL, 0x12, 0x45, 0x00, 0x00, + PROP_REASON_STRING, 0, 6, 'r', 'e', 'a', 's', 'o', 'n', + PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e'}; + + struct mosquitto__packet packet; + struct mqtt5__property *properties, *p; + int rc; + + payload[0] = sizeof(payload)-1; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.payload = payload; + packet.remaining_length = sizeof(payload);; + rc = property__read_all(&packet, &properties); + + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(properties->next); + p = properties; + + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_SESSION_EXPIRY_INTERVAL); + CU_ASSERT_EQUAL(p->value.i32, 0x12450000); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_REASON_STRING); + CU_ASSERT_STRING_EQUAL(p->value.s.v, "reason"); + CU_ASSERT_EQUAL(p->value.s.len, strlen("reason")); + + p = p->next; + CU_ASSERT_PTR_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_USER_PROPERTY); + CU_ASSERT_STRING_EQUAL(p->value.s.v, "value"); + CU_ASSERT_EQUAL(p->value.s.len, strlen("value")); + CU_ASSERT_STRING_EQUAL(p->name.v, "name"); + CU_ASSERT_EQUAL(p->name.len, strlen("name")); + + property__free_all(&properties); +} + +static void TEST_packet_auth(void) +{ + uint8_t payload[] = {0, + PROP_AUTHENTICATION_METHOD, 0x00, 0x04, 'n', 'o', 'n', 'e', + PROP_AUTHENTICATION_DATA, 0x00, 0x02, 1, 2, + PROP_REASON_STRING, 0, 6, 'r', 'e', 'a', 's', 'o', 'n', + PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e'}; + + struct mosquitto__packet packet; + struct mqtt5__property *properties, *p; + int rc; + + payload[0] = sizeof(payload)-1; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.payload = payload; + packet.remaining_length = sizeof(payload);; + rc = property__read_all(&packet, &properties); + + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(properties->next); + p = properties; + + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_AUTHENTICATION_METHOD); + CU_ASSERT_STRING_EQUAL(p->value.s.v, "none"); + CU_ASSERT_EQUAL(p->value.s.len, strlen("none")); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_AUTHENTICATION_DATA); + CU_ASSERT_EQUAL(p->value.bin.v[0], 1); + CU_ASSERT_EQUAL(p->value.bin.v[1], 2); + CU_ASSERT_EQUAL(p->value.s.len, 2); + + p = p->next; + CU_ASSERT_PTR_NOT_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_REASON_STRING); + CU_ASSERT_STRING_EQUAL(p->value.s.v, "reason"); + CU_ASSERT_EQUAL(p->value.s.len, strlen("reason")); + + p = p->next; + CU_ASSERT_PTR_NULL(p->next); + CU_ASSERT_EQUAL(p->identifier, PROP_USER_PROPERTY); + CU_ASSERT_STRING_EQUAL(p->value.s.v, "value"); + CU_ASSERT_EQUAL(p->value.s.len, strlen("value")); + CU_ASSERT_STRING_EQUAL(p->name.v, "name"); + CU_ASSERT_EQUAL(p->name.len, strlen("name")); + + property__free_all(&properties); +} + + /* ======================================================================== * TEST SUITE SETUP * ======================================================================== */ @@ -987,6 +1704,8 @@ int init_property_read_tests(void) || !CU_add_test(test_suite, "Single Reason String", TEST_single_reason_string) || !CU_add_test(test_suite, "Single Correlation Data", TEST_single_correlation_data) || !CU_add_test(test_suite, "Single Authentication Data", TEST_single_authentication_data) + || !CU_add_test(test_suite, "Single User Property", TEST_single_user_property) + || !CU_add_test(test_suite, "Single Subscription Identifier", TEST_single_subscription_identifier) || !CU_add_test(test_suite, "Duplicate Payload Format Indicator", TEST_duplicate_payload_format_indicator) || !CU_add_test(test_suite, "Duplicate Request Problem Information", TEST_duplicate_request_problem_information) || !CU_add_test(test_suite, "Duplicate Request Response Information", TEST_duplicate_request_response_information) @@ -1012,6 +1731,8 @@ int init_property_read_tests(void) || !CU_add_test(test_suite, "Duplicate Reason String", TEST_duplicate_reason_string) || !CU_add_test(test_suite, "Duplicate Correlation Data", TEST_duplicate_correlation_data) || !CU_add_test(test_suite, "Duplicate Authentication Data", TEST_duplicate_authentication_data) + || !CU_add_test(test_suite, "Duplicate User Property", TEST_duplicate_user_property) + || !CU_add_test(test_suite, "Duplicate Subscription Identifier", TEST_duplicate_subscription_identifier) || !CU_add_test(test_suite, "Bad Request Problem Information", TEST_bad_request_problem_information) || !CU_add_test(test_suite, "Bad Request Response Information", TEST_bad_request_response_information) || !CU_add_test(test_suite, "Bad Maximum QoS", TEST_bad_maximum_qos) @@ -1023,6 +1744,20 @@ int init_property_read_tests(void) || !CU_add_test(test_suite, "Bad Receive Maximum", TEST_bad_receive_maximum) || !CU_add_test(test_suite, "Bad Topic Alias", TEST_bad_topic_alias) || !CU_add_test(test_suite, "Bad Content Type", TEST_bad_content_type) + || !CU_add_test(test_suite, "Bad Subscription Identifier", TEST_bad_subscription_identifier) + || !CU_add_test(test_suite, "Packet CONNECT", TEST_packet_connect) + || !CU_add_test(test_suite, "Packet CONNACK", TEST_packet_connack) + || !CU_add_test(test_suite, "Packet PUBLISH", TEST_packet_publish) + || !CU_add_test(test_suite, "Packet PUBACK", TEST_packet_puback) + || !CU_add_test(test_suite, "Packet PUBREC", TEST_packet_pubrec) + || !CU_add_test(test_suite, "Packet PUBREL", TEST_packet_pubrel) + || !CU_add_test(test_suite, "Packet PUBCOMP", TEST_packet_pubcomp) + || !CU_add_test(test_suite, "Packet SUBSCRIBE", TEST_packet_subscribe) + || !CU_add_test(test_suite, "Packet SUBACK", TEST_packet_suback) + || !CU_add_test(test_suite, "Packet UNSUBSCRIBE", TEST_packet_unsubscribe) + || !CU_add_test(test_suite, "Packet UNSUBACK", TEST_packet_unsuback) + || !CU_add_test(test_suite, "Packet DISCONNECT", TEST_packet_disconnect) + || !CU_add_test(test_suite, "Packet AUTH", TEST_packet_auth) ){ printf("Error adding Property read CUnit tests.\n"); From 246c9e65656207785c73090ddb9cff860f3bb29b Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 10 Oct 2018 08:41:10 +0100 Subject: [PATCH 044/254] Read will properties, and free properties immediately for the moment. --- src/handle_connect.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/handle_connect.c b/src/handle_connect.c index 5b3e0b47fb..d9b489a8d8 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -246,6 +246,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) if(rc) return rc; property__free_all(&properties); } + property__free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ if(packet__read_string(&context->in_packet, &client_id, &slen)){ rc = 1; @@ -300,6 +301,13 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) rc = MOSQ_ERR_NOMEM; goto handle_connect_error; } + /* FIXME - this needs to be "will" specific */ + if(protocol_version == PROTOCOL_VERSION_v5){ + rc = property__read_all(&context->in_packet, &properties); + if(rc) return rc; + property__free_all(&properties); + } + property__free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ if(packet__read_string(&context->in_packet, &will_topic, &slen)){ rc = 1; goto handle_connect_error; From 8210c1fa7ac1965d010683d8f8789da3742ce201 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 10 Oct 2018 12:42:27 +0100 Subject: [PATCH 045/254] All outgoing packets now write property length for MQTT 5. At the moment this only writes a 0 property length, i.e. no properties. It does mean that output packets are more correct than before. --- lib/property_mosq.c | 8 ++++++++ lib/property_mosq.h | 1 + lib/send_connect.c | 10 +++++++++- lib/send_disconnect.c | 28 +++++++++++++++++++++++++++- lib/send_mosq.c | 22 +++++++++++++++------- lib/send_mosq.h | 3 ++- lib/send_publish.c | 8 ++++++++ lib/send_subscribe.c | 8 ++++++++ lib/send_unsubscribe.c | 8 ++++++++ src/handle_connect.c | 2 +- src/handle_unsubscribe.c | 2 +- src/send_connack.c | 7 ++++--- src/send_suback.c | 9 +++++++++ 13 files changed, 101 insertions(+), 15 deletions(-) diff --git a/lib/property_mosq.c b/lib/property_mosq.c index 26baa4b188..f41fb3da1c 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -279,3 +279,11 @@ void property__free_all(struct mqtt5__property **property) } *property = NULL; } + + +int property__write_all(struct mosquitto__packet *packet, struct mqtt5__property **property) +{ + packet__write_byte(packet, 0); + return MOSQ_ERR_SUCCESS; +} + diff --git a/lib/property_mosq.h b/lib/property_mosq.h index 6ce67d834a..27301eacf1 100644 --- a/lib/property_mosq.h +++ b/lib/property_mosq.h @@ -40,6 +40,7 @@ struct mqtt5__property { int property__read_all(struct mosquitto__packet *packet, struct mqtt5__property **property); +int property__write_all(struct mosquitto__packet *packet, struct mqtt5__property **property); void property__free(struct mqtt5__property **property); void property__free_all(struct mqtt5__property **property); diff --git a/lib/send_connect.c b/lib/send_connect.c index 2295e9b024..5f6b380645 100644 --- a/lib/send_connect.c +++ b/lib/send_connect.c @@ -29,6 +29,7 @@ and the Eclipse Distribution License is available at #include "mosquitto_internal.h" #include "mqtt_protocol.h" #include "packet_mosq.h" +#include "property_mosq.h" int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session) { @@ -82,6 +83,9 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session assert(mosq->will->topic); payloadlen += 2+strlen(mosq->will->topic) + 2+mosq->will->payloadlen; + if(mosq->protocol == mosq_p_mqtt5){ + payloadlen += 1; + } } if(username){ payloadlen += 2+strlen(username); @@ -126,12 +130,16 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session if(mosq->protocol == mosq_p_mqtt5){ /* Write properties */ - packet__write_byte(packet, 0); /* FIXME - No properties yet. */ + property__write_all(packet, NULL); } /* Payload */ packet__write_string(packet, clientid, strlen(clientid)); if(will){ + if(mosq->protocol == mosq_p_mqtt5){ + /* Write will properties */ + property__write_all(packet, NULL); + } packet__write_string(packet, mosq->will->topic, strlen(mosq->will->topic)); packet__write_string(packet, (const char *)mosq->will->payload, mosq->will->payloadlen); } diff --git a/lib/send_disconnect.c b/lib/send_disconnect.c index e5009d696f..18c5b92437 100644 --- a/lib/send_disconnect.c +++ b/lib/send_disconnect.c @@ -25,12 +25,18 @@ and the Eclipse Distribution License is available at #include "mosquitto.h" #include "mosquitto_internal.h" #include "logging_mosq.h" +#include "memory_mosq.h" #include "mqtt_protocol.h" +#include "packet_mosq.h" +#include "property_mosq.h" #include "send_mosq.h" int send__disconnect(struct mosquitto *mosq) { + struct mosquitto__packet *packet = NULL; + int rc; + assert(mosq); #ifdef WITH_BROKER # ifdef WITH_BRIDGE @@ -39,6 +45,26 @@ int send__disconnect(struct mosquitto *mosq) #else log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending DISCONNECT", mosq->id); #endif - return send__simple_command(mosq, DISCONNECT); + assert(mosq); + packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet)); + if(!packet) return MOSQ_ERR_NOMEM; + + packet->command = DISCONNECT; + if(mosq->protocol == mosq_p_mqtt5){ + packet->remaining_length = 1; + }else{ + packet->remaining_length = 0; + } + + rc = packet__alloc(packet); + if(rc){ + mosquitto__free(packet); + return rc; + } + if(mosq->protocol == mosq_p_mqtt5){ + property__write_all(packet, NULL); + } + + return packet__queue(mosq, packet); } diff --git a/lib/send_mosq.c b/lib/send_mosq.c index 3c58d724f6..ca01c0108e 100644 --- a/lib/send_mosq.c +++ b/lib/send_mosq.c @@ -34,6 +34,7 @@ and the Eclipse Distribution License is available at #include "memory_mosq.h" #include "net_mosq.h" #include "packet_mosq.h" +#include "property_mosq.h" #include "send_mosq.h" #include "time_mosq.h" #include "util_mosq.h" @@ -71,7 +72,7 @@ int send__puback(struct mosquitto *mosq, uint16_t mid) #else if(mosq) log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBACK (Mid: %d)", mosq->id, mid); #endif - return send__command_with_mid(mosq, PUBACK, mid, false); + return send__command_with_mid(mosq, PUBACK, mid, false, NULL); } int send__pubcomp(struct mosquitto *mosq, uint16_t mid) @@ -81,7 +82,7 @@ int send__pubcomp(struct mosquitto *mosq, uint16_t mid) #else if(mosq) log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBCOMP (Mid: %d)", mosq->id, mid); #endif - return send__command_with_mid(mosq, PUBCOMP, mid, false); + return send__command_with_mid(mosq, PUBCOMP, mid, false, NULL); } @@ -92,7 +93,7 @@ int send__pubrec(struct mosquitto *mosq, uint16_t mid) #else if(mosq) log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBREC (Mid: %d)", mosq->id, mid); #endif - return send__command_with_mid(mosq, PUBREC, mid, false); + return send__command_with_mid(mosq, PUBREC, mid, false, NULL); } int send__pubrel(struct mosquitto *mosq, uint16_t mid) @@ -102,11 +103,11 @@ int send__pubrel(struct mosquitto *mosq, uint16_t mid) #else if(mosq) log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBREL (Mid: %d)", mosq->id, mid); #endif - return send__command_with_mid(mosq, PUBREL|2, mid, false); + return send__command_with_mid(mosq, PUBREL|2, mid, false, NULL); } /* For PUBACK, PUBCOMP, PUBREC, and PUBREL */ -int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup) +int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup, struct mqtt5__property *properties) { struct mosquitto__packet *packet = NULL; int rc; @@ -120,14 +121,21 @@ int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid packet->command |= 8; } packet->remaining_length = 2; + if(mosq->protocol == mosq_p_mqtt5){ + packet->remaining_length += 1; + } + rc = packet__alloc(packet); if(rc){ mosquitto__free(packet); return rc; } - packet->payload[packet->pos+0] = MOSQ_MSB(mid); - packet->payload[packet->pos+1] = MOSQ_LSB(mid); + packet__write_uint16(packet, mid); + + if(mosq->protocol == mosq_p_mqtt5){ + property__write_all(packet, NULL); + } return packet__queue(mosq, packet); } diff --git a/lib/send_mosq.h b/lib/send_mosq.h index 35645952dd..1bac1d3041 100644 --- a/lib/send_mosq.h +++ b/lib/send_mosq.h @@ -17,9 +17,10 @@ and the Eclipse Distribution License is available at #define SEND_MOSQ_H #include "mosquitto.h" +#include "property_mosq.h" int send__simple_command(struct mosquitto *mosq, uint8_t command); -int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup); +int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup, struct mqtt5__property *properties); int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup); int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session); diff --git a/lib/send_publish.c b/lib/send_publish.c index 124fc85f9f..3df0909b6f 100644 --- a/lib/send_publish.c +++ b/lib/send_publish.c @@ -33,6 +33,7 @@ and the Eclipse Distribution License is available at #include "memory_mosq.h" #include "net_mosq.h" #include "packet_mosq.h" +#include "property_mosq.h" #include "send_mosq.h" @@ -139,6 +140,9 @@ int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, packetlen = 2+strlen(topic) + payloadlen; if(qos > 0) packetlen += 2; /* For message id */ + if(mosq->protocol == mosq_p_mqtt5){ + packetlen += 1; + } packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet)); if(!packet) return MOSQ_ERR_NOMEM; @@ -156,6 +160,10 @@ int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, packet__write_uint16(packet, mid); } + if(mosq->protocol == mosq_p_mqtt5){ + property__write_all(packet, NULL); + } + /* Payload */ if(payloadlen){ packet__write_bytes(packet, payload, payloadlen); diff --git a/lib/send_subscribe.c b/lib/send_subscribe.c index ec0eacabfb..8e6e5eb613 100644 --- a/lib/send_subscribe.c +++ b/lib/send_subscribe.c @@ -29,6 +29,7 @@ and the Eclipse Distribution License is available at #include "memory_mosq.h" #include "mqtt_protocol.h" #include "packet_mosq.h" +#include "property_mosq.h" #include "util_mosq.h" @@ -47,6 +48,9 @@ int send__subscribe(struct mosquitto *mosq, int *mid, int topic_count, const cha if(!packet) return MOSQ_ERR_NOMEM; packetlen = 2; + if(mosq->protocol == mosq_p_mqtt5){ + packetlen += 1; + } for(i=0; iprotocol == mosq_p_mqtt5){ + property__write_all(packet, NULL); + } + /* Payload */ for(i=0; iprotocol == mosq_p_mqtt5){ + packetlen += 1; + } packet->command = UNSUBSCRIBE | (1<<1); packet->remaining_length = packetlen; @@ -60,6 +64,10 @@ int send__unsubscribe(struct mosquitto *mosq, int *mid, const char *topic) if(mid) *mid = (int)local_mid; packet__write_uint16(packet, local_mid); + if(mosq->protocol == mosq_p_mqtt5){ + property__write_all(packet, NULL); + } + /* Payload */ packet__write_string(packet, topic, strlen(topic)); diff --git a/src/handle_connect.c b/src/handle_connect.c index d9b489a8d8..18fd59f011 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -131,7 +131,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) struct mosquitto__subleaf *leaf; int i; struct mosquitto__security_options *security_opts; - struct mqtt5__property *properties; + struct mqtt5__property *properties = NULL; #ifdef WITH_TLS X509 *client_cert = NULL; X509_NAME *name; diff --git a/src/handle_unsubscribe.c b/src/handle_unsubscribe.c index 3bb8bd4aa0..03848d8d53 100644 --- a/src/handle_unsubscribe.c +++ b/src/handle_unsubscribe.c @@ -87,6 +87,6 @@ int handle__unsubscribe(struct mosquitto_db *db, struct mosquitto *context) log__printf(NULL, MOSQ_LOG_DEBUG, "Sending UNSUBACK to %s", context->id); - return send__command_with_mid(context, UNSUBACK, mid, false); + return send__command_with_mid(context, UNSUBACK, mid, false, NULL); } diff --git a/src/send_connack.c b/src/send_connack.c index 3bb6ea7c3e..00a394719e 100644 --- a/src/send_connack.c +++ b/src/send_connack.c @@ -20,6 +20,7 @@ and the Eclipse Distribution License is available at #include "mqtt_protocol.h" #include "memory_mosq.h" #include "packet_mosq.h" +#include "property_mosq.h" #include "util_mosq.h" int send__connack(struct mosquitto *context, int ack, int result) @@ -50,10 +51,10 @@ int send__connack(struct mosquitto *context, int ack, int result) mosquitto__free(packet); return rc; } - packet->payload[packet->pos+0] = ack; - packet->payload[packet->pos+1] = result; + packet__write_byte(packet, ack); + packet__write_byte(packet, result); if(context->protocol == mosq_p_mqtt5){ - packet->payload[packet->pos+2] = 0; + property__write_all(packet, NULL); } return packet__queue(context, packet); diff --git a/src/send_suback.c b/src/send_suback.c index 7bbe72fa18..b1718872b8 100644 --- a/src/send_suback.c +++ b/src/send_suback.c @@ -20,6 +20,7 @@ and the Eclipse Distribution License is available at #include "mqtt_protocol.h" #include "memory_mosq.h" #include "packet_mosq.h" +#include "property_mosq.h" #include "util_mosq.h" @@ -35,12 +36,20 @@ int send__suback(struct mosquitto *context, uint16_t mid, uint32_t payloadlen, c packet->command = SUBACK; packet->remaining_length = 2+payloadlen; + if(context->protocol == mosq_p_mqtt5){ + packet->remaining_length += 1; + } rc = packet__alloc(packet); if(rc){ mosquitto__free(packet); return rc; } packet__write_uint16(packet, mid); + + if(context->protocol == mosq_p_mqtt5){ + property__write_all(packet, NULL); + } + if(payloadlen){ packet__write_bytes(packet, payload, payloadlen); } From c0ff42408222b7b9c27f74d652d2b48cf16a3b0a Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 10 Oct 2018 14:50:30 +0100 Subject: [PATCH 046/254] Add property__get_length_all() and property__get_length(). For getting the number of bytes needed for writing a property list. --- lib/property_mosq.c | 77 +++++++++++++++++++++++++++++++++++++++ lib/property_mosq.h | 3 ++ test/unit/property_read.c | 17 +++++++++ 3 files changed, 97 insertions(+) diff --git a/lib/property_mosq.c b/lib/property_mosq.c index f41fb3da1c..d5ce563150 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -281,6 +281,83 @@ void property__free_all(struct mqtt5__property **property) } +int property__get_length(struct mqtt5__property *property) +{ + if(!property) return 0; + + switch(property->identifier){ + case PROP_PAYLOAD_FORMAT_INDICATOR: + case PROP_REQUEST_PROBLEM_INFO: + case PROP_REQUEST_RESPONSE_INFO: + case PROP_MAXIMUM_QOS: + case PROP_RETAIN_AVAILABLE: + case PROP_WILDCARD_SUB_AVAILABLE: + case PROP_SUBSCRIPTION_ID_AVAILABLE: + case PROP_SHARED_SUB_AVAILABLE: + return 2; /* 1 (identifier) + 1 byte */ + + case PROP_SERVER_KEEP_ALIVE: + case PROP_RECEIVE_MAXIMUM: + case PROP_TOPIC_ALIAS_MAXIMUM: + case PROP_TOPIC_ALIAS: + return 3; /* 1 (identifier) + 2 bytes */ + + case PROP_MESSAGE_EXPIRY_INTERVAL: + case PROP_WILL_DELAY_INTERVAL: + case PROP_MAXIMUM_PACKET_SIZE: + case PROP_SESSION_EXPIRY_INTERVAL: + return 5; /* 1 (identifier) + 5 bytes */ + + case PROP_SUBSCRIPTION_IDENTIFIER: + if(property->value.varint < 128){ + return 1; + }else if(property->value.varint < 16384){ + return 2; + }else if(property->value.varint < 2097152){ + return 3; + }else if(property->value.varint < 268435456){ + return 4; + }else{ + return 0; + } + + case PROP_CORRELATION_DATA: + case PROP_AUTHENTICATION_DATA: + return 3 + property->value.bin.len; /* 1 + 2 bytes (len) + X bytes (payload) */ + + case PROP_CONTENT_TYPE: + case PROP_RESPONSE_TOPIC: + case PROP_ASSIGNED_CLIENT_IDENTIFIER: + case PROP_AUTHENTICATION_METHOD: + case PROP_RESPONSE_INFO: + case PROP_SERVER_REFERENCE: + case PROP_REASON_STRING: + return 3 + property->value.s.len; /* 1 + 2 bytes (len) + X bytes (string) */ + + case PROP_USER_PROPERTY: + return 5 + property->value.s.len + property->name.len; /* 1 + 2*(2 bytes (len) + X bytes (string))*/ + + default: + return 0; + } + return 0; +} + + +int property__get_length_all(struct mqtt5__property *property) +{ + struct mqtt5__property *p; + int len = 0; + + p = property; + while(p){ + len += property__get_length(p); + p = p->next; + } + return len; +} + + int property__write_all(struct mosquitto__packet *packet, struct mqtt5__property **property) { packet__write_byte(packet, 0); diff --git a/lib/property_mosq.h b/lib/property_mosq.h index 27301eacf1..7f7ea54866 100644 --- a/lib/property_mosq.h +++ b/lib/property_mosq.h @@ -44,4 +44,7 @@ int property__write_all(struct mosquitto__packet *packet, struct mqtt5__property void property__free(struct mqtt5__property **property); void property__free_all(struct mqtt5__property **property); +int property__get_length(struct mqtt5__property *property); +int property__get_length_all(struct mqtt5__property *property); + #endif diff --git a/test/unit/property_read.c b/test/unit/property_read.c index 9022e7346c..4a8fa75dca 100644 --- a/test/unit/property_read.c +++ b/test/unit/property_read.c @@ -27,6 +27,7 @@ static void byte_prop_read_helper( CU_ASSERT_EQUAL(properties->identifier, identifier); CU_ASSERT_EQUAL(properties->value.i8, value_expected); CU_ASSERT_PTR_EQUAL(properties->next, NULL); + CU_ASSERT_EQUAL(property__get_length_all(properties), 2); property__free_all(&properties); } CU_ASSERT_PTR_EQUAL(properties, NULL); @@ -81,6 +82,7 @@ static void int32_prop_read_helper( CU_ASSERT_EQUAL(properties->identifier, identifier); CU_ASSERT_EQUAL(properties->value.i32, value_expected); CU_ASSERT_PTR_EQUAL(properties->next, NULL); + CU_ASSERT_EQUAL(property__get_length_all(properties), 5); property__free_all(&properties); } CU_ASSERT_PTR_EQUAL(properties, NULL); @@ -129,6 +131,7 @@ static void int16_prop_read_helper( CU_ASSERT_EQUAL(properties->identifier, identifier); CU_ASSERT_EQUAL(properties->value.i16, value_expected); CU_ASSERT_PTR_EQUAL(properties->next, NULL); + CU_ASSERT_EQUAL(property__get_length_all(properties), 3); property__free_all(&properties); } CU_ASSERT_PTR_EQUAL(properties, NULL); @@ -173,6 +176,7 @@ static void string_prop_read_helper( CU_ASSERT_EQUAL(properties->value.s.len, strlen(value_expected)); CU_ASSERT_STRING_EQUAL(properties->value.s.v, value_expected); CU_ASSERT_PTR_EQUAL(properties->next, NULL); + CU_ASSERT_EQUAL(property__get_length_all(properties), 1+2+strlen(value_expected)); property__free_all(&properties); } CU_ASSERT_PTR_EQUAL(properties, NULL); @@ -236,6 +240,7 @@ static void binary_prop_read_helper( CU_ASSERT_EQUAL(properties->value.bin.len, len_expected); CU_ASSERT_EQUAL(memcmp(properties->value.bin.v, value_expected, len_expected), 0); CU_ASSERT_PTR_EQUAL(properties->next, NULL); + CU_ASSERT_EQUAL(property__get_length_all(properties), 1+2+len_expected); property__free_all(&properties); } CU_ASSERT_PTR_EQUAL(properties, NULL); @@ -289,6 +294,7 @@ static void string_pair_prop_read_helper( CU_ASSERT_PTR_NOT_NULL(properties->next); }else{ CU_ASSERT_PTR_NULL(properties->next); + CU_ASSERT_EQUAL(property__get_length_all(properties), 1+2+strlen(name_expected)+2+strlen(value_expected)); } property__free_all(&properties); } @@ -316,6 +322,17 @@ static void varint_prop_read_helper( CU_ASSERT_EQUAL(properties->identifier, identifier); CU_ASSERT_EQUAL(properties->value.varint, value_expected); CU_ASSERT_PTR_NULL(properties->next); + if(value_expected < 128){ + CU_ASSERT_EQUAL(property__get_length_all(properties), 2); + }else if(value_expected < 16384){ + CU_ASSERT_EQUAL(property__get_length_all(properties), 3); + }else if(value_expected < 2097152){ + CU_ASSERT_EQUAL(property__get_length_all(properties), 4); + }else if(value_expected < 268435456){ + CU_ASSERT_EQUAL(property__get_length_all(properties), 5); + }else{ + CU_FAIL("Incorrect varint value."); + } property__free_all(&properties); } CU_ASSERT_PTR_NULL(properties); From 6609bbac102a7f5738b0af0ca242e699f7164533 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 10 Oct 2018 17:52:41 +0100 Subject: [PATCH 047/254] Move topic matching tests to unit tests. Needs improving. --- lib/CMakeLists.txt | 2 +- lib/Makefile | 4 + lib/util_mosq.c | 211 -------------------- lib/util_topic.c | 254 ++++++++++++++++++++++++ test/lib/09-util-topic-matching.py | 29 --- test/lib/Makefile | 1 - test/lib/c/09-util-topic-matching.c | 63 ------ test/lib/c/Makefile | 5 +- test/lib/cpp/09-util-topic-matching.cpp | 47 ----- test/lib/cpp/Makefile | 5 +- test/unit/Makefile | 5 + test/unit/test.c | 2 + test/unit/util_topic_test.c | 131 ++++++++++++ 13 files changed, 399 insertions(+), 360 deletions(-) create mode 100644 lib/util_topic.c delete mode 100755 test/lib/09-util-topic-matching.py delete mode 100644 test/lib/c/09-util-topic-matching.c delete mode 100644 test/lib/cpp/09-util-topic-matching.cpp create mode 100644 test/unit/util_topic_test.c diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 603e9f1571..cae15b03ae 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -69,7 +69,7 @@ set(C_SRC time_mosq.c tls_mosq.c utf8_mosq.c - util_mosq.c util_mosq.h + util_mosq.c util_topic.c util_mosq.h will_mosq.c will_mosq.h) set (LIBRARIES ${OPENSSL_LIBRARIES} ${PTHREAD_LIBRARIES}) diff --git a/lib/Makefile b/lib/Makefile index d9304c32bf..52d04714f9 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -38,6 +38,7 @@ MOSQ_OBJS=mosquitto.o \ tls_mosq.o \ utf8_mosq.o \ util_mosq.o \ + util_topic.o \ will_mosq.o ALL_DEPS=libmosquitto.so.${SOVERSION} @@ -189,6 +190,9 @@ utf8_mosq.o : utf8_mosq.c util_mosq.o : util_mosq.c util_mosq.h ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ +util_topic.o : util_topic.c util_mosq.h + ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ + will_mosq.o : will_mosq.c will_mosq.h ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ diff --git a/lib/util_mosq.c b/lib/util_mosq.c index 56d8cb0564..4909862c61 100644 --- a/lib/util_mosq.c +++ b/lib/util_mosq.c @@ -134,217 +134,6 @@ uint16_t mosquitto__mid_generate(struct mosquitto *mosq) return mid; } -/* Check that a topic used for publishing is valid. - * Search for + or # in a topic. Return MOSQ_ERR_INVAL if found. - * Also returns MOSQ_ERR_INVAL if the topic string is too long. - * Returns MOSQ_ERR_SUCCESS if everything is fine. - */ -int mosquitto_pub_topic_check(const char *str) -{ - int len = 0; - while(str && str[0]){ - if(str[0] == '+' || str[0] == '#'){ - return MOSQ_ERR_INVAL; - } - len++; - str = &str[1]; - } - if(len > 65535) return MOSQ_ERR_INVAL; - - return MOSQ_ERR_SUCCESS; -} - -int mosquitto_pub_topic_check2(const char *str, size_t len) -{ - int i; - - if(len > 65535) return MOSQ_ERR_INVAL; - - for(i=0; i 65535) return MOSQ_ERR_INVAL; - - return MOSQ_ERR_SUCCESS; -} - -int mosquitto_sub_topic_check2(const char *str, size_t len) -{ - char c = '\0'; - int i; - - if(len > 65535) return MOSQ_ERR_INVAL; - - for(i=0; i 0 && sub[spos-1] != '/'){ - return MOSQ_ERR_INVAL; - } - spos++; - *result = true; - return MOSQ_ERR_SUCCESS; - } - }else{ - if(sub[spos] == '+'){ - /* Check for bad "+foo" or "a/+foo" subscription */ - if(spos > 0 && sub[spos-1] != '/'){ - return MOSQ_ERR_INVAL; - } - /* Check for bad "foo+" or "foo+/a" subscription */ - if(spos < sublen-1 && sub[spos+1] != '/'){ - return MOSQ_ERR_INVAL; - } - spos++; - while(tpos < topiclen && topic[tpos] != '/'){ - tpos++; - } - if(tpos == topiclen && spos == sublen){ - *result = true; - return MOSQ_ERR_SUCCESS; - } - }else if(sub[spos] == '#'){ - if(spos > 0 && sub[spos-1] != '/'){ - return MOSQ_ERR_INVAL; - } - multilevel_wildcard = true; - if(spos+1 != sublen){ - return MOSQ_ERR_INVAL; - }else{ - *result = true; - return MOSQ_ERR_SUCCESS; - } - }else{ - /* Check for e.g. foo/bar matching foo/+/# */ - if(spos > 0 - && spos+2 == sublen - && tpos == topiclen - && sub[spos-1] == '+' - && sub[spos] == '/' - && sub[spos+1] == '#') - { - *result = true; - multilevel_wildcard = true; - return MOSQ_ERR_SUCCESS; - } - return MOSQ_ERR_SUCCESS; - } - } - } - if(multilevel_wildcard == false && (tpos < topiclen || spos < sublen)){ - *result = false; - } - - return MOSQ_ERR_SUCCESS; -} #ifdef WITH_TLS_PSK int mosquitto__hex2bin(const char *hex, unsigned char *bin, int bin_max_len) diff --git a/lib/util_topic.c b/lib/util_topic.c new file mode 100644 index 0000000000..dccec306c3 --- /dev/null +++ b/lib/util_topic.c @@ -0,0 +1,254 @@ +/* +Copyright (c) 2009-2018 Roger Light + +All rights reserved. This program and the accompanying materials +are made available under the terms of the Eclipse Public License v1.0 +and Eclipse Distribution License v1.0 which accompany this distribution. + +The Eclipse Public License is available at + http://www.eclipse.org/legal/epl-v10.html +and the Eclipse Distribution License is available at + http://www.eclipse.org/org/documents/edl-v10.php. + +Contributors: + Roger Light - initial implementation and documentation. +*/ + +#include "config.h" + +#include +#include + +#ifdef WIN32 +# include +# include +# include +# include +#else +# include +#endif + + +#ifdef WITH_BROKER +#include "mosquitto_broker_internal.h" +#endif + +#include "mosquitto.h" +#include "memory_mosq.h" +#include "net_mosq.h" +#include "send_mosq.h" +#include "time_mosq.h" +#include "tls_mosq.h" +#include "util_mosq.h" + +/* Check that a topic used for publishing is valid. + * Search for + or # in a topic. Return MOSQ_ERR_INVAL if found. + * Also returns MOSQ_ERR_INVAL if the topic string is too long. + * Returns MOSQ_ERR_SUCCESS if everything is fine. + */ +int mosquitto_pub_topic_check(const char *str) +{ + int len = 0; + while(str && str[0]){ + if(str[0] == '+' || str[0] == '#'){ + return MOSQ_ERR_INVAL; + } + len++; + str = &str[1]; + } + if(len > 65535) return MOSQ_ERR_INVAL; + + return MOSQ_ERR_SUCCESS; +} + +int mosquitto_pub_topic_check2(const char *str, size_t len) +{ + int i; + + if(len > 65535) return MOSQ_ERR_INVAL; + + for(i=0; i 65535) return MOSQ_ERR_INVAL; + + return MOSQ_ERR_SUCCESS; +} + +int mosquitto_sub_topic_check2(const char *str, size_t len) +{ + char c = '\0'; + int i; + + if(len > 65535) return MOSQ_ERR_INVAL; + + for(i=0; i 0 && sub[spos-1] != '/'){ + return MOSQ_ERR_INVAL; + } + spos++; + *result = true; + return MOSQ_ERR_SUCCESS; + } + }else{ + if(sub[spos] == '+'){ + /* Check for bad "+foo" or "a/+foo" subscription */ + if(spos > 0 && sub[spos-1] != '/'){ + return MOSQ_ERR_INVAL; + } + /* Check for bad "foo+" or "foo+/a" subscription */ + if(spos < sublen-1 && sub[spos+1] != '/'){ + return MOSQ_ERR_INVAL; + } + spos++; + while(tpos < topiclen && topic[tpos] != '/'){ + tpos++; + } + if(tpos == topiclen && spos == sublen){ + *result = true; + return MOSQ_ERR_SUCCESS; + } + }else if(sub[spos] == '#'){ + if(spos > 0 && sub[spos-1] != '/'){ + return MOSQ_ERR_INVAL; + } + multilevel_wildcard = true; + if(spos+1 != sublen){ + return MOSQ_ERR_INVAL; + }else{ + *result = true; + return MOSQ_ERR_SUCCESS; + } + }else{ + /* Check for e.g. foo/bar matching foo/+/# */ + if(spos > 0 + && spos+2 == sublen + && tpos == topiclen + && sub[spos-1] == '+' + && sub[spos] == '/' + && sub[spos+1] == '#') + { + *result = true; + multilevel_wildcard = true; + return MOSQ_ERR_SUCCESS; + } + return MOSQ_ERR_SUCCESS; + } + } + } + if(multilevel_wildcard == false && (tpos < topiclen || spos < sublen)){ + *result = false; + } + + return MOSQ_ERR_SUCCESS; +} diff --git a/test/lib/09-util-topic-matching.py b/test/lib/09-util-topic-matching.py deleted file mode 100755 index 3dc19e0b63..0000000000 --- a/test/lib/09-util-topic-matching.py +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python - -import inspect -import os -import sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) -import mosq_test - -rc = 1 - -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) -client.wait() -if client.returncode: - (stdo, stde) = client.communicate() - print(stdo) -exit(client.returncode) diff --git a/test/lib/Makefile b/test/lib/Makefile index f448d7e4f2..bf5a931fbe 100644 --- a/test/lib/Makefile +++ b/test/lib/Makefile @@ -46,7 +46,6 @@ ifeq ($(WITH_TLS),yes) ./08-ssl-bad-cacert.py $@/08-ssl-bad-cacert.test #./08-ssl-fake-cacert.py $@/08-ssl-fake-cacert.test endif - ./09-util-topic-matching.py $@/09-util-topic-matching.test ./09-util-topic-tokenise.py $@/09-util-topic-tokenise.test clean : diff --git a/test/lib/c/09-util-topic-matching.c b/test/lib/c/09-util-topic-matching.c deleted file mode 100644 index 12c512fd86..0000000000 --- a/test/lib/c/09-util-topic-matching.c +++ /dev/null @@ -1,63 +0,0 @@ -#include -#include -#include - -#define EXPECT_MATCH(A, B) do_check((A), (B), false) -#define EXPECT_NOMATCH(A, B) do_check((A), (B), true) - -void do_check(const char *sub, const char *topic, bool bad_res) -{ - bool match; - - mosquitto_topic_matches_sub(sub, topic, &match); - - if(match == bad_res){ - printf("s: %s t: %s\n", sub, topic); - exit(1); - } -} - -int main(int argc, char *argv[]) -{ - EXPECT_MATCH("foo/#", "foo/"); - EXPECT_NOMATCH("foo#", "foo"); - EXPECT_NOMATCH("fo#o/", "foo"); - EXPECT_NOMATCH("foo#", "fooa"); - EXPECT_NOMATCH("foo+", "foo"); - EXPECT_NOMATCH("foo+", "fooa"); - - EXPECT_NOMATCH("test/6/#", "test/3"); - EXPECT_MATCH("foo/bar", "foo/bar"); - EXPECT_MATCH("foo/+", "foo/bar"); - EXPECT_MATCH("foo/+/baz", "foo/bar/baz"); - - EXPECT_MATCH("A/B/+/#", "A/B/B/C"); - - EXPECT_MATCH("foo/+/#", "foo/bar/baz"); - EXPECT_MATCH("foo/+/#", "foo/bar"); - EXPECT_MATCH("#", "foo/bar/baz"); - EXPECT_MATCH("#", "foo/bar/baz"); - - EXPECT_NOMATCH("foo/bar", "foo"); - EXPECT_NOMATCH("foo/+", "foo/bar/baz"); - EXPECT_NOMATCH("foo/+/baz", "foo/bar/bar"); - - EXPECT_NOMATCH("foo/+/#", "fo2/bar/baz"); - - EXPECT_MATCH("#", "/foo/bar"); - EXPECT_MATCH("/#", "/foo/bar"); - EXPECT_NOMATCH("/#", "foo/bar"); - - - EXPECT_MATCH("foo//bar", "foo//bar"); - EXPECT_MATCH("foo//+", "foo//bar"); - EXPECT_MATCH("foo/+/+/baz", "foo///baz"); - EXPECT_MATCH("foo/bar/+", "foo/bar/"); - - EXPECT_MATCH("$SYS/bar", "$SYS/bar"); - EXPECT_NOMATCH("#", "$SYS/bar"); - EXPECT_NOMATCH("$BOB/bar", "$SYS/bar"); - - return 0; -} - diff --git a/test/lib/c/Makefile b/test/lib/c/Makefile index 0484fedd72..9678766a47 100644 --- a/test/lib/c/Makefile +++ b/test/lib/c/Makefile @@ -74,9 +74,6 @@ all : 01 02 03 04 08 09 08-ssl-fake-cacert.test : 08-ssl-fake-cacert.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) -09-util-topic-matching.test : 09-util-topic-matching.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - 09-util-topic-tokenise.test : 09-util-topic-tokenise.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) @@ -90,7 +87,7 @@ all : 01 02 03 04 08 09 08 : 08-ssl-connect-no-auth.test 08-ssl-connect-cert-auth.test 08-ssl-connect-cert-auth-enc.test 08-ssl-bad-cacert.test 08-ssl-fake-cacert.test -09 : 09-util-topic-matching.test 09-util-topic-tokenise.test +09 : 09-util-topic-tokenise.test reallyclean : clean -rm -f *.orig diff --git a/test/lib/cpp/09-util-topic-matching.cpp b/test/lib/cpp/09-util-topic-matching.cpp deleted file mode 100644 index 4b1776aa84..0000000000 --- a/test/lib/cpp/09-util-topic-matching.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include - -void do_check(const char *sub, const char *topic, bool bad_res) -{ - bool match; - - mosqpp::topic_matches_sub(sub, topic, &match); - - if(match == bad_res){ - printf("s: %s t: %s\n", sub, topic); - exit(1); - } -} - -int main(int argc, char *argv[]) -{ - do_check("foo/bar", "foo/bar", false); - do_check("foo/+", "foo/bar", false); - do_check("foo/+/baz", "foo/bar/baz", false); - - do_check("foo/+/#", "foo/bar/baz", false); - do_check("#", "foo/bar/baz", false); - - do_check("foo/bar", "foo", true); - do_check("foo/+", "foo/bar/baz", true); - do_check("foo/+/baz", "foo/bar/bar", true); - - do_check("foo/+/#", "fo2/bar/baz", true); - - do_check("#", "/foo/bar", false); - do_check("/#", "/foo/bar", false); - do_check("/#", "foo/bar", true); - - - do_check("foo//bar", "foo//bar", false); - do_check("foo//+", "foo//bar", false); - do_check("foo/+/+/baz", "foo///baz", false); - do_check("foo/bar/+", "foo/bar/", false); - - do_check("$SYS/bar", "$SYS/bar", false); - do_check("#", "$SYS/bar", true); - do_check("$BOB/bar", "$SYS/bar", true); - - return 0; -} - diff --git a/test/lib/cpp/Makefile b/test/lib/cpp/Makefile index 4d9e86f017..5761d9d40c 100644 --- a/test/lib/cpp/Makefile +++ b/test/lib/cpp/Makefile @@ -74,9 +74,6 @@ all : 01 02 03 04 08 09 08-ssl-fake-cacert.test : 08-ssl-fake-cacert.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) -09-util-topic-matching.test : 09-util-topic-matching.cpp - $(CXX) $< -o $@ $(CFLAGS) $(LIBS) - 09-util-topic-tokenise.test : 09-util-topic-tokenise.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) @@ -90,7 +87,7 @@ all : 01 02 03 04 08 09 08 : 08-ssl-connect-no-auth.test 08-ssl-connect-cert-auth.test 08-ssl-connect-cert-auth-enc.test 08-ssl-bad-cacert.test 08-ssl-fake-cacert.test -09 : 09-util-topic-matching.test 09-util-topic-tokenise.test +09 : 09-util-topic-tokenise.test reallyclean : clean -rm -f *.orig diff --git a/test/unit/Makefile b/test/unit/Makefile index 952490768d..fba2ce321c 100644 --- a/test/unit/Makefile +++ b/test/unit/Makefile @@ -10,11 +10,13 @@ TEST_OBJS = test.o \ datatype_write.o \ property_read.o \ stubs.o \ + util_topic_test.o \ utf8.o LIB_OBJS = memory_mosq.o \ packet_datatypes.o \ property_mosq.o \ + util_topic.o \ utf8_mosq.o all : test @@ -31,6 +33,9 @@ packet_datatypes.o : ../../lib/packet_datatypes.c property_mosq.o : ../../lib/property_mosq.c $(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^ +util_topic.o : ../../lib/util_topic.c + $(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^ + utf8_mosq.o : ../../lib/utf8_mosq.c $(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^ diff --git a/test/unit/test.c b/test/unit/test.c index dea045a493..1b920ed69f 100644 --- a/test/unit/test.c +++ b/test/unit/test.c @@ -7,6 +7,7 @@ int init_datatype_read_tests(void); int init_datatype_write_tests(void); int init_property_read_tests(void); int init_utf8_tests(void); +int init_util_topic_tests(void); int main(int argc, char *argv[]) { @@ -21,6 +22,7 @@ int main(int argc, char *argv[]) || init_datatype_read_tests() || init_datatype_write_tests() || init_property_read_tests() + || init_util_topic_tests() ){ CU_cleanup_registry(); diff --git a/test/unit/util_topic_test.c b/test/unit/util_topic_test.c new file mode 100644 index 0000000000..9b614fdf78 --- /dev/null +++ b/test/unit/util_topic_test.c @@ -0,0 +1,131 @@ +#include +#include + +#include + +static void match_helper(const char *sub, const char *topic) +{ + int rc; + bool match; + + rc = mosquitto_topic_matches_sub(sub, topic, &match); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_EQUAL(match, true); +} + +static void no_match_helper(const char *sub, const char *topic) +{ + int rc; + bool match; + + rc = mosquitto_topic_matches_sub(sub, topic, &match); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_EQUAL(match, false); +} + +/* ======================================================================== + * EMPTY INPUT + * ======================================================================== */ + +static void TEST_empty_input(void) +{ + int rc; + bool match; + + rc = mosquitto_topic_matches_sub("sub", NULL, &match); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); + CU_ASSERT_EQUAL(match, false); + + rc = mosquitto_topic_matches_sub(NULL, "topic", &match); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); + CU_ASSERT_EQUAL(match, false); + + rc = mosquitto_topic_matches_sub(NULL, NULL, &match); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); + CU_ASSERT_EQUAL(match, false); + + rc = mosquitto_topic_matches_sub2("sub", 3, NULL, 0, &match); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); + CU_ASSERT_EQUAL(match, false); + + rc = mosquitto_topic_matches_sub2(NULL, 0, "topic", 5, &match); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); + CU_ASSERT_EQUAL(match, false); + + rc = mosquitto_topic_matches_sub2(NULL, 0, NULL, 0, &match); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); + CU_ASSERT_EQUAL(match, false); +} + +/* ======================================================================== + * VALID MATCHING AND NON-MATCHING + * ======================================================================== */ + +void TEST_valid_matching(void) +{ + match_helper("foo/#", "foo/"); + match_helper("foo//bar", "foo//bar"); + match_helper("foo//+", "foo//bar"); + match_helper("foo/+/+/baz", "foo///baz"); + match_helper("foo/bar/+", "foo/bar/"); + match_helper("foo/bar", "foo/bar"); + match_helper("foo/+", "foo/bar"); + match_helper("foo/+/baz", "foo/bar/baz"); + match_helper("A/B/+/#", "A/B/B/C"); + match_helper("foo/+/#", "foo/bar/baz"); + match_helper("foo/+/#", "foo/bar"); + match_helper("#", "foo/bar/baz"); + match_helper("#", "foo/bar/baz"); + match_helper("#", "/foo/bar"); + match_helper("/#", "/foo/bar"); +} + +void TEST_no_matching(void) +{ + no_match_helper("foo#", "foo"); + no_match_helper("fo#o/", "foo"); + no_match_helper("foo#", "fooa"); + no_match_helper("foo+", "foo"); + no_match_helper("foo+", "fooa"); + + no_match_helper("test/6/#", "test/3"); + + no_match_helper("foo/bar", "foo"); + no_match_helper("foo/+", "foo/bar/baz"); + no_match_helper("foo/+/baz", "foo/bar/bar"); + + no_match_helper("foo/+/#", "fo2/bar/baz"); + + no_match_helper("/#", "foo/bar"); + + + no_match_helper("#", "$SYS/bar"); + no_match_helper("$BOB/bar", "$SYS/bar"); +} + +/* ======================================================================== + * TEST SUITE SETUP + * ======================================================================== */ + +int init_util_topic_tests(void) +{ + CU_pSuite test_suite = NULL; + + test_suite = CU_add_suite("Util topic", NULL, NULL); + if(!test_suite){ + printf("Error adding CUnit util topic test suite.\n"); + return 1; + } + + if(0 + || !CU_add_test(test_suite, "Empty input", TEST_empty_input) + || !CU_add_test(test_suite, "Valid matching", TEST_valid_matching) + || !CU_add_test(test_suite, "No matching", TEST_no_matching) + ){ + + printf("Error adding util topic CUnit tests.\n"); + return 1; + } + + return 0; +} From 262ac3fb5bef0a5b8c4dbae464782919adf0dc09 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 10 Oct 2018 17:53:19 +0100 Subject: [PATCH 048/254] Fix varint length reporting. --- lib/property_mosq.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/property_mosq.c b/lib/property_mosq.c index d5ce563150..74fbd66249 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -310,13 +310,13 @@ int property__get_length(struct mqtt5__property *property) case PROP_SUBSCRIPTION_IDENTIFIER: if(property->value.varint < 128){ - return 1; - }else if(property->value.varint < 16384){ return 2; - }else if(property->value.varint < 2097152){ + }else if(property->value.varint < 16384){ return 3; - }else if(property->value.varint < 268435456){ + }else if(property->value.varint < 2097152){ return 4; + }else if(property->value.varint < 268435456){ + return 5; }else{ return 0; } From a7fff2ad2e338e3581b22f146850af24c48c35b3 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 16 Oct 2018 13:49:38 +0100 Subject: [PATCH 049/254] Topic test improvements. --- src/CMakeLists.txt | 2 +- src/Makefile | 4 ++ test/unit/util_topic_test.c | 92 ++++++++++++++++++++++++++++--------- 3 files changed, 76 insertions(+), 22 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d14ac49488..ba503f6001 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -47,7 +47,7 @@ set (MOSQ_SRCS sys_tree.c sys_tree.h ../lib/time_mosq.c ../lib/tls_mosq.c - ../lib/util_mosq.c ../lib/util_mosq.h + ../lib/util_mosq.c ../lib/util_topic.c ../lib/util_mosq.h ../lib/utf8_mosq.c websockets.c ../lib/will_mosq.c ../lib/will_mosq.h) diff --git a/src/Makefile b/src/Makefile index e9bf16a1c0..07d8f1131c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -54,6 +54,7 @@ OBJS= mosquitto.o \ tls_mosq.o \ utf8_mosq.o \ util_mosq.o \ + util_topic.o \ websockets.o \ will_mosq.o @@ -195,6 +196,9 @@ tls_mosq.o : ../lib/tls_mosq.c util_mosq.o : ../lib/util_mosq.c ../lib/util_mosq.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ +util_topic.o : ../lib/util_topic.c ../lib/util_mosq.h + ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ + utf8_mosq.o : ../lib/utf8_mosq.c ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ diff --git a/test/unit/util_topic_test.c b/test/unit/util_topic_test.c index 9b614fdf78..c843f861e7 100644 --- a/test/unit/util_topic_test.c +++ b/test/unit/util_topic_test.c @@ -13,13 +13,13 @@ static void match_helper(const char *sub, const char *topic) CU_ASSERT_EQUAL(match, true); } -static void no_match_helper(const char *sub, const char *topic) +static void no_match_helper(int rc_expected, const char *sub, const char *topic) { int rc; bool match; rc = mosquitto_topic_matches_sub(sub, topic, &match); - CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_EQUAL(rc, rc_expected); CU_ASSERT_EQUAL(match, false); } @@ -35,26 +35,50 @@ static void TEST_empty_input(void) rc = mosquitto_topic_matches_sub("sub", NULL, &match); CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); CU_ASSERT_EQUAL(match, false); - + rc = mosquitto_topic_matches_sub(NULL, "topic", &match); CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); CU_ASSERT_EQUAL(match, false); - + rc = mosquitto_topic_matches_sub(NULL, NULL, &match); CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); CU_ASSERT_EQUAL(match, false); + rc = mosquitto_topic_matches_sub("sub", "", &match); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); + CU_ASSERT_EQUAL(match, false); + + rc = mosquitto_topic_matches_sub("", "topic", &match); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); + CU_ASSERT_EQUAL(match, false); + + rc = mosquitto_topic_matches_sub("", "", &match); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); + CU_ASSERT_EQUAL(match, false); + rc = mosquitto_topic_matches_sub2("sub", 3, NULL, 0, &match); CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); CU_ASSERT_EQUAL(match, false); - + rc = mosquitto_topic_matches_sub2(NULL, 0, "topic", 5, &match); CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); CU_ASSERT_EQUAL(match, false); - + rc = mosquitto_topic_matches_sub2(NULL, 0, NULL, 0, &match); CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); CU_ASSERT_EQUAL(match, false); + + rc = mosquitto_topic_matches_sub2("sub", 3, "", 0, &match); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); + CU_ASSERT_EQUAL(match, false); + + rc = mosquitto_topic_matches_sub2("", 0, "topic", 5, &match); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); + CU_ASSERT_EQUAL(match, false); + + rc = mosquitto_topic_matches_sub2("", 0, "", 0, &match); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); + CU_ASSERT_EQUAL(match, false); } /* ======================================================================== @@ -64,6 +88,7 @@ static void TEST_empty_input(void) void TEST_valid_matching(void) { match_helper("foo/#", "foo/"); + match_helper("foo/#", "foo"); match_helper("foo//bar", "foo//bar"); match_helper("foo//+", "foo//bar"); match_helper("foo/+/+/baz", "foo///baz"); @@ -80,27 +105,51 @@ void TEST_valid_matching(void) match_helper("/#", "/foo/bar"); } -void TEST_no_matching(void) + +void TEST_invalid_but_matching(void) +{ + /* Matching here is "naive treatment of the wildcards would produce a + * match". They shouldn't really match, they should fail. */ + no_match_helper(MOSQ_ERR_INVAL, "+foo", "+foo"); + no_match_helper(MOSQ_ERR_INVAL, "fo+o", "fo+o"); + no_match_helper(MOSQ_ERR_INVAL, "foo+", "foo+"); + no_match_helper(MOSQ_ERR_INVAL, "+foo/bar", "+foo/bar"); + no_match_helper(MOSQ_ERR_INVAL, "foo+/bar", "foo+/bar"); + no_match_helper(MOSQ_ERR_INVAL, "foo/+bar", "foo/+bar"); + no_match_helper(MOSQ_ERR_INVAL, "foo/bar+", "foo/bar+"); + + no_match_helper(MOSQ_ERR_INVAL, "#foo", "#foo"); + no_match_helper(MOSQ_ERR_INVAL, "fo#o", "fo#o"); + no_match_helper(MOSQ_ERR_INVAL, "foo#", "foo#"); + no_match_helper(MOSQ_ERR_INVAL, "#foo/bar", "#foo/bar"); + no_match_helper(MOSQ_ERR_INVAL, "foo#/bar", "foo#/bar"); + no_match_helper(MOSQ_ERR_INVAL, "foo/#bar", "foo/#bar"); + no_match_helper(MOSQ_ERR_INVAL, "foo/bar#", "foo/bar#"); +} + + +void TEST_valid_no_matching(void) { - no_match_helper("foo#", "foo"); - no_match_helper("fo#o/", "foo"); - no_match_helper("foo#", "fooa"); - no_match_helper("foo+", "foo"); - no_match_helper("foo+", "fooa"); + no_match_helper(MOSQ_ERR_INVAL, "foo#", "foo"); + no_match_helper(MOSQ_ERR_INVAL, "fo#o/", "foo"); + no_match_helper(MOSQ_ERR_INVAL, "foo#", "fooa"); + no_match_helper(MOSQ_ERR_INVAL, "foo+", "foo"); + no_match_helper(MOSQ_ERR_INVAL, "foo+", "fooa"); - no_match_helper("test/6/#", "test/3"); + no_match_helper(MOSQ_ERR_INVAL, "test/6/#", "test/3"); - no_match_helper("foo/bar", "foo"); - no_match_helper("foo/+", "foo/bar/baz"); - no_match_helper("foo/+/baz", "foo/bar/bar"); + no_match_helper(MOSQ_ERR_INVAL, "foo/bar", "foo"); + no_match_helper(MOSQ_ERR_INVAL, "foo/+", "foo/bar/baz"); + no_match_helper(MOSQ_ERR_INVAL, "foo/+/baz", "foo/bar/bar"); - no_match_helper("foo/+/#", "fo2/bar/baz"); + no_match_helper(MOSQ_ERR_INVAL, "foo/+/#", "fo2/bar/baz"); - no_match_helper("/#", "foo/bar"); + no_match_helper(MOSQ_ERR_INVAL, "/#", "foo/bar"); + no_match_helper(MOSQ_ERR_INVAL, "/#a", "foo/bar"); - no_match_helper("#", "$SYS/bar"); - no_match_helper("$BOB/bar", "$SYS/bar"); + no_match_helper(MOSQ_ERR_INVAL, "#", "$SYS/bar"); + no_match_helper(MOSQ_ERR_INVAL, "$BOB/bar", "$SYS/bar"); } /* ======================================================================== @@ -120,7 +169,8 @@ int init_util_topic_tests(void) if(0 || !CU_add_test(test_suite, "Empty input", TEST_empty_input) || !CU_add_test(test_suite, "Valid matching", TEST_valid_matching) - || !CU_add_test(test_suite, "No matching", TEST_no_matching) + || !CU_add_test(test_suite, "Valid no matching", TEST_valid_no_matching) + || !CU_add_test(test_suite, "Invalid but matching", TEST_invalid_but_matching) ){ printf("Error adding util topic CUnit tests.\n"); From 5edc87bcdf5c572e924c9d748a437361021f4842 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 16 Oct 2018 13:54:50 +0100 Subject: [PATCH 050/254] Build options for building with coverage support. --- config.mk | 13 +++++++++++++ src/Makefile | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/config.mk b/config.mk index 46ffb6db2c..6f3f3ac592 100644 --- a/config.mk +++ b/config.mk @@ -95,6 +95,9 @@ WITH_EPOLL:=yes # Build with bundled uthash.h WITH_BUNDLED_DEPS:=yes +# Build with coverage options +WITH_COVERAGE:=no + # ============================================================================= # End of user configuration # ============================================================================= @@ -131,6 +134,7 @@ LIB_CXXFLAGS:=$(CFLAGS) ${CPPFLAGS} -I. -I.. -I../lib LIB_LDFLAGS:=${LDFLAGS} BROKER_CFLAGS:=${LIB_CFLAGS} ${CPPFLAGS} -DVERSION="\"${VERSION}\"" -DWITH_BROKER +BROKER_LDFLAGS:=${LDFLAGS} CLIENT_CFLAGS:=${CFLAGS} ${CPPFLAGS} -I.. -I../lib -DVERSION="\"${VERSION}\"" ifneq ($(or $(findstring $(UNAME),FreeBSD), $(findstring $(UNAME),OpenBSD), $(findstring $(UNAME),NetBSD)),) @@ -295,3 +299,12 @@ endif ifeq ($(WITH_BUNDLED_DEPS),yes) BROKER_CFLAGS:=$(BROKER_CFLAGS) -Ideps endif + +ifeq ($(WITH_COVERAGE),yes) + BROKER_CFLAGS:=$(BROKER_CFLAGS) -coverage + BROKER_LDFLAGS:=$(BROKER_LDFLAGS) -coverage + LIB_CFLAGS:=$(LIB_CFLAGS) -coverage + LIB_LDFLAGS:=$(LIB_LDFLAGS) -coverage + CLIENT_CFLAGS:=$(CLIENT_CFLAGS) -coverage + CLIENT_LDFLAGS:=$(CLIENT_LDFLAGS) -coverage +endif diff --git a/src/Makefile b/src/Makefile index 07d8f1131c..16191e20f9 100644 --- a/src/Makefile +++ b/src/Makefile @@ -59,7 +59,7 @@ OBJS= mosquitto.o \ will_mosq.o mosquitto : ${OBJS} - ${CROSS_COMPILE}${CC} $^ -o $@ ${LDFLAGS} $(BROKER_LIBS) + ${CROSS_COMPILE}${CC} $^ -o $@ ${BROKER_LDFLAGS} $(BROKER_LIBS) mosquitto.o : mosquitto.c mosquitto_broker_internal.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ From 4daaaaf4a7707e290af6e7fc23e8e03fde946a74 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 16 Oct 2018 14:35:37 +0100 Subject: [PATCH 051/254] Add property writing support, untested. --- lib/packet_datatypes.c | 24 +++++++++++++ lib/packet_mosq.h | 1 + lib/property_mosq.c | 81 ++++++++++++++++++++++++++++++++++++++++-- lib/property_mosq.h | 2 +- 4 files changed, 105 insertions(+), 3 deletions(-) diff --git a/lib/packet_datatypes.c b/lib/packet_datatypes.c index dd15d67342..a07a9f54f7 100644 --- a/lib/packet_datatypes.c +++ b/lib/packet_datatypes.c @@ -225,3 +225,27 @@ int packet__read_varint(struct mosquitto__packet *packet, int32_t *word, int8_t return MOSQ_ERR_PROTOCOL; } + +int packet__write_varint(struct mosquitto__packet *packet, int32_t word) +{ + uint8_t byte; + int count = 0; + + packet->payload = NULL; + packet->remaining_count = 0; + do{ + byte = word % 128; + word = word / 128; + /* If there are more digits to encode, set the top bit of this digit */ + if(word > 0){ + byte = byte | 0x80; + } + packet__write_byte(packet, byte); + count++; + }while(word > 0 && count < 5); + + if(count == 5){ + return MOSQ_ERR_PROTOCOL; + } + return MOSQ_ERR_SUCCESS; +} diff --git a/lib/packet_mosq.h b/lib/packet_mosq.h index 8c44d6ab92..04855327f9 100644 --- a/lib/packet_mosq.h +++ b/lib/packet_mosq.h @@ -40,6 +40,7 @@ void packet__write_bytes(struct mosquitto__packet *packet, const void *bytes, ui void packet__write_string(struct mosquitto__packet *packet, const char *str, uint16_t length); void packet__write_uint16(struct mosquitto__packet *packet, uint16_t word); void packet__write_uint32(struct mosquitto__packet *packet, uint32_t word); +int packet__write_varint(struct mosquitto__packet *packet, int32_t word); int packet__write(struct mosquitto *mosq); #ifdef WITH_BROKER diff --git a/lib/property_mosq.c b/lib/property_mosq.c index 74fbd66249..5bb7331ad3 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -358,9 +358,86 @@ int property__get_length_all(struct mqtt5__property *property) } -int property__write_all(struct mosquitto__packet *packet, struct mqtt5__property **property) +int property__write(struct mosquitto__packet *packet, struct mqtt5__property *property) { - packet__write_byte(packet, 0); + int rc; + + rc = packet__write_varint(packet, property->identifier); + if(rc) return rc; + + switch(property->identifier){ + case PROP_PAYLOAD_FORMAT_INDICATOR: + case PROP_REQUEST_PROBLEM_INFO: + case PROP_REQUEST_RESPONSE_INFO: + case PROP_MAXIMUM_QOS: + case PROP_RETAIN_AVAILABLE: + case PROP_WILDCARD_SUB_AVAILABLE: + case PROP_SUBSCRIPTION_ID_AVAILABLE: + case PROP_SHARED_SUB_AVAILABLE: + packet__write_byte(packet, property->value.i8); + break; + + case PROP_SERVER_KEEP_ALIVE: + case PROP_RECEIVE_MAXIMUM: + case PROP_TOPIC_ALIAS_MAXIMUM: + case PROP_TOPIC_ALIAS: + packet__write_uint16(packet, property->value.i16); + break; + + case PROP_MESSAGE_EXPIRY_INTERVAL: + case PROP_SESSION_EXPIRY_INTERVAL: + case PROP_WILL_DELAY_INTERVAL: + case PROP_MAXIMUM_PACKET_SIZE: + packet__write_uint32(packet, property->value.i32); + break; + + case PROP_SUBSCRIPTION_IDENTIFIER: + return packet__write_varint(packet, property->value.varint); + + case PROP_CONTENT_TYPE: + case PROP_RESPONSE_TOPIC: + case PROP_ASSIGNED_CLIENT_IDENTIFIER: + case PROP_AUTHENTICATION_METHOD: + case PROP_RESPONSE_INFO: + case PROP_SERVER_REFERENCE: + case PROP_REASON_STRING: + packet__write_string(packet, property->value.s.v, property->value.s.len); + break; + + case PROP_AUTHENTICATION_DATA: + case PROP_CORRELATION_DATA: + packet__write_uint16(packet, property->value.bin.len); + packet__write_bytes(packet, property->value.bin.v, property->value.bin.len); + + case PROP_USER_PROPERTY: + packet__write_string(packet, property->name.v, property->name.len); + packet__write_string(packet, property->value.s.v, property->value.s.len); + break; + + default: + log__printf(NULL, MOSQ_LOG_DEBUG, "Unsupported property type: %d", property->identifier); + return MOSQ_ERR_INVAL; + } + + return MOSQ_ERR_SUCCESS; +} + + +int property__write_all(struct mosquitto__packet *packet, struct mqtt5__property *properties) +{ + int rc; + struct mqtt5__property *p; + + rc = packet__write_varint(packet, property__get_length_all(properties)); + if(rc) return rc; + + p = properties; + while(p){ + rc = property__write(packet, p); + if(rc) return rc; + p = p->next; + } + return MOSQ_ERR_SUCCESS; } diff --git a/lib/property_mosq.h b/lib/property_mosq.h index 7f7ea54866..9e913f9910 100644 --- a/lib/property_mosq.h +++ b/lib/property_mosq.h @@ -40,7 +40,7 @@ struct mqtt5__property { int property__read_all(struct mosquitto__packet *packet, struct mqtt5__property **property); -int property__write_all(struct mosquitto__packet *packet, struct mqtt5__property **property); +int property__write_all(struct mosquitto__packet *packet, struct mqtt5__property *property); void property__free(struct mqtt5__property **property); void property__free_all(struct mqtt5__property **property); From 77099bb58c5ed610c2cd965373002cd61ed3fb71 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 16 Oct 2018 21:32:13 +0100 Subject: [PATCH 052/254] Add property write tests. --- lib/packet_datatypes.c | 2 - test/unit/Makefile | 1 + test/unit/property_read.c | 2 +- test/unit/property_write.c | 508 +++++++++++++++++++++++++++++++++++++ test/unit/test.c | 2 + 5 files changed, 512 insertions(+), 3 deletions(-) create mode 100644 test/unit/property_write.c diff --git a/lib/packet_datatypes.c b/lib/packet_datatypes.c index a07a9f54f7..1b0abeeb97 100644 --- a/lib/packet_datatypes.c +++ b/lib/packet_datatypes.c @@ -231,8 +231,6 @@ int packet__write_varint(struct mosquitto__packet *packet, int32_t word) uint8_t byte; int count = 0; - packet->payload = NULL; - packet->remaining_count = 0; do{ byte = word % 128; word = word / 128; diff --git a/test/unit/Makefile b/test/unit/Makefile index fba2ce321c..611e20987a 100644 --- a/test/unit/Makefile +++ b/test/unit/Makefile @@ -9,6 +9,7 @@ TEST_OBJS = test.o \ datatype_read.o \ datatype_write.o \ property_read.o \ + property_write.o \ stubs.o \ util_topic_test.o \ utf8.o diff --git a/test/unit/property_read.c b/test/unit/property_read.c index 4a8fa75dca..97a8182c95 100644 --- a/test/unit/property_read.c +++ b/test/unit/property_read.c @@ -338,7 +338,7 @@ static void varint_prop_read_helper( CU_ASSERT_PTR_NULL(properties); } -void packet_helper_reason_string_user_property(void) +static void packet_helper_reason_string_user_property(void) { uint8_t payload[24] = {23, PROP_REASON_STRING, 0, 6, 'r', 'e', 'a', 's', 'o', 'n', diff --git a/test/unit/property_write.c b/test/unit/property_write.c new file mode 100644 index 0000000000..4fca1d5c79 --- /dev/null +++ b/test/unit/property_write.c @@ -0,0 +1,508 @@ +#include +#include + +#include "mqtt_protocol.h" +#include "property_mosq.h" +#include "packet_mosq.h" + +static void byte_prop_write_helper( + int remaining_length, + int rc_expected, + int identifier, + uint8_t value_expected) +{ + struct mqtt5__property property; + struct mosquitto__packet packet; + struct mqtt5__property *properties; + int rc; + + memset(&property, 0, sizeof(struct mqtt5__property)); + + property.identifier = identifier; + property.value.i8 = value_expected; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.remaining_length = property__get_length_all(&property)+1; + packet.packet_length = packet.remaining_length+10; + packet.payload = calloc(packet.remaining_length+10, 1); + + property__write_all(&packet, &property); + packet.pos = 0; + + rc = property__read_all(&packet, &properties); + + CU_ASSERT_EQUAL(rc, rc_expected); + CU_ASSERT_EQUAL(packet.pos, remaining_length); + if(properties){ + CU_ASSERT_EQUAL(properties->identifier, identifier); + CU_ASSERT_EQUAL(properties->value.i8, value_expected); + CU_ASSERT_PTR_EQUAL(properties->next, NULL); + CU_ASSERT_EQUAL(property__get_length_all(properties), 2); + property__free_all(&properties); + } + CU_ASSERT_PTR_EQUAL(properties, NULL); +} + + +static void int32_prop_write_helper( + int remaining_length, + int rc_expected, + int identifier, + uint32_t value_expected) +{ + struct mqtt5__property property; + struct mosquitto__packet packet; + struct mqtt5__property *properties; + int rc; + + memset(&property, 0, sizeof(struct mqtt5__property)); + + property.identifier = identifier; + property.value.i32 = value_expected; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.remaining_length = property__get_length_all(&property)+1; + packet.packet_length = packet.remaining_length+10; + packet.payload = calloc(packet.remaining_length+10, 1); + + property__write_all(&packet, &property); + packet.pos = 0; + + rc = property__read_all(&packet, &properties); + + CU_ASSERT_EQUAL(rc, rc_expected); + CU_ASSERT_EQUAL(packet.pos, remaining_length); + if(properties){ + CU_ASSERT_EQUAL(properties->identifier, identifier); + CU_ASSERT_EQUAL(properties->value.i32, value_expected); + CU_ASSERT_PTR_EQUAL(properties->next, NULL); + CU_ASSERT_EQUAL(property__get_length_all(properties), 5); + property__free_all(&properties); + } + CU_ASSERT_PTR_EQUAL(properties, NULL); +} + + +static void int16_prop_write_helper( + int remaining_length, + int rc_expected, + int identifier, + uint16_t value_expected) +{ + struct mqtt5__property property; + struct mosquitto__packet packet; + struct mqtt5__property *properties; + int rc; + + memset(&property, 0, sizeof(struct mqtt5__property)); + + property.identifier = identifier; + property.value.i16 = value_expected; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.remaining_length = property__get_length_all(&property)+1; + packet.packet_length = packet.remaining_length+10; + packet.payload = calloc(packet.remaining_length+10, 1); + + property__write_all(&packet, &property); + packet.pos = 0; + + rc = property__read_all(&packet, &properties); + + CU_ASSERT_EQUAL(rc, rc_expected); + CU_ASSERT_EQUAL(packet.pos, remaining_length); + if(properties){ + CU_ASSERT_EQUAL(properties->identifier, identifier); + CU_ASSERT_EQUAL(properties->value.i16, value_expected); + CU_ASSERT_PTR_EQUAL(properties->next, NULL); + CU_ASSERT_EQUAL(property__get_length_all(properties), 3); + property__free_all(&properties); + } + CU_ASSERT_PTR_EQUAL(properties, NULL); +} + +static void string_prop_write_helper( + int remaining_length, + int rc_expected, + int identifier, + const char *value_expected) +{ + struct mqtt5__property property; + struct mosquitto__packet packet; + struct mqtt5__property *properties; + int rc; + + memset(&property, 0, sizeof(struct mqtt5__property)); + + property.identifier = identifier; + property.value.s.v = strdup(value_expected); + property.value.s.len = strlen(value_expected); + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.remaining_length = property__get_length_all(&property)+1; + packet.packet_length = packet.remaining_length+10; + packet.payload = calloc(packet.remaining_length+10, 1); + + property__write_all(&packet, &property); + packet.pos = 0; + + rc = property__read_all(&packet, &properties); + + CU_ASSERT_EQUAL(rc, rc_expected); + CU_ASSERT_EQUAL(packet.pos, remaining_length); + if(properties){ + CU_ASSERT_EQUAL(properties->identifier, identifier); + CU_ASSERT_EQUAL(properties->value.s.len, strlen(value_expected)); + CU_ASSERT_STRING_EQUAL(properties->value.s.v, value_expected); + CU_ASSERT_PTR_EQUAL(properties->next, NULL); + CU_ASSERT_EQUAL(property__get_length_all(properties), 1+2+strlen(value_expected)); + property__free_all(&properties); + } + CU_ASSERT_PTR_EQUAL(properties, NULL); + free(property.value.s.v); +} + + +static void binary_prop_write_helper( + int remaining_length, + int rc_expected, + int identifier, + const uint8_t *value_expected, + int len_expected) +{ + struct mqtt5__property property; + struct mosquitto__packet packet; + struct mqtt5__property *properties; + int rc; + + memset(&property, 0, sizeof(struct mqtt5__property)); + + property.identifier = identifier; + property.value.bin.v = malloc(len_expected); + memcpy(property.value.bin.v, value_expected, len_expected); + property.value.bin.len = len_expected; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.remaining_length = property__get_length_all(&property)+1; + packet.packet_length = packet.remaining_length+10; + packet.payload = calloc(packet.remaining_length+10, 1); + + property__write_all(&packet, &property); + packet.pos = 0; + + rc = property__read_all(&packet, &properties); + + CU_ASSERT_EQUAL(rc, rc_expected); + CU_ASSERT_EQUAL(packet.pos, remaining_length); + if(properties){ + CU_ASSERT_EQUAL(properties->identifier, identifier); + CU_ASSERT_EQUAL(properties->value.bin.len, len_expected); + CU_ASSERT_EQUAL(memcmp(properties->value.bin.v, value_expected, len_expected), 0); + CU_ASSERT_PTR_EQUAL(properties->next, NULL); + CU_ASSERT_EQUAL(property__get_length_all(properties), 1+2+len_expected); + property__free_all(&properties); + } + CU_ASSERT_PTR_EQUAL(properties, NULL); + free(property.value.bin.v); +} + +static void string_pair_prop_write_helper( + int remaining_length, + int rc_expected, + int identifier, + const char *name_expected, + const char *value_expected, + bool expect_multiple) +{ + struct mqtt5__property property; + struct mosquitto__packet packet; + struct mqtt5__property *properties; + int rc; + + memset(&property, 0, sizeof(struct mqtt5__property)); + + property.identifier = identifier; + property.value.s.v = strdup(value_expected); + property.value.s.len = strlen(value_expected); + property.name.v = strdup(name_expected); + property.name.len = strlen(name_expected); + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.remaining_length = property__get_length_all(&property)+1; + packet.packet_length = packet.remaining_length+10; + packet.payload = calloc(packet.remaining_length+10, 1); + + property__write_all(&packet, &property); + packet.pos = 0; + + rc = property__read_all(&packet, &properties); + + CU_ASSERT_EQUAL(rc, rc_expected); + CU_ASSERT_EQUAL(packet.pos, remaining_length); + if(properties){ + CU_ASSERT_EQUAL(properties->identifier, identifier); + CU_ASSERT_EQUAL(properties->name.len, strlen(name_expected)); + CU_ASSERT_EQUAL(properties->value.s.len, strlen(value_expected)); + CU_ASSERT_STRING_EQUAL(properties->name.v, name_expected); + CU_ASSERT_STRING_EQUAL(properties->value.s.v, value_expected); + if(expect_multiple){ + CU_ASSERT_PTR_NOT_NULL(properties->next); + }else{ + CU_ASSERT_PTR_NULL(properties->next); + CU_ASSERT_EQUAL(property__get_length_all(properties), 1+2+strlen(name_expected)+2+strlen(value_expected)); + } + property__free_all(&properties); + } + CU_ASSERT_PTR_NULL(properties); + free(property.value.s.v); + free(property.name.v); +} + +static void varint_prop_write_helper( + int remaining_length, + int rc_expected, + int identifier, + uint32_t value_expected) +{ + struct mqtt5__property property; + struct mosquitto__packet packet; + struct mqtt5__property *properties; + int rc; + + memset(&property, 0, sizeof(struct mqtt5__property)); + + property.identifier = identifier; + property.value.varint = value_expected; + + memset(&packet, 0, sizeof(struct mosquitto__packet)); + packet.remaining_length = property__get_length_all(&property)+1; + packet.packet_length = packet.remaining_length+10; + packet.payload = calloc(packet.remaining_length+10, 1); + + property__write_all(&packet, &property); + packet.pos = 0; + + rc = property__read_all(&packet, &properties); + + CU_ASSERT_EQUAL(rc, rc_expected); + if(properties){ + CU_ASSERT_EQUAL(properties->identifier, identifier); + CU_ASSERT_EQUAL(properties->value.varint, value_expected); + CU_ASSERT_PTR_NULL(properties->next); + if(value_expected < 128){ + CU_ASSERT_EQUAL(property__get_length_all(properties), 2); + }else if(value_expected < 16384){ + CU_ASSERT_EQUAL(property__get_length_all(properties), 3); + }else if(value_expected < 2097152){ + CU_ASSERT_EQUAL(property__get_length_all(properties), 4); + }else if(value_expected < 268435456){ + CU_ASSERT_EQUAL(property__get_length_all(properties), 5); + }else{ + CU_FAIL("Incorrect varint value."); + } + property__free_all(&properties); + } + CU_ASSERT_PTR_NULL(properties); +} + +/* ======================================================================== + * SINGLE PROPERTIES + * ======================================================================== */ + +static void TEST_single_payload_format_indicator(void) +{ + byte_prop_write_helper(3, MOSQ_ERR_SUCCESS, PROP_PAYLOAD_FORMAT_INDICATOR, 1); +} + +static void TEST_single_request_problem_information(void) +{ + byte_prop_write_helper(3, MOSQ_ERR_SUCCESS, PROP_REQUEST_PROBLEM_INFO, 1); +} + +static void TEST_single_request_response_information(void) +{ + byte_prop_write_helper(3, MOSQ_ERR_SUCCESS, PROP_REQUEST_RESPONSE_INFO, 1); +} + +static void TEST_single_maximum_qos(void) +{ + byte_prop_write_helper(3, MOSQ_ERR_SUCCESS, PROP_MAXIMUM_QOS, 1); +} + +static void TEST_single_retain_available(void) +{ + byte_prop_write_helper(3, MOSQ_ERR_SUCCESS, PROP_RETAIN_AVAILABLE, 1); +} + +static void TEST_single_wildcard_subscription_available(void) +{ + byte_prop_write_helper(3, MOSQ_ERR_SUCCESS, PROP_WILDCARD_SUB_AVAILABLE, 0); +} + +static void TEST_single_subscription_identifier_available(void) +{ + byte_prop_write_helper(3, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_ID_AVAILABLE, 0); +} + +static void TEST_single_shared_subscription_available(void) +{ + byte_prop_write_helper(3, MOSQ_ERR_SUCCESS, PROP_SHARED_SUB_AVAILABLE, 1); +} + +static void TEST_single_message_expiry_interval(void) +{ + int32_prop_write_helper(6, MOSQ_ERR_SUCCESS, PROP_MESSAGE_EXPIRY_INTERVAL, 0x12233445); +} + +static void TEST_single_session_expiry_interval(void) +{ + int32_prop_write_helper(6, MOSQ_ERR_SUCCESS, PROP_SESSION_EXPIRY_INTERVAL, 0x45342312); +} + +static void TEST_single_will_delay_interval(void) +{ + int32_prop_write_helper(6, MOSQ_ERR_SUCCESS, PROP_WILL_DELAY_INTERVAL, 0x45342312); +} + +static void TEST_single_maximum_packet_size(void) +{ + int32_prop_write_helper(6, MOSQ_ERR_SUCCESS, PROP_MAXIMUM_PACKET_SIZE, 0x45342312); +} + +static void TEST_single_server_keep_alive(void) +{ + int16_prop_write_helper(4, MOSQ_ERR_SUCCESS, PROP_SERVER_KEEP_ALIVE, 0x4534); +} + +static void TEST_single_receive_maximum(void) +{ + int16_prop_write_helper(4, MOSQ_ERR_SUCCESS, PROP_RECEIVE_MAXIMUM, 0x6842); +} + +static void TEST_single_topic_alias_maximum(void) +{ + int16_prop_write_helper(4, MOSQ_ERR_SUCCESS, PROP_TOPIC_ALIAS_MAXIMUM, 0x6842); +} + +static void TEST_single_topic_alias(void) +{ + int16_prop_write_helper(4, MOSQ_ERR_SUCCESS, PROP_TOPIC_ALIAS, 0x6842); +} + +static void TEST_single_content_type(void) +{ + string_prop_write_helper(9, MOSQ_ERR_SUCCESS, PROP_CONTENT_TYPE, "hello"); +} + +static void TEST_single_response_topic(void) +{ + string_prop_write_helper(9, MOSQ_ERR_SUCCESS, PROP_RESPONSE_TOPIC, "hello"); +} + +static void TEST_single_assigned_client_identifier(void) +{ + string_prop_write_helper(9, MOSQ_ERR_SUCCESS, PROP_ASSIGNED_CLIENT_IDENTIFIER, "hello"); +} + +static void TEST_single_authentication_method(void) +{ + string_prop_write_helper(9, MOSQ_ERR_SUCCESS, PROP_AUTHENTICATION_METHOD, "hello"); +} + +static void TEST_single_response_information(void) +{ + string_prop_write_helper(9, MOSQ_ERR_SUCCESS, PROP_RESPONSE_INFO, "hello"); +} + +static void TEST_single_server_reference(void) +{ + string_prop_write_helper(9, MOSQ_ERR_SUCCESS, PROP_SERVER_REFERENCE, "hello"); +} + +static void TEST_single_reason_string(void) +{ + string_prop_write_helper(9, MOSQ_ERR_SUCCESS, PROP_REASON_STRING, "hello"); +} + +static void TEST_single_correlation_data(void) +{ + uint8_t payload[5] = {1, 'e', 0, 'l', 9}; + + binary_prop_write_helper(9, MOSQ_ERR_SUCCESS, PROP_CORRELATION_DATA, payload, 5); +} + +static void TEST_single_authentication_data(void) +{ + uint8_t payload[5] = {1, 'e', 0, 'l', 9}; + + binary_prop_write_helper(9, MOSQ_ERR_SUCCESS, PROP_AUTHENTICATION_DATA, payload, 5); +} + +static void TEST_single_user_property(void) +{ + string_pair_prop_write_helper(10, MOSQ_ERR_SUCCESS, PROP_USER_PROPERTY, "za", "bc", false); +} + +static void TEST_single_subscription_identifier(void) +{ + varint_prop_write_helper(3, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 0); + varint_prop_write_helper(3, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 127); + varint_prop_write_helper(4, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 128); + varint_prop_write_helper(4, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 16383); + varint_prop_write_helper(5, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 16384); + varint_prop_write_helper(5, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 2097151); + varint_prop_write_helper(6, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 2097152); + varint_prop_write_helper(6, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 268435455); +} + + +/* ======================================================================== + * TEST SUITE SETUP + * ======================================================================== */ + +int init_property_write_tests(void) +{ + CU_pSuite test_suite = NULL; + + test_suite = CU_add_suite("Property write", NULL, NULL); + if(!test_suite){ + printf("Error adding CUnit Property write test suite.\n"); + return 1; + } + + if(0 + || !CU_add_test(test_suite, "Single Payload Format Indicator", TEST_single_payload_format_indicator) + || !CU_add_test(test_suite, "Single Request Problem Information", TEST_single_request_problem_information) + || !CU_add_test(test_suite, "Single Request Response Information", TEST_single_request_response_information) + || !CU_add_test(test_suite, "Single Maximum QoS", TEST_single_maximum_qos) + || !CU_add_test(test_suite, "Single Retain Available", TEST_single_retain_available) + || !CU_add_test(test_suite, "Single Wildcard Subscription Available", TEST_single_wildcard_subscription_available) + || !CU_add_test(test_suite, "Single Subscription Identifier Available", TEST_single_subscription_identifier_available) + || !CU_add_test(test_suite, "Single Shared Subscription Available", TEST_single_shared_subscription_available) + || !CU_add_test(test_suite, "Single Message Expiry Interval", TEST_single_message_expiry_interval) + || !CU_add_test(test_suite, "Single Session Expiry Interval", TEST_single_session_expiry_interval) + || !CU_add_test(test_suite, "Single Will Delay Interval", TEST_single_will_delay_interval) + || !CU_add_test(test_suite, "Single Maximum Packet Size", TEST_single_maximum_packet_size) + || !CU_add_test(test_suite, "Single Server Keep Alive", TEST_single_server_keep_alive) + || !CU_add_test(test_suite, "Single Receive Maximum", TEST_single_receive_maximum) + || !CU_add_test(test_suite, "Single Topic Alias Maximum", TEST_single_topic_alias_maximum) + || !CU_add_test(test_suite, "Single Topic Alias", TEST_single_topic_alias) + || !CU_add_test(test_suite, "Single Content Type", TEST_single_content_type) + || !CU_add_test(test_suite, "Single Response Topic", TEST_single_response_topic) + || !CU_add_test(test_suite, "Single Assigned Client Identifier", TEST_single_assigned_client_identifier) + || !CU_add_test(test_suite, "Single Authentication Method", TEST_single_authentication_method) + || !CU_add_test(test_suite, "Single Response Information", TEST_single_response_information) + || !CU_add_test(test_suite, "Single Server Reference", TEST_single_server_reference) + || !CU_add_test(test_suite, "Single Reason String", TEST_single_reason_string) + || !CU_add_test(test_suite, "Single Correlation Data", TEST_single_correlation_data) + || !CU_add_test(test_suite, "Single Authentication Data", TEST_single_authentication_data) + || !CU_add_test(test_suite, "Single User Property", TEST_single_user_property) + || !CU_add_test(test_suite, "Single Subscription Identifier", TEST_single_subscription_identifier) + ){ + + printf("Error adding Property read CUnit tests.\n"); + return 1; + } + + return 0; +} diff --git a/test/unit/test.c b/test/unit/test.c index 1b920ed69f..9e29f39132 100644 --- a/test/unit/test.c +++ b/test/unit/test.c @@ -6,6 +6,7 @@ int init_datatype_read_tests(void); int init_datatype_write_tests(void); int init_property_read_tests(void); +int init_property_write_tests(void); int init_utf8_tests(void); int init_util_topic_tests(void); @@ -22,6 +23,7 @@ int main(int argc, char *argv[]) || init_datatype_read_tests() || init_datatype_write_tests() || init_property_read_tests() + || init_property_write_tests() || init_util_topic_tests() ){ From 40ed672ecf95846600b772bc101e7a99d05105da Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 16 Oct 2018 22:49:13 +0100 Subject: [PATCH 053/254] Fix topic matching tests and function. --- lib/util_topic.c | 53 ++++++++++++++++++++----------------- test/unit/util_topic_test.c | 47 ++++++++++++++++++++------------ 2 files changed, 58 insertions(+), 42 deletions(-) diff --git a/lib/util_topic.c b/lib/util_topic.c index dccec306c3..45a2d311db 100644 --- a/lib/util_topic.c +++ b/lib/util_topic.c @@ -176,31 +176,10 @@ int mosquitto_topic_matches_sub2(const char *sub, size_t sublen, const char *top tpos = 0; while(spos < sublen && tpos <= topiclen){ - if(sub[spos] == topic[tpos]){ - if(tpos == topiclen-1){ - /* Check for e.g. foo matching foo/# */ - if(spos == sublen-3 - && sub[spos+1] == '/' - && sub[spos+2] == '#'){ - *result = true; - multilevel_wildcard = true; - return MOSQ_ERR_SUCCESS; - } - } - spos++; - tpos++; - if(spos == sublen && tpos == topiclen){ - *result = true; - return MOSQ_ERR_SUCCESS; - }else if(tpos == topiclen && spos == sublen-1 && sub[spos] == '+'){ - if(spos > 0 && sub[spos-1] != '/'){ - return MOSQ_ERR_INVAL; - } - spos++; - *result = true; - return MOSQ_ERR_SUCCESS; - } - }else{ + if(topic[tpos] == '+' || topic[tpos] == '#'){ + return MOSQ_ERR_INVAL; + } + if(sub[spos] != topic[tpos]){ if(sub[spos] == '+'){ /* Check for bad "+foo" or "a/+foo" subscription */ if(spos > 0 && sub[spos-1] != '/'){ @@ -244,6 +223,30 @@ int mosquitto_topic_matches_sub2(const char *sub, size_t sublen, const char *top } return MOSQ_ERR_SUCCESS; } + }else{ + if(tpos == topiclen-1){ + /* Check for e.g. foo matching foo/# */ + if(spos == sublen-3 + && sub[spos+1] == '/' + && sub[spos+2] == '#'){ + *result = true; + multilevel_wildcard = true; + return MOSQ_ERR_SUCCESS; + } + } + spos++; + tpos++; + if(spos == sublen && tpos == topiclen){ + *result = true; + return MOSQ_ERR_SUCCESS; + }else if(tpos == topiclen && spos == sublen-1 && sub[spos] == '+'){ + if(spos > 0 && sub[spos-1] != '/'){ + return MOSQ_ERR_INVAL; + } + spos++; + *result = true; + return MOSQ_ERR_SUCCESS; + } } } if(multilevel_wildcard == false && (tpos < topiclen || spos < sublen)){ diff --git a/test/unit/util_topic_test.c b/test/unit/util_topic_test.c index c843f861e7..6e5934a77d 100644 --- a/test/unit/util_topic_test.c +++ b/test/unit/util_topic_test.c @@ -85,7 +85,7 @@ static void TEST_empty_input(void) * VALID MATCHING AND NON-MATCHING * ======================================================================== */ -void TEST_valid_matching(void) +static void TEST_valid_matching(void) { match_helper("foo/#", "foo/"); match_helper("foo/#", "foo"); @@ -106,7 +106,7 @@ void TEST_valid_matching(void) } -void TEST_invalid_but_matching(void) +static void TEST_invalid_but_matching(void) { /* Matching here is "naive treatment of the wildcards would produce a * match". They shouldn't really match, they should fail. */ @@ -118,6 +118,14 @@ void TEST_invalid_but_matching(void) no_match_helper(MOSQ_ERR_INVAL, "foo/+bar", "foo/+bar"); no_match_helper(MOSQ_ERR_INVAL, "foo/bar+", "foo/bar+"); + no_match_helper(MOSQ_ERR_INVAL, "+foo", "afoo"); + no_match_helper(MOSQ_ERR_INVAL, "fo+o", "foao"); + no_match_helper(MOSQ_ERR_INVAL, "foo+", "fooa"); + no_match_helper(MOSQ_ERR_INVAL, "+foo/bar", "afoo/bar"); + no_match_helper(MOSQ_ERR_INVAL, "foo+/bar", "fooa/bar"); + no_match_helper(MOSQ_ERR_INVAL, "foo/+bar", "foo/abar"); + no_match_helper(MOSQ_ERR_INVAL, "foo/bar+", "foo/bara"); + no_match_helper(MOSQ_ERR_INVAL, "#foo", "#foo"); no_match_helper(MOSQ_ERR_INVAL, "fo#o", "fo#o"); no_match_helper(MOSQ_ERR_INVAL, "foo#", "foo#"); @@ -125,31 +133,35 @@ void TEST_invalid_but_matching(void) no_match_helper(MOSQ_ERR_INVAL, "foo#/bar", "foo#/bar"); no_match_helper(MOSQ_ERR_INVAL, "foo/#bar", "foo/#bar"); no_match_helper(MOSQ_ERR_INVAL, "foo/bar#", "foo/bar#"); + + no_match_helper(MOSQ_ERR_INVAL, "foo+", "fooa"); } -void TEST_valid_no_matching(void) +static void TEST_valid_no_matching(void) { - no_match_helper(MOSQ_ERR_INVAL, "foo#", "foo"); - no_match_helper(MOSQ_ERR_INVAL, "fo#o/", "foo"); - no_match_helper(MOSQ_ERR_INVAL, "foo#", "fooa"); - no_match_helper(MOSQ_ERR_INVAL, "foo+", "foo"); - no_match_helper(MOSQ_ERR_INVAL, "foo+", "fooa"); + no_match_helper(MOSQ_ERR_SUCCESS, "test/6/#", "test/3"); - no_match_helper(MOSQ_ERR_INVAL, "test/6/#", "test/3"); + no_match_helper(MOSQ_ERR_SUCCESS, "foo/bar", "foo"); + no_match_helper(MOSQ_ERR_SUCCESS, "foo/+", "foo/bar/baz"); + no_match_helper(MOSQ_ERR_SUCCESS, "foo/+/baz", "foo/bar/bar"); - no_match_helper(MOSQ_ERR_INVAL, "foo/bar", "foo"); - no_match_helper(MOSQ_ERR_INVAL, "foo/+", "foo/bar/baz"); - no_match_helper(MOSQ_ERR_INVAL, "foo/+/baz", "foo/bar/bar"); + no_match_helper(MOSQ_ERR_SUCCESS, "foo/+/#", "fo2/bar/baz"); - no_match_helper(MOSQ_ERR_INVAL, "foo/+/#", "fo2/bar/baz"); + no_match_helper(MOSQ_ERR_SUCCESS, "/#", "foo/bar"); + no_match_helper(MOSQ_ERR_SUCCESS, "/#a", "foo/bar"); - no_match_helper(MOSQ_ERR_INVAL, "/#", "foo/bar"); - no_match_helper(MOSQ_ERR_INVAL, "/#a", "foo/bar"); + no_match_helper(MOSQ_ERR_SUCCESS, "#", "$SYS/bar"); + no_match_helper(MOSQ_ERR_SUCCESS, "$BOB/bar", "$SYS/bar"); +} - no_match_helper(MOSQ_ERR_INVAL, "#", "$SYS/bar"); - no_match_helper(MOSQ_ERR_INVAL, "$BOB/bar", "$SYS/bar"); +static void TEST_invalid(void) +{ + no_match_helper(MOSQ_ERR_INVAL, "foo#", "foo"); + no_match_helper(MOSQ_ERR_INVAL, "fo#o/", "foo"); + no_match_helper(MOSQ_ERR_INVAL, "foo#", "fooa"); + no_match_helper(MOSQ_ERR_INVAL, "foo+", "foo"); } /* ======================================================================== @@ -171,6 +183,7 @@ int init_util_topic_tests(void) || !CU_add_test(test_suite, "Valid matching", TEST_valid_matching) || !CU_add_test(test_suite, "Valid no matching", TEST_valid_no_matching) || !CU_add_test(test_suite, "Invalid but matching", TEST_invalid_but_matching) + || !CU_add_test(test_suite, "Invalid", TEST_invalid) ){ printf("Error adding util topic CUnit tests.\n"); From 1e9e552034d0f5578cad4b4c86710d2d5ac485fd Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 16 Oct 2018 22:57:52 +0100 Subject: [PATCH 054/254] Property write bad identifier test. --- test/unit/property_write.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/unit/property_write.c b/test/unit/property_write.c index 4fca1d5c79..dae5282910 100644 --- a/test/unit/property_write.c +++ b/test/unit/property_write.c @@ -305,6 +305,28 @@ static void varint_prop_write_helper( CU_ASSERT_PTR_NULL(properties); } +/* ======================================================================== + * BAD IDENTIFIER + * ======================================================================== */ + +static void TEST_bad_identifier(void) +{ + struct mqtt5__property property; + struct mosquitto__packet packet; + uint8_t payload[10]; + int rc; + + memset(&property, 0, sizeof(struct mqtt5__property)); + memset(&packet, 0, sizeof(struct mosquitto__packet)); + property.identifier = 0xFFFF; + packet.packet_length = 10; + packet.remaining_length = 8; + packet.payload = payload; + rc = property__write_all(&packet, &property); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); +} + + /* ======================================================================== * SINGLE PROPERTIES * ======================================================================== */ @@ -471,6 +493,7 @@ int init_property_write_tests(void) } if(0 + || !CU_add_test(test_suite, "Bad identifier", TEST_bad_identifier) || !CU_add_test(test_suite, "Single Payload Format Indicator", TEST_single_payload_format_indicator) || !CU_add_test(test_suite, "Single Request Problem Information", TEST_single_request_problem_information) || !CU_add_test(test_suite, "Single Request Response Information", TEST_single_request_response_information) From 42896112a1303c2360b77469a38b15c6b0cc87d0 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 16 Oct 2018 23:09:08 +0100 Subject: [PATCH 055/254] Pub/sub topic checking tests. --- test/unit/util_topic_test.c | 96 +++++++++++++++++++++++++++++++++++-- 1 file changed, 91 insertions(+), 5 deletions(-) diff --git a/test/unit/util_topic_test.c b/test/unit/util_topic_test.c index 6e5934a77d..39900826ec 100644 --- a/test/unit/util_topic_test.c +++ b/test/unit/util_topic_test.c @@ -164,6 +164,88 @@ static void TEST_invalid(void) no_match_helper(MOSQ_ERR_INVAL, "foo+", "foo"); } +/* ======================================================================== + * PUB TOPIC CHECK + * ======================================================================== */ + +static void pub_topic_helper(const char *topic, int rc_expected) +{ + int rc; + + rc = mosquitto_pub_topic_check(topic); + CU_ASSERT_EQUAL(rc, rc_expected); + + rc = mosquitto_pub_topic_check2(topic, strlen(topic)); + CU_ASSERT_EQUAL(rc, rc_expected); +} + +static void TEST_pub_topic_valid(void) +{ + pub_topic_helper("pub/topic", MOSQ_ERR_SUCCESS); + pub_topic_helper("pub//topic", MOSQ_ERR_SUCCESS); + pub_topic_helper("pub/ /topic", MOSQ_ERR_SUCCESS); +} + +static void TEST_pub_topic_invalid(void) +{ + pub_topic_helper("+pub/topic", MOSQ_ERR_INVAL); + pub_topic_helper("pub+/topic", MOSQ_ERR_INVAL); + pub_topic_helper("pub/+topic", MOSQ_ERR_INVAL); + pub_topic_helper("pub/topic+", MOSQ_ERR_INVAL); + pub_topic_helper("pub/topic/+", MOSQ_ERR_INVAL); + pub_topic_helper("#pub/topic", MOSQ_ERR_INVAL); + pub_topic_helper("pub#/topic", MOSQ_ERR_INVAL); + pub_topic_helper("pub/#topic", MOSQ_ERR_INVAL); + pub_topic_helper("pub/topic#", MOSQ_ERR_INVAL); + pub_topic_helper("pub/topic/#", MOSQ_ERR_INVAL); + pub_topic_helper("+/pub/topic", MOSQ_ERR_INVAL); +} + + +/* ======================================================================== + * SUB TOPIC CHECK + * ======================================================================== */ + +static void sub_topic_helper(const char *topic, int rc_expected) +{ + int rc; + + rc = mosquitto_sub_topic_check(topic); + CU_ASSERT_EQUAL(rc, rc_expected); + + rc = mosquitto_sub_topic_check2(topic, strlen(topic)); + CU_ASSERT_EQUAL(rc, rc_expected); +} + +static void TEST_sub_topic_valid(void) +{ + sub_topic_helper("sub/topic", MOSQ_ERR_SUCCESS); + sub_topic_helper("sub//topic", MOSQ_ERR_SUCCESS); + sub_topic_helper("sub/ /topic", MOSQ_ERR_SUCCESS); + sub_topic_helper("sub/+/topic", MOSQ_ERR_SUCCESS); + sub_topic_helper("+/+/+", MOSQ_ERR_SUCCESS); + sub_topic_helper("+", MOSQ_ERR_SUCCESS); + sub_topic_helper("sub/topic/#", MOSQ_ERR_SUCCESS); + sub_topic_helper("sub//topic/#", MOSQ_ERR_SUCCESS); + sub_topic_helper("sub/ /topic/#", MOSQ_ERR_SUCCESS); + sub_topic_helper("sub/+/topic/#", MOSQ_ERR_SUCCESS); + sub_topic_helper("+/+/+/#", MOSQ_ERR_SUCCESS); + sub_topic_helper("#", MOSQ_ERR_SUCCESS); +} + +static void TEST_sub_topic_invalid(void) +{ + sub_topic_helper("+sub/topic", MOSQ_ERR_INVAL); + sub_topic_helper("sub+/topic", MOSQ_ERR_INVAL); + sub_topic_helper("sub/+topic", MOSQ_ERR_INVAL); + sub_topic_helper("sub/topic+", MOSQ_ERR_INVAL); + sub_topic_helper("#sub/topic", MOSQ_ERR_INVAL); + sub_topic_helper("sub#/topic", MOSQ_ERR_INVAL); + sub_topic_helper("sub/#topic", MOSQ_ERR_INVAL); + sub_topic_helper("sub/topic#", MOSQ_ERR_INVAL); + sub_topic_helper("#/sub/topic", MOSQ_ERR_INVAL); +} + /* ======================================================================== * TEST SUITE SETUP * ======================================================================== */ @@ -179,11 +261,15 @@ int init_util_topic_tests(void) } if(0 - || !CU_add_test(test_suite, "Empty input", TEST_empty_input) - || !CU_add_test(test_suite, "Valid matching", TEST_valid_matching) - || !CU_add_test(test_suite, "Valid no matching", TEST_valid_no_matching) - || !CU_add_test(test_suite, "Invalid but matching", TEST_invalid_but_matching) - || !CU_add_test(test_suite, "Invalid", TEST_invalid) + || !CU_add_test(test_suite, "Matching: Empty input", TEST_empty_input) + || !CU_add_test(test_suite, "Matching: Valid matching", TEST_valid_matching) + || !CU_add_test(test_suite, "Matching: Valid no matching", TEST_valid_no_matching) + || !CU_add_test(test_suite, "Matching: Invalid but matching", TEST_invalid_but_matching) + || !CU_add_test(test_suite, "Matching: Invalid", TEST_invalid) + || !CU_add_test(test_suite, "Pub topic: Valid", TEST_pub_topic_valid) + || !CU_add_test(test_suite, "Pub topic: Invalid", TEST_pub_topic_invalid) + || !CU_add_test(test_suite, "Sub topic: Valid", TEST_sub_topic_valid) + || !CU_add_test(test_suite, "Sub topic: Invalid", TEST_sub_topic_invalid) ){ printf("Error adding util topic CUnit tests.\n"); From 0baf358cf85aec2403f300b5515f3d5e04c5f6a1 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 24 Oct 2018 14:07:09 +0100 Subject: [PATCH 056/254] Add properties member to will struct. --- lib/mosquitto_internal.h | 3 ++- lib/send_connect.c | 12 ++++++------ lib/will_mosq.c | 36 ++++++++++++++++++------------------ src/context.c | 21 ++++++++++++++++----- src/handle_connect.c | 26 +++++++++++++++----------- 5 files changed, 57 insertions(+), 41 deletions(-) diff --git a/lib/mosquitto_internal.h b/lib/mosquitto_internal.h index 9ca1aa23af..2fac25bad2 100644 --- a/lib/mosquitto_internal.h +++ b/lib/mosquitto_internal.h @@ -147,6 +147,7 @@ struct mosquitto__packet{ struct mosquitto_message_all{ struct mosquitto_message_all *next; + struct mqtt5__property *properties; time_t timestamp; //enum mosquitto_msg_direction direction; enum mosquitto_msg_state state; @@ -176,7 +177,7 @@ struct mosquitto { struct mosquitto__packet in_packet; struct mosquitto__packet *current_out_packet; struct mosquitto__packet *out_packet; - struct mosquitto_message *will; + struct mosquitto_message_all *will; #ifdef WITH_TLS SSL *ssl; SSL_CTX *ssl_ctx; diff --git a/lib/send_connect.c b/lib/send_connect.c index 5f6b380645..5231de784f 100644 --- a/lib/send_connect.c +++ b/lib/send_connect.c @@ -80,9 +80,9 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session payloadlen = 2+strlen(clientid); if(mosq->will){ will = 1; - assert(mosq->will->topic); + assert(mosq->will->msg.topic); - payloadlen += 2+strlen(mosq->will->topic) + 2+mosq->will->payloadlen; + payloadlen += 2+strlen(mosq->will->msg.topic) + 2+mosq->will->msg.payloadlen; if(mosq->protocol == mosq_p_mqtt5){ payloadlen += 1; } @@ -117,7 +117,7 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session packet__write_byte(packet, version); byte = (clean_session&0x1)<<1; if(will){ - byte = byte | ((mosq->will->retain&0x1)<<5) | ((mosq->will->qos&0x3)<<3) | ((will&0x1)<<2); + byte = byte | ((mosq->will->msg.retain&0x1)<<5) | ((mosq->will->msg.qos&0x3)<<3) | ((will&0x1)<<2); } if(username){ byte = byte | 0x1<<7; @@ -130,7 +130,7 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session if(mosq->protocol == mosq_p_mqtt5){ /* Write properties */ - property__write_all(packet, NULL); + property__write_all(packet, mosq->will->properties); } /* Payload */ @@ -140,8 +140,8 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session /* Write will properties */ property__write_all(packet, NULL); } - packet__write_string(packet, mosq->will->topic, strlen(mosq->will->topic)); - packet__write_string(packet, (const char *)mosq->will->payload, mosq->will->payloadlen); + packet__write_string(packet, mosq->will->msg.topic, strlen(mosq->will->msg.topic)); + packet__write_string(packet, (const char *)mosq->will->msg.payload, mosq->will->msg.payloadlen); } if(username){ packet__write_string(packet, username, strlen(username)); diff --git a/lib/will_mosq.c b/lib/will_mosq.c index fe5a0443ef..7062b5126a 100644 --- a/lib/will_mosq.c +++ b/lib/will_mosq.c @@ -46,41 +46,41 @@ int will__set(struct mosquitto *mosq, const char *topic, int payloadlen, const v if(mosquitto_validate_utf8(topic, strlen(topic))) return MOSQ_ERR_MALFORMED_UTF8; if(mosq->will){ - mosquitto__free(mosq->will->topic); - mosquitto__free(mosq->will->payload); + mosquitto__free(mosq->will->msg.topic); + mosquitto__free(mosq->will->msg.payload); mosquitto__free(mosq->will); } - mosq->will = mosquitto__calloc(1, sizeof(struct mosquitto_message)); + mosq->will = mosquitto__calloc(1, sizeof(struct mosquitto_message_all)); if(!mosq->will) return MOSQ_ERR_NOMEM; - mosq->will->topic = mosquitto__strdup(topic); - if(!mosq->will->topic){ + mosq->will->msg.topic = mosquitto__strdup(topic); + if(!mosq->will->msg.topic){ rc = MOSQ_ERR_NOMEM; goto cleanup; } - mosq->will->payloadlen = payloadlen; - if(mosq->will->payloadlen > 0){ + mosq->will->msg.payloadlen = payloadlen; + if(mosq->will->msg.payloadlen > 0){ if(!payload){ rc = MOSQ_ERR_INVAL; goto cleanup; } - mosq->will->payload = mosquitto__malloc(sizeof(char)*mosq->will->payloadlen); - if(!mosq->will->payload){ + mosq->will->msg.payload = mosquitto__malloc(sizeof(char)*mosq->will->msg.payloadlen); + if(!mosq->will->msg.payload){ rc = MOSQ_ERR_NOMEM; goto cleanup; } - memcpy(mosq->will->payload, payload, payloadlen); + memcpy(mosq->will->msg.payload, payload, payloadlen); } - mosq->will->qos = qos; - mosq->will->retain = retain; + mosq->will->msg.qos = qos; + mosq->will->msg.retain = retain; return MOSQ_ERR_SUCCESS; cleanup: if(mosq->will){ - mosquitto__free(mosq->will->topic); - mosquitto__free(mosq->will->payload); + mosquitto__free(mosq->will->msg.topic); + mosquitto__free(mosq->will->msg.payload); mosquitto__free(mosq->will); mosq->will = NULL; @@ -93,11 +93,11 @@ int will__clear(struct mosquitto *mosq) { if(!mosq->will) return MOSQ_ERR_SUCCESS; - mosquitto__free(mosq->will->topic); - mosq->will->topic = NULL; + mosquitto__free(mosq->will->msg.topic); + mosq->will->msg.topic = NULL; - mosquitto__free(mosq->will->payload); - mosq->will->payload = NULL; + mosquitto__free(mosq->will->msg.payload); + mosq->will->msg.payload = NULL; mosquitto__free(mosq->will); mosq->will = NULL; diff --git a/src/context.c b/src/context.c index 1d3ae1633e..549c05fb70 100644 --- a/src/context.c +++ b/src/context.c @@ -206,15 +206,26 @@ void context__cleanup(struct mosquitto_db *db, struct mosquitto *context, bool d void context__send_will(struct mosquitto_db *db, struct mosquitto *ctxt) { if(ctxt->state != mosq_cs_disconnecting && ctxt->will){ - if(mosquitto_acl_check(db, ctxt, ctxt->will->topic, ctxt->will->payloadlen, ctxt->will->payload, - ctxt->will->qos, ctxt->will->retain, MOSQ_ACL_WRITE) == MOSQ_ERR_SUCCESS){ + if(mosquitto_acl_check(db, ctxt, + ctxt->will->msg.topic, + ctxt->will->msg.payloadlen, + ctxt->will->msg.payload, + ctxt->will->msg.qos, + ctxt->will->msg.retain, + MOSQ_ACL_WRITE) == MOSQ_ERR_SUCCESS){ + /* Unexpected disconnect, queue the client will. */ - db__messages_easy_queue(db, ctxt, ctxt->will->topic, ctxt->will->qos, ctxt->will->payloadlen, ctxt->will->payload, ctxt->will->retain); + db__messages_easy_queue(db, ctxt, + ctxt->will->msg.topic, + ctxt->will->msg.qos, + ctxt->will->msg.payloadlen, + ctxt->will->msg.payload, + ctxt->will->msg.retain); } } if(ctxt->will){ - mosquitto__free(ctxt->will->topic); - mosquitto__free(ctxt->will->payload); + mosquitto__free(ctxt->will->msg.topic); + mosquitto__free(ctxt->will->msg.payload); mosquitto__free(ctxt->will); ctxt->will = NULL; } diff --git a/src/handle_connect.c b/src/handle_connect.c index 18fd59f011..2dfbd0ad3a 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -119,7 +119,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) char *will_payload = NULL, *will_topic = NULL; char *will_topic_mount; uint16_t will_payloadlen; - struct mosquitto_message *will_struct = NULL; + struct mosquitto_message_all *will_struct = NULL; uint8_t will, will_retain, will_qos, clean_session; uint8_t username_flag, password_flag; char *username = NULL, *password = NULL; @@ -296,7 +296,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) } if(will){ - will_struct = mosquitto__calloc(1, sizeof(struct mosquitto_message)); + will_struct = mosquitto__calloc(1, sizeof(struct mosquitto_message_all)); if(!will_struct){ rc = MOSQ_ERR_NOMEM; goto handle_connect_error; @@ -643,16 +643,16 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) if(will_struct){ context->will = will_struct; - context->will->topic = will_topic; + context->will->msg.topic = will_topic; if(will_payload){ - context->will->payload = will_payload; - context->will->payloadlen = will_payloadlen; + context->will->msg.payload = will_payload; + context->will->msg.payloadlen = will_payloadlen; }else{ - context->will->payload = NULL; - context->will->payloadlen = 0; + context->will->msg.payload = NULL; + context->will->msg.payloadlen = 0; } - context->will->qos = will_qos; - context->will->retain = will_retain; + context->will->msg.qos = will_qos; + context->will->msg.retain = will_retain; } if(db->config->connection_messages == true){ @@ -671,8 +671,12 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) } if(context->will) { - log__printf(NULL, MOSQ_LOG_DEBUG, "Will message specified (%ld bytes) (r%d, q%d).", (long)context->will->payloadlen, context->will->retain, context->will->qos); - log__printf(NULL, MOSQ_LOG_DEBUG, "\t%s", context->will->topic); + log__printf(NULL, MOSQ_LOG_DEBUG, "Will message specified (%ld bytes) (r%d, q%d).", + (long)context->will->msg.payloadlen, + context->will->msg.retain, + context->will->msg.qos); + + log__printf(NULL, MOSQ_LOG_DEBUG, "\t%s", context->will->msg.topic); } else { log__printf(NULL, MOSQ_LOG_DEBUG, "No will message specified."); } From 267178bd993878d5a36baeb6e7af00d979cb4ebb Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 25 Oct 2018 10:24:19 +0100 Subject: [PATCH 057/254] User properties are copied from PUBLISH to PUBLISH. --- lib/actions.c | 4 +-- lib/messages_mosq.c | 4 +-- lib/packet_datatypes.c | 16 ++++++++++ lib/packet_mosq.h | 2 ++ lib/send_mosq.h | 4 +-- lib/send_publish.c | 21 +++++++++---- src/bridge.c | 8 ++--- src/context.c | 5 ++- src/database.c | 24 ++++++++++----- src/handle_connack.c | 8 ++--- src/handle_connect.c | 9 +++--- src/handle_publish.c | 13 +++++--- src/handle_subscribe.c | 9 ++++++ src/logging.c | 4 +-- src/mosquitto_broker_internal.h | 5 +-- src/persist.c | 2 +- src/sys_tree.c | 54 ++++++++++++++++----------------- 17 files changed, 124 insertions(+), 68 deletions(-) diff --git a/lib/actions.c b/lib/actions.c index c8f966a6b7..7a48f3cc26 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -49,7 +49,7 @@ int mosquitto_publish(struct mosquitto *mosq, int *mid, const char *topic, int p } if(qos == 0){ - return send__publish(mosq, local_mid, topic, payloadlen, payload, qos, retain, false); + return send__publish(mosq, local_mid, topic, payloadlen, payload, qos, retain, false, NULL); }else{ message = mosquitto__calloc(1, sizeof(struct mosquitto_message_all)); if(!message) return MOSQ_ERR_NOMEM; @@ -87,7 +87,7 @@ int mosquitto_publish(struct mosquitto *mosq, int *mid, const char *topic, int p message->state = mosq_ms_wait_for_pubrec; } pthread_mutex_unlock(&mosq->out_message_mutex); - return send__publish(mosq, message->msg.mid, message->msg.topic, message->msg.payloadlen, message->msg.payload, message->msg.qos, message->msg.retain, message->dup); + return send__publish(mosq, message->msg.mid, message->msg.topic, message->msg.payloadlen, message->msg.payload, message->msg.qos, message->msg.retain, message->dup, NULL); }else{ message->state = mosq_ms_invalid; pthread_mutex_unlock(&mosq->out_message_mutex); diff --git a/lib/messages_mosq.c b/lib/messages_mosq.c index f6c50b8bc5..2a737d9b77 100644 --- a/lib/messages_mosq.c +++ b/lib/messages_mosq.c @@ -264,7 +264,7 @@ int message__remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_dir }else if(cur->msg.qos == 2){ cur->state = mosq_ms_wait_for_pubrec; } - rc = send__publish(mosq, cur->msg.mid, cur->msg.topic, cur->msg.payloadlen, cur->msg.payload, cur->msg.qos, cur->msg.retain, cur->dup); + rc = send__publish(mosq, cur->msg.mid, cur->msg.topic, cur->msg.payloadlen, cur->msg.payload, cur->msg.qos, cur->msg.retain, cur->dup, NULL); if(rc){ pthread_mutex_unlock(&mosq->out_message_mutex); return rc; @@ -334,7 +334,7 @@ void message__retry_check_actual(struct mosquitto *mosq, struct mosquitto_messag case mosq_ms_publish_qos2: messages->timestamp = now; messages->dup = true; - send__publish(mosq, messages->msg.mid, messages->msg.topic, messages->msg.payloadlen, messages->msg.payload, messages->msg.qos, messages->msg.retain, messages->dup); + send__publish(mosq, messages->msg.mid, messages->msg.topic, messages->msg.payloadlen, messages->msg.payload, messages->msg.qos, messages->msg.retain, messages->dup, NULL); break; case mosq_ms_wait_for_pubrel: messages->timestamp = now; diff --git a/lib/packet_datatypes.c b/lib/packet_datatypes.c index 1b0abeeb97..9297afe6e7 100644 --- a/lib/packet_datatypes.c +++ b/lib/packet_datatypes.c @@ -247,3 +247,19 @@ int packet__write_varint(struct mosquitto__packet *packet, int32_t word) } return MOSQ_ERR_SUCCESS; } + + +int packet__varint_bytes(int32_t word) +{ + if(word < 128){ + return 1; + }else if(word < 16384){ + return 2; + }else if(word < 2097152){ + return 3; + }else if(word < 268435456){ + return 4; + }else{ + return 5; + } +} diff --git a/lib/packet_mosq.h b/lib/packet_mosq.h index 04855327f9..22728cd79d 100644 --- a/lib/packet_mosq.h +++ b/lib/packet_mosq.h @@ -42,6 +42,8 @@ void packet__write_uint16(struct mosquitto__packet *packet, uint16_t word); void packet__write_uint32(struct mosquitto__packet *packet, uint32_t word); int packet__write_varint(struct mosquitto__packet *packet, int32_t word); +int packet__varint_bytes(int32_t word); + int packet__write(struct mosquitto *mosq); #ifdef WITH_BROKER int packet__read(struct mosquitto_db *db, struct mosquitto *mosq); diff --git a/lib/send_mosq.h b/lib/send_mosq.h index 1bac1d3041..7ea0b12bb3 100644 --- a/lib/send_mosq.h +++ b/lib/send_mosq.h @@ -21,7 +21,7 @@ and the Eclipse Distribution License is available at int send__simple_command(struct mosquitto *mosq, uint8_t command); int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup, struct mqtt5__property *properties); -int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup); +int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, struct mqtt5__property *properties); int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session); int send__disconnect(struct mosquitto *mosq); @@ -29,7 +29,7 @@ int send__pingreq(struct mosquitto *mosq); int send__pingresp(struct mosquitto *mosq); int send__puback(struct mosquitto *mosq, uint16_t mid); int send__pubcomp(struct mosquitto *mosq, uint16_t mid); -int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup); +int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, struct mqtt5__property *properties); int send__pubrec(struct mosquitto *mosq, uint16_t mid); int send__pubrel(struct mosquitto *mosq, uint16_t mid); int send__subscribe(struct mosquitto *mosq, int *mid, int topic_count, char *const *const topic, int topic_qos); diff --git a/lib/send_publish.c b/lib/send_publish.c index 3df0909b6f..2cd703c756 100644 --- a/lib/send_publish.c +++ b/lib/send_publish.c @@ -37,7 +37,7 @@ and the Eclipse Distribution License is available at #include "send_mosq.h" -int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup) +int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, struct mqtt5__property *properties) { #ifdef WITH_BROKER size_t len; @@ -111,7 +111,7 @@ int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint3 } log__printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBLISH to %s (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes))", mosq->id, dup, qos, retain, mid, mapped_topic, (long)payloadlen); G_PUB_BYTES_SENT_INC(payloadlen); - rc = send__real_publish(mosq, mid, mapped_topic, payloadlen, payload, qos, retain, dup); + rc = send__real_publish(mosq, mid, mapped_topic, payloadlen, payload, qos, retain, dup, properties); mosquitto__free(mapped_topic); return rc; } @@ -125,14 +125,16 @@ int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint3 log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBLISH (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes))", mosq->id, dup, qos, retain, mid, topic, (long)payloadlen); #endif - return send__real_publish(mosq, mid, topic, payloadlen, payload, qos, retain, dup); + return send__real_publish(mosq, mid, topic, payloadlen, payload, qos, retain, dup, properties); } -int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup) +int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, struct mqtt5__property *properties) { struct mosquitto__packet *packet = NULL; int packetlen; + int proplen; + int varlen; int rc; assert(mosq); @@ -141,7 +143,14 @@ int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, packetlen = 2+strlen(topic) + payloadlen; if(qos > 0) packetlen += 2; /* For message id */ if(mosq->protocol == mosq_p_mqtt5){ - packetlen += 1; + proplen = property__get_length_all(properties); + varlen = packet__varint_bytes(proplen); + if(varlen > 4){ + /* FIXME - Properties too big, don't publish any - should remove some first really */ + properties = NULL; + }else{ + packetlen += proplen + varlen; + } } packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet)); if(!packet) return MOSQ_ERR_NOMEM; @@ -161,7 +170,7 @@ int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, } if(mosq->protocol == mosq_p_mqtt5){ - property__write_all(packet, NULL); + property__write_all(packet, properties); } /* Payload */ diff --git a/src/bridge.c b/src/bridge.c index a3f2ed7dd5..77ccf34123 100644 --- a/src/bridge.c +++ b/src/bridge.c @@ -155,7 +155,7 @@ int bridge__connect_step1(struct mosquitto_db *db, struct mosquitto *context) if(context->bridge->notification_topic){ if(!context->bridge->initial_notification_done){ notification_payload = '0'; - db__messages_easy_queue(db, context, context->bridge->notification_topic, 1, 1, ¬ification_payload, 1); + db__messages_easy_queue(db, context, context->bridge->notification_topic, 1, 1, ¬ification_payload, 1, NULL); context->bridge->initial_notification_done = true; } notification_payload = '0'; @@ -172,7 +172,7 @@ int bridge__connect_step1(struct mosquitto_db *db, struct mosquitto *context) if(!context->bridge->initial_notification_done){ notification_payload = '0'; - db__messages_easy_queue(db, context, notification_topic, 1, 1, ¬ification_payload, 1); + db__messages_easy_queue(db, context, notification_topic, 1, 1, ¬ification_payload, 1, NULL); context->bridge->initial_notification_done = true; } @@ -321,7 +321,7 @@ int bridge__connect(struct mosquitto_db *db, struct mosquitto *context) if(context->bridge->notification_topic){ if(!context->bridge->initial_notification_done){ notification_payload = '0'; - db__messages_easy_queue(db, context, context->bridge->notification_topic, 1, 1, ¬ification_payload, 1); + db__messages_easy_queue(db, context, context->bridge->notification_topic, 1, 1, ¬ification_payload, 1, NULL); context->bridge->initial_notification_done = true; } @@ -341,7 +341,7 @@ int bridge__connect(struct mosquitto_db *db, struct mosquitto *context) if(!context->bridge->initial_notification_done){ notification_payload = '0'; - db__messages_easy_queue(db, context, notification_topic, 1, 1, ¬ification_payload, 1); + db__messages_easy_queue(db, context, notification_topic, 1, 1, ¬ification_payload, 1, NULL); context->bridge->initial_notification_done = true; } diff --git a/src/context.c b/src/context.c index 549c05fb70..f4fe9a43ce 100644 --- a/src/context.c +++ b/src/context.c @@ -22,6 +22,7 @@ and the Eclipse Distribution License is available at #include "mosquitto_broker_internal.h" #include "memory_mosq.h" #include "packet_mosq.h" +#include "property_mosq.h" #include "time_mosq.h" #include "uthash.h" @@ -220,10 +221,12 @@ void context__send_will(struct mosquitto_db *db, struct mosquitto *ctxt) ctxt->will->msg.qos, ctxt->will->msg.payloadlen, ctxt->will->msg.payload, - ctxt->will->msg.retain); + ctxt->will->msg.retain, + &ctxt->will->properties); } } if(ctxt->will){ + property__free_all(&ctxt->will->properties); mosquitto__free(ctxt->will->msg.topic); mosquitto__free(ctxt->will->msg.payload); mosquitto__free(ctxt->will); diff --git a/src/database.c b/src/database.c index d2f482d1b6..1595be214f 100644 --- a/src/database.c +++ b/src/database.c @@ -207,6 +207,7 @@ void db__msg_store_remove(struct mosquitto_db *db, struct mosquitto_msg_store *s mosquitto__free(store->dest_ids); } mosquitto__free(store->topic); + property__free_all(&store->properties); UHPA_FREE_PAYLOAD(store); mosquitto__free(store); } @@ -558,12 +559,13 @@ int db__messages_delete(struct mosquitto_db *db, struct mosquitto *context) return MOSQ_ERR_SUCCESS; } -int db__messages_easy_queue(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int qos, uint32_t payloadlen, const void *payload, int retain) +int db__messages_easy_queue(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int qos, uint32_t payloadlen, const void *payload, int retain, struct mqtt5__property **properties) { struct mosquitto_msg_store *stored; char *source_id; char *topic_heap; mosquitto__payload_uhpa payload_uhpa; + struct mqtt5__property *local_properties = NULL; assert(db); @@ -584,13 +586,17 @@ int db__messages_easy_queue(struct mosquitto_db *db, struct mosquitto *context, }else{ source_id = ""; } - if(db__message_store(db, source_id, 0, topic_heap, qos, payloadlen, &payload_uhpa, retain, &stored, 0)) return 1; + if(properties){ + local_properties = *properties; + *properties = NULL; + } + if(db__message_store(db, source_id, 0, topic_heap, qos, payloadlen, &payload_uhpa, retain, &stored, local_properties, 0)) return 1; return sub__messages_queue(db, source_id, topic_heap, qos, retain, &stored); } -/* This function requires topic to be allocated on the heap. Once called, it owns topic and will free it on error. Likewise payload. */ -int db__message_store(struct mosquitto_db *db, const char *source, uint16_t source_mid, char *topic, int qos, uint32_t payloadlen, mosquitto__payload_uhpa *payload, int retain, struct mosquitto_msg_store **stored, dbid_t store_id) +/* This function requires topic to be allocated on the heap. Once called, it owns topic and will free it on error. Likewise payload and properties. */ +int db__message_store(struct mosquitto_db *db, const char *source, uint16_t source_mid, char *topic, int qos, uint32_t payloadlen, mosquitto__payload_uhpa *payload, int retain, struct mosquitto_msg_store **stored, struct mqtt5__property *properties, dbid_t store_id) { struct mosquitto_msg_store *temp = NULL; int rc = MOSQ_ERR_SUCCESS; @@ -626,6 +632,7 @@ int db__message_store(struct mosquitto_db *db, const char *source, uint16_t sour temp->topic = topic; topic = NULL; temp->payloadlen = payloadlen; + temp->properties = properties; if(payloadlen){ UHPA_MOVE(temp->payload, *payload, payloadlen); }else{ @@ -654,6 +661,7 @@ int db__message_store(struct mosquitto_db *db, const char *source, uint16_t sour mosquitto__free(temp->topic); mosquitto__free(temp); } + property__free_all(&properties); return rc; } @@ -858,6 +866,7 @@ int db__message_write(struct mosquitto_db *db, struct mosquitto *context) uint32_t payloadlen; const void *payload; int msg_count = 0; + struct mqtt5__property *properties; if(!context || context->sock == INVALID_SOCKET || (context->state == mosq_cs_connected && !context->id)){ @@ -878,10 +887,11 @@ int db__message_write(struct mosquitto_db *db, struct mosquitto *context) qos = tail->qos; payloadlen = tail->store->payloadlen; payload = UHPA_ACCESS_PAYLOAD(tail->store); + properties = tail->store->properties; switch(tail->state){ case mosq_ms_publish_qos0: - rc = send__publish(context, mid, topic, payloadlen, payload, qos, retain, retries); + rc = send__publish(context, mid, topic, payloadlen, payload, qos, retain, retries, properties); if(!rc){ db__message_remove(db, context, &tail, last); }else{ @@ -890,7 +900,7 @@ int db__message_write(struct mosquitto_db *db, struct mosquitto *context) break; case mosq_ms_publish_qos1: - rc = send__publish(context, mid, topic, payloadlen, payload, qos, retain, retries); + rc = send__publish(context, mid, topic, payloadlen, payload, qos, retain, retries, properties); if(!rc){ tail->timestamp = mosquitto_time(); tail->dup = 1; /* Any retry attempts are a duplicate. */ @@ -903,7 +913,7 @@ int db__message_write(struct mosquitto_db *db, struct mosquitto *context) break; case mosq_ms_publish_qos2: - rc = send__publish(context, mid, topic, payloadlen, payload, qos, retain, retries); + rc = send__publish(context, mid, topic, payloadlen, payload, qos, retain, retries, properties); if(!rc){ tail->timestamp = mosquitto_time(); tail->dup = 1; /* Any retry attempts are a duplicate. */ diff --git a/src/handle_connack.c b/src/handle_connack.c index 3070e7cafc..0124ce605f 100644 --- a/src/handle_connack.c +++ b/src/handle_connack.c @@ -49,12 +49,12 @@ int handle__connack(struct mosquitto_db *db, struct mosquitto *context) if(context->bridge->notification_topic){ if(!context->bridge->notifications_local_only){ if(send__real_publish(context, mosquitto__mid_generate(context), - context->bridge->notification_topic, 1, ¬ification_payload, 1, true, 0)){ + context->bridge->notification_topic, 1, ¬ification_payload, 1, true, 0, NULL)){ return 1; } } - db__messages_easy_queue(db, context, context->bridge->notification_topic, 1, 1, ¬ification_payload, 1); + db__messages_easy_queue(db, context, context->bridge->notification_topic, 1, 1, ¬ification_payload, 1, NULL); }else{ notification_topic_len = strlen(context->bridge->remote_clientid)+strlen("$SYS/broker/connection//state"); notification_topic = mosquitto__malloc(sizeof(char)*(notification_topic_len+1)); @@ -64,13 +64,13 @@ int handle__connack(struct mosquitto_db *db, struct mosquitto *context) notification_payload = '1'; if(!context->bridge->notifications_local_only){ if(send__real_publish(context, mosquitto__mid_generate(context), - notification_topic, 1, ¬ification_payload, 1, true, 0)){ + notification_topic, 1, ¬ification_payload, 1, true, 0, NULL)){ mosquitto__free(notification_topic); return 1; } } - db__messages_easy_queue(db, context, notification_topic, 1, 1, ¬ification_payload, 1); + db__messages_easy_queue(db, context, notification_topic, 1, 1, ¬ification_payload, 1, NULL); mosquitto__free(notification_topic); } } diff --git a/src/handle_connect.c b/src/handle_connect.c index 2dfbd0ad3a..df4b307465 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -301,13 +301,11 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) rc = MOSQ_ERR_NOMEM; goto handle_connect_error; } - /* FIXME - this needs to be "will" specific */ if(protocol_version == PROTOCOL_VERSION_v5){ - rc = property__read_all(&context->in_packet, &properties); + rc = property__read_all(&context->in_packet, &will_struct->properties); if(rc) return rc; - property__free_all(&properties); + property__free_all(&will_struct->properties); } - property__free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ if(packet__read_string(&context->in_packet, &will_topic, &slen)){ rc = 1; goto handle_connect_error; @@ -710,6 +708,9 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) mosquitto__free(password); mosquitto__free(will_payload); mosquitto__free(will_topic); + if(will_struct){ + property__free_all(&will_struct->properties); + } mosquitto__free(will_struct); #ifdef WITH_TLS if(client_cert) X509_free(client_cert); diff --git a/src/handle_publish.c b/src/handle_publish.c index 2b03ef68c3..0aa780b381 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -45,7 +45,7 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) int len; int slen; char *topic_mount; - struct mqtt5__property *properties; + struct mqtt5__property *properties = NULL; #ifdef WITH_BRIDGE char *topic_temp; @@ -136,7 +136,6 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) if(context->protocol == mosq_p_mqtt5){ rc = property__read_all(&context->in_packet, &properties); if(rc) return rc; - property__free_all(&properties); } payloadlen = context->in_packet.remaining_length - context->in_packet.pos; @@ -146,6 +145,7 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) topic_mount = mosquitto__malloc(len+1); if(!topic_mount){ mosquitto__free(topic); + property__free_all(&properties); return MOSQ_ERR_NOMEM; } snprintf(topic_mount, len, "%s%s", context->listener->mount_point, topic); @@ -162,11 +162,13 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) } if(UHPA_ALLOC(payload, payloadlen+1) == 0){ mosquitto__free(topic); + property__free_all(&properties); return MOSQ_ERR_NOMEM; } if(packet__read_bytes(&context->in_packet, UHPA_ACCESS(payload, payloadlen), payloadlen)){ mosquitto__free(topic); UHPA_FREE(payload, payloadlen); + property__free_all(&properties); return 1; } } @@ -179,6 +181,7 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) }else if(rc != MOSQ_ERR_SUCCESS){ mosquitto__free(topic); UHPA_FREE(payload, payloadlen); + property__free_all(&properties); return rc; } @@ -188,9 +191,10 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) } if(!stored){ dup = 0; - if(db__message_store(db, context->id, mid, topic, qos, payloadlen, &payload, retain, &stored, 0)){ + if(db__message_store(db, context->id, mid, topic, qos, payloadlen, &payload, retain, &stored, properties, 0)){ return 1; } + properties = NULL; /* Now belongs to db__message_store() */ }else{ mosquitto__free(topic); topic = stored->topic; @@ -224,6 +228,7 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) return rc; process_bad_message: mosquitto__free(topic); + property__free_all(&properties); UHPA_FREE(payload, payloadlen); switch(qos){ case 0: @@ -233,7 +238,7 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) case 2: db__message_store_find(context, mid, &stored); if(!stored){ - if(db__message_store(db, context->id, mid, NULL, qos, 0, NULL, false, &stored, 0)){ + if(db__message_store(db, context->id, mid, NULL, qos, 0, NULL, false, &stored, NULL, 0)){ return 1; } res = db__message_insert(db, context, mid, mosq_md_in, qos, false, stored); diff --git a/src/handle_subscribe.c b/src/handle_subscribe.c index e2f49e377f..7585c225f7 100644 --- a/src/handle_subscribe.c +++ b/src/handle_subscribe.c @@ -22,6 +22,7 @@ and the Eclipse Distribution License is available at #include "mosquitto_broker_internal.h" #include "memory_mosq.h" #include "packet_mosq.h" +#include "property_mosq.h" @@ -37,6 +38,7 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) int len; int slen; char *sub_mount; + struct mqtt5__property *properties = NULL; if(!context) return MOSQ_ERR_INVAL; log__printf(NULL, MOSQ_LOG_DEBUG, "Received SUBSCRIBE from %s", context->id); @@ -49,6 +51,13 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) } if(packet__read_uint16(&context->in_packet, &mid)) return 1; + if(context->protocol == mosq_p_mqtt5){ + rc = property__read_all(&context->in_packet, &properties); + if(rc) return rc; + property__free_all(&properties); + } + property__free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ + while(context->in_packet.pos < context->in_packet.remaining_length){ sub = NULL; if(packet__read_string(&context->in_packet, &sub, &slen)){ diff --git a/src/logging.c b/src/logging.c index 0b7b792a58..ccb536514c 100644 --- a/src/logging.c +++ b/src/logging.c @@ -239,10 +239,10 @@ int log__vprintf(int priority, const char *fmt, va_list va) return MOSQ_ERR_NOMEM; } snprintf(st, len, "%d: %s", (int)now, s); - db__messages_easy_queue(&int_db, NULL, topic, 2, strlen(st), st, 0); + db__messages_easy_queue(&int_db, NULL, topic, 2, strlen(st), st, 0, NULL); mosquitto__free(st); }else{ - db__messages_easy_queue(&int_db, NULL, topic, 2, strlen(s), s, 0); + db__messages_easy_queue(&int_db, NULL, topic, 2, strlen(s), s, 0, NULL); } } mosquitto__free(s); diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index 67a2924cbb..de4cb12108 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -315,6 +315,7 @@ struct mosquitto_msg_store{ int dest_id_count; int ref_count; char* topic; + struct mqtt5__property *properties; mosquitto__payload_uhpa payload; uint32_t payloadlen; uint16_t source_mid; @@ -551,8 +552,8 @@ int db__message_update(struct mosquitto *context, uint16_t mid, enum mosquitto_m int db__message_write(struct mosquitto_db *db, struct mosquitto *context); void db__message_dequeue_first(struct mosquitto *context); int db__messages_delete(struct mosquitto_db *db, struct mosquitto *context); -int db__messages_easy_queue(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int qos, uint32_t payloadlen, const void *payload, int retain); -int db__message_store(struct mosquitto_db *db, const char *source, uint16_t source_mid, char *topic, int qos, uint32_t payloadlen, mosquitto__payload_uhpa *payload, int retain, struct mosquitto_msg_store **stored, dbid_t store_id); +int db__messages_easy_queue(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int qos, uint32_t payloadlen, const void *payload, int retain, struct mqtt5__property **properties); +int db__message_store(struct mosquitto_db *db, const char *source, uint16_t source_mid, char *topic, int qos, uint32_t payloadlen, mosquitto__payload_uhpa *payload, int retain, struct mosquitto_msg_store **stored, struct mqtt5__property *properties, dbid_t store_id); int db__message_store_find(struct mosquitto *context, uint16_t mid, struct mosquitto_msg_store **stored); void db__msg_store_add(struct mosquitto_db *db, struct mosquitto_msg_store *store); void db__msg_store_remove(struct mosquitto_db *db, struct mosquitto_msg_store *store); diff --git a/src/persist.c b/src/persist.c index 7a93f98427..cccd04ade7 100644 --- a/src/persist.c +++ b/src/persist.c @@ -717,7 +717,7 @@ static int persist__msg_store_chunk_restore(struct mosquitto_db *db, FILE *db_fp read_e(db_fptr, UHPA_ACCESS(payload, payloadlen), payloadlen); } - rc = db__message_store(db, source_id, source_mid, topic, qos, payloadlen, &payload, retain, &stored, store_id); + rc = db__message_store(db, source_id, source_mid, topic, qos, payloadlen, &payload, retain, &stored, NULL, store_id); mosquitto__free(source_id); if(rc == MOSQ_ERR_SUCCESS){ diff --git a/src/sys_tree.c b/src/sys_tree.c index ebece86b97..582e8f540f 100644 --- a/src/sys_tree.c +++ b/src/sys_tree.c @@ -52,7 +52,7 @@ void sys_tree__init(struct mosquitto_db *db) /* Set static $SYS messages */ snprintf(buf, 64, "mosquitto version %s", VERSION); - db__messages_easy_queue(db, NULL, "$SYS/broker/version", SYS_TREE_QOS, strlen(buf), buf, 1); + db__messages_easy_queue(db, NULL, "$SYS/broker/version", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); } static void sys_tree__update_clients(struct mosquitto_db *db, char *buf) @@ -71,31 +71,31 @@ static void sys_tree__update_clients(struct mosquitto_db *db, char *buf) if(client_count != count_total){ client_count = count_total; snprintf(buf, BUFLEN, "%d", client_count); - db__messages_easy_queue(db, NULL, "$SYS/broker/clients/total", SYS_TREE_QOS, strlen(buf), buf, 1); + db__messages_easy_queue(db, NULL, "$SYS/broker/clients/total", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); if(client_count > client_max){ client_max = client_count; snprintf(buf, BUFLEN, "%d", client_max); - db__messages_easy_queue(db, NULL, "$SYS/broker/clients/maximum", SYS_TREE_QOS, strlen(buf), buf, 1); + db__messages_easy_queue(db, NULL, "$SYS/broker/clients/maximum", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); } } if(disconnected_count != count_total-count_by_sock){ disconnected_count = count_total-count_by_sock; snprintf(buf, BUFLEN, "%d", disconnected_count); - db__messages_easy_queue(db, NULL, "$SYS/broker/clients/inactive", SYS_TREE_QOS, strlen(buf), buf, 1); - db__messages_easy_queue(db, NULL, "$SYS/broker/clients/disconnected", SYS_TREE_QOS, strlen(buf), buf, 1); + db__messages_easy_queue(db, NULL, "$SYS/broker/clients/inactive", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/clients/disconnected", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); } if(connected_count != count_by_sock){ connected_count = count_by_sock; snprintf(buf, BUFLEN, "%d", connected_count); - db__messages_easy_queue(db, NULL, "$SYS/broker/clients/active", SYS_TREE_QOS, strlen(buf), buf, 1); - db__messages_easy_queue(db, NULL, "$SYS/broker/clients/connected", SYS_TREE_QOS, strlen(buf), buf, 1); + db__messages_easy_queue(db, NULL, "$SYS/broker/clients/active", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/clients/connected", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); } if(g_clients_expired != clients_expired){ clients_expired = g_clients_expired; snprintf(buf, BUFLEN, "%d", clients_expired); - db__messages_easy_queue(db, NULL, "$SYS/broker/clients/expired", SYS_TREE_QOS, strlen(buf), buf, 1); + db__messages_easy_queue(db, NULL, "$SYS/broker/clients/expired", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); } } @@ -110,13 +110,13 @@ static void sys_tree__update_memory(struct mosquitto_db *db, char *buf) if(current_heap != value_ul){ current_heap = value_ul; snprintf(buf, BUFLEN, "%lu", current_heap); - db__messages_easy_queue(db, NULL, "$SYS/broker/heap/current", SYS_TREE_QOS, strlen(buf), buf, 1); + db__messages_easy_queue(db, NULL, "$SYS/broker/heap/current", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); } value_ul =mosquitto__max_memory_used(); if(max_heap != value_ul){ max_heap = value_ul; snprintf(buf, BUFLEN, "%lu", max_heap); - db__messages_easy_queue(db, NULL, "$SYS/broker/heap/maximum", SYS_TREE_QOS, strlen(buf), buf, 1); + db__messages_easy_queue(db, NULL, "$SYS/broker/heap/maximum", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); } } #endif @@ -128,12 +128,12 @@ static void calc_load(struct mosquitto_db *db, char *buf, const char *topic, boo if (initial) { new_value = *current; snprintf(buf, BUFLEN, "%.2f", new_value); - db__messages_easy_queue(db, NULL, topic, SYS_TREE_QOS, strlen(buf), buf, 1); + db__messages_easy_queue(db, NULL, topic, SYS_TREE_QOS, strlen(buf), buf, 1, NULL); } else { new_value = interval + exponent*((*current) - interval); if(fabs(new_value - (*current)) >= 0.01){ snprintf(buf, BUFLEN, "%.2f", new_value); - db__messages_easy_queue(db, NULL, topic, SYS_TREE_QOS, strlen(buf), buf, 1); + db__messages_easy_queue(db, NULL, topic, SYS_TREE_QOS, strlen(buf), buf, 1, NULL); } } (*current) = new_value; @@ -211,7 +211,7 @@ void sys_tree__update(struct mosquitto_db *db, int interval, time_t start_time) if(interval && now - interval > last_update){ uptime = now - start_time; snprintf(buf, BUFLEN, "%d seconds", (int)uptime); - db__messages_easy_queue(db, NULL, "$SYS/broker/uptime", SYS_TREE_QOS, strlen(buf), buf, 1); + db__messages_easy_queue(db, NULL, "$SYS/broker/uptime", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); sys_tree__update_clients(db, buf); bool initial_publish = false; @@ -280,26 +280,26 @@ void sys_tree__update(struct mosquitto_db *db, int interval, time_t start_time) if(db->msg_store_count != msg_store_count){ msg_store_count = db->msg_store_count; snprintf(buf, BUFLEN, "%d", msg_store_count); - db__messages_easy_queue(db, NULL, "$SYS/broker/messages/stored", SYS_TREE_QOS, strlen(buf), buf, 1); - db__messages_easy_queue(db, NULL, "$SYS/broker/store/messages/count", SYS_TREE_QOS, strlen(buf), buf, 1); + db__messages_easy_queue(db, NULL, "$SYS/broker/messages/stored", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/store/messages/count", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); } if (db->msg_store_bytes != msg_store_bytes){ msg_store_bytes = db->msg_store_bytes; snprintf(buf, BUFLEN, "%lu", msg_store_bytes); - db__messages_easy_queue(db, NULL, "$SYS/broker/store/messages/bytes", SYS_TREE_QOS, strlen(buf), buf, 1); + db__messages_easy_queue(db, NULL, "$SYS/broker/store/messages/bytes", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); } if(db->subscription_count != subscription_count){ subscription_count = db->subscription_count; snprintf(buf, BUFLEN, "%d", subscription_count); - db__messages_easy_queue(db, NULL, "$SYS/broker/subscriptions/count", SYS_TREE_QOS, strlen(buf), buf, 1); + db__messages_easy_queue(db, NULL, "$SYS/broker/subscriptions/count", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); } if(db->retained_count != retained_count){ retained_count = db->retained_count; snprintf(buf, BUFLEN, "%d", retained_count); - db__messages_easy_queue(db, NULL, "$SYS/broker/retained messages/count", SYS_TREE_QOS, strlen(buf), buf, 1); + db__messages_easy_queue(db, NULL, "$SYS/broker/retained messages/count", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); } #ifdef REAL_WITH_MEMORY_TRACKING @@ -309,55 +309,55 @@ void sys_tree__update(struct mosquitto_db *db, int interval, time_t start_time) if(msgs_received != g_msgs_received){ msgs_received = g_msgs_received; snprintf(buf, BUFLEN, "%lu", msgs_received); - db__messages_easy_queue(db, NULL, "$SYS/broker/messages/received", SYS_TREE_QOS, strlen(buf), buf, 1); + db__messages_easy_queue(db, NULL, "$SYS/broker/messages/received", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); } if(msgs_sent != g_msgs_sent){ msgs_sent = g_msgs_sent; snprintf(buf, BUFLEN, "%lu", msgs_sent); - db__messages_easy_queue(db, NULL, "$SYS/broker/messages/sent", SYS_TREE_QOS, strlen(buf), buf, 1); + db__messages_easy_queue(db, NULL, "$SYS/broker/messages/sent", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); } if(publish_dropped != g_msgs_dropped){ publish_dropped = g_msgs_dropped; snprintf(buf, BUFLEN, "%lu", publish_dropped); - db__messages_easy_queue(db, NULL, "$SYS/broker/publish/messages/dropped", SYS_TREE_QOS, strlen(buf), buf, 1); + db__messages_easy_queue(db, NULL, "$SYS/broker/publish/messages/dropped", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); } if(pub_msgs_received != g_pub_msgs_received){ pub_msgs_received = g_pub_msgs_received; snprintf(buf, BUFLEN, "%lu", pub_msgs_received); - db__messages_easy_queue(db, NULL, "$SYS/broker/publish/messages/received", SYS_TREE_QOS, strlen(buf), buf, 1); + db__messages_easy_queue(db, NULL, "$SYS/broker/publish/messages/received", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); } if(pub_msgs_sent != g_pub_msgs_sent){ pub_msgs_sent = g_pub_msgs_sent; snprintf(buf, BUFLEN, "%lu", pub_msgs_sent); - db__messages_easy_queue(db, NULL, "$SYS/broker/publish/messages/sent", SYS_TREE_QOS, strlen(buf), buf, 1); + db__messages_easy_queue(db, NULL, "$SYS/broker/publish/messages/sent", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); } if(bytes_received != g_bytes_received){ bytes_received = g_bytes_received; snprintf(buf, BUFLEN, "%llu", bytes_received); - db__messages_easy_queue(db, NULL, "$SYS/broker/bytes/received", SYS_TREE_QOS, strlen(buf), buf, 1); + db__messages_easy_queue(db, NULL, "$SYS/broker/bytes/received", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); } if(bytes_sent != g_bytes_sent){ bytes_sent = g_bytes_sent; snprintf(buf, BUFLEN, "%llu", bytes_sent); - db__messages_easy_queue(db, NULL, "$SYS/broker/bytes/sent", SYS_TREE_QOS, strlen(buf), buf, 1); + db__messages_easy_queue(db, NULL, "$SYS/broker/bytes/sent", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); } if(pub_bytes_received != g_pub_bytes_received){ pub_bytes_received = g_pub_bytes_received; snprintf(buf, BUFLEN, "%llu", pub_bytes_received); - db__messages_easy_queue(db, NULL, "$SYS/broker/publish/bytes/received", SYS_TREE_QOS, strlen(buf), buf, 1); + db__messages_easy_queue(db, NULL, "$SYS/broker/publish/bytes/received", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); } if(pub_bytes_sent != g_pub_bytes_sent){ pub_bytes_sent = g_pub_bytes_sent; snprintf(buf, BUFLEN, "%llu", pub_bytes_sent); - db__messages_easy_queue(db, NULL, "$SYS/broker/publish/bytes/sent", SYS_TREE_QOS, strlen(buf), buf, 1); + db__messages_easy_queue(db, NULL, "$SYS/broker/publish/bytes/sent", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); } last_update = mosquitto_time(); From 723d9c2782e0590fad6cf680c017036ebcef8314 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 25 Oct 2018 11:23:04 +0100 Subject: [PATCH 058/254] Check whether properties are on the correct commands. --- lib/mqtt_protocol.h | 3 + lib/property_mosq.c | 112 +++++++++++++++++- lib/property_mosq.h | 2 +- src/handle_connect.c | 4 +- src/handle_publish.c | 2 +- src/handle_subscribe.c | 3 +- test/unit/property_read.c | 232 ++++++++++++++++++------------------- test/unit/property_write.c | 69 ++++++----- 8 files changed, 272 insertions(+), 155 deletions(-) diff --git a/lib/mqtt_protocol.h b/lib/mqtt_protocol.h index b5807f4704..62befba6f1 100644 --- a/lib/mqtt_protocol.h +++ b/lib/mqtt_protocol.h @@ -45,6 +45,9 @@ and the Eclipse Distribution License is available at #define DISCONNECT 0xE0 #define AUTH 0xF0 +/* For distinguishing CONNECT and WILL properties */ +#define CMD_WILL 0 + enum mqtt311_connack_codes { CONNACK_ACCEPTED = 0, CONNACK_REFUSED_PROTOCOL_VERSION = 1, diff --git a/lib/property_mosq.c b/lib/property_mosq.c index 5bb7331ad3..b4f44c845e 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -26,6 +26,9 @@ and the Eclipse Distribution License is available at #include "packet_mosq.h" #include "property_mosq.h" +static int property__command_check(int command, struct mqtt5__property *properties); + + int property__read(struct mosquitto__packet *packet, int32_t *len, struct mqtt5__property *property) { int rc; @@ -138,7 +141,7 @@ int property__read(struct mosquitto__packet *packet, int32_t *len, struct mqtt5_ } -int property__read_all(struct mosquitto__packet *packet, struct mqtt5__property **properties) +int property__read_all(int command, struct mosquitto__packet *packet, struct mqtt5__property **properties) { int rc; int32_t proplen; @@ -197,6 +200,7 @@ int property__read_all(struct mosquitto__packet *packet, struct mqtt5__property } } + /* Check for duplicates */ current = *properties; while(current){ tail = current->next; @@ -212,6 +216,11 @@ int property__read_all(struct mosquitto__packet *packet, struct mqtt5__property current = current->next; } + /* Check for properties on incorrect commands */ + if(property__command_check(command, *properties)){ + property__free_all(properties); + return MOSQ_ERR_PROTOCOL; + } return MOSQ_ERR_SUCCESS; } @@ -441,3 +450,104 @@ int property__write_all(struct mosquitto__packet *packet, struct mqtt5__property return MOSQ_ERR_SUCCESS; } + +static int property__command_check(int command, struct mqtt5__property *properties) +{ + struct mqtt5__property *p; + + p = properties; + while(p){ + switch(p->identifier){ + case PROP_PAYLOAD_FORMAT_INDICATOR: + case PROP_MESSAGE_EXPIRY_INTERVAL: + case PROP_CONTENT_TYPE: + case PROP_RESPONSE_TOPIC: + case PROP_CORRELATION_DATA: + if(command != PUBLISH && command != 0){ + return MOSQ_ERR_PROTOCOL; + } + break; + + case PROP_SUBSCRIPTION_IDENTIFIER: + if(command != PUBLISH && command != SUBSCRIBE){ + return MOSQ_ERR_PROTOCOL; + } + break; + + case PROP_SESSION_EXPIRY_INTERVAL: + if(command != CONNECT && command != CONNACK && command != DISCONNECT){ + return MOSQ_ERR_PROTOCOL; + } + break; + + case PROP_AUTHENTICATION_METHOD: + case PROP_AUTHENTICATION_DATA: + if(command != CONNECT && command != CONNACK && command != AUTH){ + return MOSQ_ERR_PROTOCOL; + } + break; + + case PROP_ASSIGNED_CLIENT_IDENTIFIER: + case PROP_SERVER_KEEP_ALIVE: + case PROP_RESPONSE_INFO: + case PROP_MAXIMUM_QOS: + case PROP_RETAIN_AVAILABLE: + case PROP_WILDCARD_SUB_AVAILABLE: + case PROP_SUBSCRIPTION_ID_AVAILABLE: + case PROP_SHARED_SUB_AVAILABLE: + if(command != CONNACK){ + return MOSQ_ERR_PROTOCOL; + } + break; + + case PROP_WILL_DELAY_INTERVAL: + if(command != 0){ + return MOSQ_ERR_PROTOCOL; + } + break; + + case PROP_REQUEST_PROBLEM_INFO: + case PROP_REQUEST_RESPONSE_INFO: + if(command != CONNECT){ + return MOSQ_ERR_PROTOCOL; + } + break; + + case PROP_SERVER_REFERENCE: + if(command != CONNACK && command != DISCONNECT){ + return MOSQ_ERR_PROTOCOL; + } + break; + + case PROP_REASON_STRING: + if(command == CONNECT || command == PUBLISH || command == SUBSCRIBE || command == UNSUBSCRIBE){ + return MOSQ_ERR_PROTOCOL; + } + break; + + case PROP_RECEIVE_MAXIMUM: + case PROP_TOPIC_ALIAS_MAXIMUM: + case PROP_MAXIMUM_PACKET_SIZE: + if(command != CONNECT && command != CONNACK){ + return MOSQ_ERR_PROTOCOL; + } + break; + + case PROP_TOPIC_ALIAS: + if(command != PUBLISH){ + return MOSQ_ERR_PROTOCOL; + } + break; + + case PROP_USER_PROPERTY: + break; + + default: + return MOSQ_ERR_PROTOCOL; + } + + p = p->next; + } + return MOSQ_ERR_SUCCESS; +} + diff --git a/lib/property_mosq.h b/lib/property_mosq.h index 9e913f9910..1253063a5a 100644 --- a/lib/property_mosq.h +++ b/lib/property_mosq.h @@ -39,7 +39,7 @@ struct mqtt5__property { }; -int property__read_all(struct mosquitto__packet *packet, struct mqtt5__property **property); +int property__read_all(int command, struct mosquitto__packet *packet, struct mqtt5__property **property); int property__write_all(struct mosquitto__packet *packet, struct mqtt5__property *property); void property__free(struct mqtt5__property **property); void property__free_all(struct mqtt5__property **property); diff --git a/src/handle_connect.c b/src/handle_connect.c index df4b307465..c0e42489cf 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -242,7 +242,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) } if(protocol_version == PROTOCOL_VERSION_v5){ - rc = property__read_all(&context->in_packet, &properties); + rc = property__read_all(CONNECT, &context->in_packet, &properties); if(rc) return rc; property__free_all(&properties); } @@ -302,7 +302,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) goto handle_connect_error; } if(protocol_version == PROTOCOL_VERSION_v5){ - rc = property__read_all(&context->in_packet, &will_struct->properties); + rc = property__read_all(CMD_WILL, &context->in_packet, &will_struct->properties); if(rc) return rc; property__free_all(&will_struct->properties); } diff --git a/src/handle_publish.c b/src/handle_publish.c index 0aa780b381..f5850a3241 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -134,7 +134,7 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) } if(context->protocol == mosq_p_mqtt5){ - rc = property__read_all(&context->in_packet, &properties); + rc = property__read_all(PUBLISH, &context->in_packet, &properties); if(rc) return rc; } diff --git a/src/handle_subscribe.c b/src/handle_subscribe.c index 7585c225f7..a134bf55ce 100644 --- a/src/handle_subscribe.c +++ b/src/handle_subscribe.c @@ -21,6 +21,7 @@ and the Eclipse Distribution License is available at #include "mosquitto_broker_internal.h" #include "memory_mosq.h" +#include "mqtt_protocol.h" #include "packet_mosq.h" #include "property_mosq.h" @@ -52,7 +53,7 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) if(packet__read_uint16(&context->in_packet, &mid)) return 1; if(context->protocol == mosq_p_mqtt5){ - rc = property__read_all(&context->in_packet, &properties); + rc = property__read_all(SUBSCRIBE, &context->in_packet, &properties); if(rc) return rc; property__free_all(&properties); } diff --git a/test/unit/property_read.c b/test/unit/property_read.c index 97a8182c95..86fb5ad691 100644 --- a/test/unit/property_read.c +++ b/test/unit/property_read.c @@ -6,6 +6,7 @@ #include "packet_mosq.h" static void byte_prop_read_helper( + int command, uint8_t *payload, int remaining_length, int rc_expected, @@ -19,7 +20,7 @@ static void byte_prop_read_helper( memset(&packet, 0, sizeof(struct mosquitto__packet)); packet.payload = payload; packet.remaining_length = remaining_length; - rc = property__read_all(&packet, &properties); + rc = property__read_all(command, &packet, &properties); CU_ASSERT_EQUAL(rc, rc_expected); CU_ASSERT_EQUAL(packet.pos, remaining_length); @@ -33,7 +34,7 @@ static void byte_prop_read_helper( CU_ASSERT_PTR_EQUAL(properties, NULL); } -static void duplicate_byte_helper(int identifier) +static void duplicate_byte_helper(int command, int identifier) { uint8_t payload[20]; @@ -44,10 +45,10 @@ static void duplicate_byte_helper(int identifier) payload[3] = identifier; payload[4] = 0; - byte_prop_read_helper(payload, 5, MOSQ_ERR_PROTOCOL, identifier, 1); + byte_prop_read_helper(command, payload, 5, MOSQ_ERR_PROTOCOL, identifier, 1); } -static void bad_byte_helper(int identifier) +static void bad_byte_helper(int command, int identifier) { uint8_t payload[20]; @@ -56,11 +57,12 @@ static void bad_byte_helper(int identifier) payload[1] = identifier; payload[2] = 2; /* 0, 1 are only valid values */ - byte_prop_read_helper(payload, 3, MOSQ_ERR_PROTOCOL, identifier, 0); + byte_prop_read_helper(command, payload, 3, MOSQ_ERR_PROTOCOL, identifier, 0); } static void int32_prop_read_helper( + int command, uint8_t *payload, int remaining_length, int rc_expected, @@ -74,7 +76,7 @@ static void int32_prop_read_helper( memset(&packet, 0, sizeof(struct mosquitto__packet)); packet.payload = payload; packet.remaining_length = remaining_length; - rc = property__read_all(&packet, &properties); + rc = property__read_all(command, &packet, &properties); CU_ASSERT_EQUAL(rc, rc_expected); CU_ASSERT_EQUAL(packet.pos, remaining_length); @@ -88,7 +90,7 @@ static void int32_prop_read_helper( CU_ASSERT_PTR_EQUAL(properties, NULL); } -static void duplicate_int32_helper(int identifier) +static void duplicate_int32_helper(int command, int identifier) { uint8_t payload[20]; @@ -105,11 +107,12 @@ static void duplicate_int32_helper(int identifier) payload[9] = 0; payload[10] = 0; - int32_prop_read_helper(payload, 11, MOSQ_ERR_PROTOCOL, identifier, 1); + int32_prop_read_helper(command, payload, 11, MOSQ_ERR_PROTOCOL, identifier, 1); } static void int16_prop_read_helper( + int command, uint8_t *payload, int remaining_length, int rc_expected, @@ -123,7 +126,7 @@ static void int16_prop_read_helper( memset(&packet, 0, sizeof(struct mosquitto__packet)); packet.payload = payload; packet.remaining_length = remaining_length; - rc = property__read_all(&packet, &properties); + rc = property__read_all(command, &packet, &properties); CU_ASSERT_EQUAL(rc, rc_expected); CU_ASSERT_EQUAL(packet.pos, remaining_length); @@ -137,7 +140,7 @@ static void int16_prop_read_helper( CU_ASSERT_PTR_EQUAL(properties, NULL); } -static void duplicate_int16_helper(int identifier) +static void duplicate_int16_helper(int command, int identifier) { uint8_t payload[20]; @@ -150,10 +153,11 @@ static void duplicate_int16_helper(int identifier) payload[5] = 0; payload[6] = 0; - int16_prop_read_helper(payload, 7, MOSQ_ERR_PROTOCOL, identifier, 1); + int16_prop_read_helper(command, payload, 7, MOSQ_ERR_PROTOCOL, identifier, 1); } static void string_prop_read_helper( + int command, uint8_t *payload, int remaining_length, int rc_expected, @@ -167,7 +171,7 @@ static void string_prop_read_helper( memset(&packet, 0, sizeof(struct mosquitto__packet)); packet.payload = payload; packet.remaining_length = remaining_length; - rc = property__read_all(&packet, &properties); + rc = property__read_all(command, &packet, &properties); CU_ASSERT_EQUAL(rc, rc_expected); CU_ASSERT_EQUAL(packet.pos, remaining_length); @@ -197,7 +201,7 @@ static void duplicate_string_helper(int identifier) payload[7] = 1; payload[8] = 'h'; - string_prop_read_helper(payload, 9, MOSQ_ERR_PROTOCOL, identifier, ""); + string_prop_read_helper(PUBLISH, payload, 9, MOSQ_ERR_PROTOCOL, identifier, ""); } static void bad_string_helper(int identifier) @@ -213,10 +217,11 @@ static void bad_string_helper(int identifier) payload[5] = 0; /* 0 in string not allowed */ payload[6] = 'h'; - string_prop_read_helper(payload, 7, MOSQ_ERR_MALFORMED_UTF8, identifier, ""); + string_prop_read_helper(PUBLISH, payload, 7, MOSQ_ERR_MALFORMED_UTF8, identifier, ""); } static void binary_prop_read_helper( + int command, uint8_t *payload, int remaining_length, int rc_expected, @@ -231,7 +236,7 @@ static void binary_prop_read_helper( memset(&packet, 0, sizeof(struct mosquitto__packet)); packet.payload = payload; packet.remaining_length = remaining_length; - rc = property__read_all(&packet, &properties); + rc = property__read_all(command, &packet, &properties); CU_ASSERT_EQUAL(rc, rc_expected); CU_ASSERT_EQUAL(packet.pos, remaining_length); @@ -246,7 +251,7 @@ static void binary_prop_read_helper( CU_ASSERT_PTR_EQUAL(properties, NULL); } -static void duplicate_binary_helper(int identifier) +static void duplicate_binary_helper(int command, int identifier) { uint8_t payload[20]; @@ -261,7 +266,7 @@ static void duplicate_binary_helper(int identifier) payload[7] = 1; payload[8] = 'h'; - string_prop_read_helper(payload, 9, MOSQ_ERR_PROTOCOL, identifier, ""); + string_prop_read_helper(command, payload, 9, MOSQ_ERR_PROTOCOL, identifier, ""); } static void string_pair_prop_read_helper( @@ -280,7 +285,7 @@ static void string_pair_prop_read_helper( memset(&packet, 0, sizeof(struct mosquitto__packet)); packet.payload = payload; packet.remaining_length = remaining_length; - rc = property__read_all(&packet, &properties); + rc = property__read_all(CONNECT, &packet, &properties); CU_ASSERT_EQUAL(rc, rc_expected); CU_ASSERT_EQUAL(packet.pos, remaining_length); @@ -315,30 +320,20 @@ static void varint_prop_read_helper( memset(&packet, 0, sizeof(struct mosquitto__packet)); packet.payload = payload; packet.remaining_length = remaining_length; - rc = property__read_all(&packet, &properties); + rc = property__read_all(PUBLISH, &packet, &properties); CU_ASSERT_EQUAL(rc, rc_expected); if(properties){ CU_ASSERT_EQUAL(properties->identifier, identifier); CU_ASSERT_EQUAL(properties->value.varint, value_expected); CU_ASSERT_PTR_NULL(properties->next); - if(value_expected < 128){ - CU_ASSERT_EQUAL(property__get_length_all(properties), 2); - }else if(value_expected < 16384){ - CU_ASSERT_EQUAL(property__get_length_all(properties), 3); - }else if(value_expected < 2097152){ - CU_ASSERT_EQUAL(property__get_length_all(properties), 4); - }else if(value_expected < 268435456){ - CU_ASSERT_EQUAL(property__get_length_all(properties), 5); - }else{ - CU_FAIL("Incorrect varint value."); - } + CU_ASSERT_EQUAL(property__get_length_all(properties), packet__varint_bytes(value_expected)+1); property__free_all(&properties); } CU_ASSERT_PTR_NULL(properties); } -static void packet_helper_reason_string_user_property(void) +static void packet_helper_reason_string_user_property(int command) { uint8_t payload[24] = {23, PROP_REASON_STRING, 0, 6, 'r', 'e', 'a', 's', 'o', 'n', @@ -351,26 +346,29 @@ static void packet_helper_reason_string_user_property(void) memset(&packet, 0, sizeof(struct mosquitto__packet)); packet.payload = payload; packet.remaining_length = sizeof(payload);; - rc = property__read_all(&packet, &properties); + rc = property__read_all(command, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); - CU_ASSERT_PTR_NOT_NULL(properties->next); - p = properties; + CU_ASSERT_PTR_NOT_NULL(properties); + if(properties){ + CU_ASSERT_PTR_NOT_NULL(properties->next); + p = properties; - CU_ASSERT_EQUAL(p->identifier, PROP_REASON_STRING); - CU_ASSERT_STRING_EQUAL(p->value.s.v, "reason"); - CU_ASSERT_EQUAL(p->value.s.len, strlen("reason")); + CU_ASSERT_EQUAL(p->identifier, PROP_REASON_STRING); + CU_ASSERT_STRING_EQUAL(p->value.s.v, "reason"); + CU_ASSERT_EQUAL(p->value.s.len, strlen("reason")); - p = p->next; - CU_ASSERT_PTR_NULL(p->next); + p = p->next; + CU_ASSERT_PTR_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_USER_PROPERTY); - CU_ASSERT_STRING_EQUAL(p->value.s.v, "value"); - CU_ASSERT_EQUAL(p->value.s.len, strlen("value")); - CU_ASSERT_STRING_EQUAL(p->name.v, "name"); - CU_ASSERT_EQUAL(p->name.len, strlen("name")); + CU_ASSERT_EQUAL(p->identifier, PROP_USER_PROPERTY); + CU_ASSERT_STRING_EQUAL(p->value.s.v, "value"); + CU_ASSERT_EQUAL(p->value.s.len, strlen("value")); + CU_ASSERT_STRING_EQUAL(p->name.v, "name"); + CU_ASSERT_EQUAL(p->name.len, strlen("name")); - property__free_all(&properties); + property__free_all(&properties); + } } /* ======================================================================== @@ -388,7 +386,7 @@ static void TEST_no_properties(void) memset(payload, 0, sizeof(payload)); packet.payload = payload; packet.remaining_length = 1; - rc = property__read_all(&packet, &properties); + rc = property__read_all(CONNECT, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); CU_ASSERT_PTR_EQUAL(properties, NULL); CU_ASSERT_EQUAL(packet.pos, 1); @@ -406,7 +404,7 @@ static void TEST_truncated(void) memset(payload, 0, sizeof(payload)); packet.payload = payload; packet.remaining_length = 0; - rc = property__read_all(&packet, &properties); + rc = property__read_all(CONNECT, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_PROTOCOL); CU_ASSERT_PTR_EQUAL(properties, NULL); CU_ASSERT_EQUAL(packet.pos, 0); @@ -417,7 +415,7 @@ static void TEST_truncated(void) payload[0] = 2; packet.payload = payload; packet.remaining_length = 1; - rc = property__read_all(&packet, &properties); + rc = property__read_all(CONNECT, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_PROTOCOL); CU_ASSERT_PTR_EQUAL(properties, NULL); CU_ASSERT_EQUAL(packet.pos, 1); @@ -429,7 +427,7 @@ static void TEST_truncated(void) payload[1] = PROP_PAYLOAD_FORMAT_INDICATOR; packet.payload = payload; packet.remaining_length = 2; - rc = property__read_all(&packet, &properties); + rc = property__read_all(CONNECT, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_PROTOCOL); CU_ASSERT_PTR_EQUAL(properties, NULL); CU_ASSERT_EQUAL(packet.pos, 2); @@ -452,7 +450,7 @@ static void TEST_invalid_property_id(void) payload[0] = 4; packet.payload = payload; packet.remaining_length = 2; - rc = property__read_all(&packet, &properties); + rc = property__read_all(CONNECT, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_MALFORMED_PACKET); CU_ASSERT_PTR_EQUAL(properties, NULL); CU_ASSERT_EQUAL(packet.pos, 2); @@ -464,7 +462,7 @@ static void TEST_invalid_property_id(void) payload[1] = 4; packet.payload = payload; packet.remaining_length = 2; - rc = property__read_all(&packet, &properties); + rc = property__read_all(CONNECT, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_MALFORMED_PACKET); CU_ASSERT_PTR_EQUAL(properties, NULL); CU_ASSERT_EQUAL(packet.pos, 2); @@ -483,7 +481,7 @@ static void TEST_single_payload_format_indicator(void) payload[1] = PROP_PAYLOAD_FORMAT_INDICATOR; payload[2] = 1; - byte_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_PAYLOAD_FORMAT_INDICATOR, 1); + byte_prop_read_helper(PUBLISH, payload, 3, MOSQ_ERR_SUCCESS, PROP_PAYLOAD_FORMAT_INDICATOR, 1); } static void TEST_single_request_problem_information(void) @@ -495,7 +493,7 @@ static void TEST_single_request_problem_information(void) payload[1] = PROP_REQUEST_PROBLEM_INFO; payload[2] = 1; - byte_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_REQUEST_PROBLEM_INFO, 1); + byte_prop_read_helper(CONNECT, payload, 3, MOSQ_ERR_SUCCESS, PROP_REQUEST_PROBLEM_INFO, 1); } static void TEST_single_request_response_information(void) @@ -507,7 +505,7 @@ static void TEST_single_request_response_information(void) payload[1] = PROP_REQUEST_RESPONSE_INFO; payload[2] = 1; - byte_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_REQUEST_RESPONSE_INFO, 1); + byte_prop_read_helper(CONNECT, payload, 3, MOSQ_ERR_SUCCESS, PROP_REQUEST_RESPONSE_INFO, 1); } static void TEST_single_maximum_qos(void) @@ -519,7 +517,7 @@ static void TEST_single_maximum_qos(void) payload[1] = PROP_MAXIMUM_QOS; payload[2] = 1; - byte_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_MAXIMUM_QOS, 1); + byte_prop_read_helper(CONNACK, payload, 3, MOSQ_ERR_SUCCESS, PROP_MAXIMUM_QOS, 1); } static void TEST_single_retain_available(void) @@ -531,7 +529,7 @@ static void TEST_single_retain_available(void) payload[1] = PROP_RETAIN_AVAILABLE; payload[2] = 1; - byte_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_RETAIN_AVAILABLE, 1); + byte_prop_read_helper(CONNACK, payload, 3, MOSQ_ERR_SUCCESS, PROP_RETAIN_AVAILABLE, 1); } static void TEST_single_wildcard_subscription_available(void) @@ -543,7 +541,7 @@ static void TEST_single_wildcard_subscription_available(void) payload[1] = PROP_WILDCARD_SUB_AVAILABLE; payload[2] = 0; - byte_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_WILDCARD_SUB_AVAILABLE, 0); + byte_prop_read_helper(CONNACK, payload, 3, MOSQ_ERR_SUCCESS, PROP_WILDCARD_SUB_AVAILABLE, 0); } static void TEST_single_subscription_identifier_available(void) @@ -555,7 +553,7 @@ static void TEST_single_subscription_identifier_available(void) payload[1] = PROP_SUBSCRIPTION_ID_AVAILABLE; payload[2] = 0; - byte_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_ID_AVAILABLE, 0); + byte_prop_read_helper(CONNACK, payload, 3, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_ID_AVAILABLE, 0); } static void TEST_single_shared_subscription_available(void) @@ -567,7 +565,7 @@ static void TEST_single_shared_subscription_available(void) payload[1] = PROP_SHARED_SUB_AVAILABLE; payload[2] = 1; - byte_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_SHARED_SUB_AVAILABLE, 1); + byte_prop_read_helper(CONNACK, payload, 3, MOSQ_ERR_SUCCESS, PROP_SHARED_SUB_AVAILABLE, 1); } static void TEST_single_message_expiry_interval(void) @@ -582,7 +580,7 @@ static void TEST_single_message_expiry_interval(void) payload[4] = 0x34; payload[5] = 0x45; - int32_prop_read_helper(payload, 6, MOSQ_ERR_SUCCESS, PROP_MESSAGE_EXPIRY_INTERVAL, 0x12233445); + int32_prop_read_helper(CMD_WILL, payload, 6, MOSQ_ERR_SUCCESS, PROP_MESSAGE_EXPIRY_INTERVAL, 0x12233445); } static void TEST_single_session_expiry_interval(void) @@ -597,7 +595,7 @@ static void TEST_single_session_expiry_interval(void) payload[4] = 0x23; payload[5] = 0x12; - int32_prop_read_helper(payload, 6, MOSQ_ERR_SUCCESS, PROP_SESSION_EXPIRY_INTERVAL, 0x45342312); + int32_prop_read_helper(CONNACK, payload, 6, MOSQ_ERR_SUCCESS, PROP_SESSION_EXPIRY_INTERVAL, 0x45342312); } static void TEST_single_will_delay_interval(void) @@ -612,7 +610,7 @@ static void TEST_single_will_delay_interval(void) payload[4] = 0x23; payload[5] = 0x12; - int32_prop_read_helper(payload, 6, MOSQ_ERR_SUCCESS, PROP_WILL_DELAY_INTERVAL, 0x45342312); + int32_prop_read_helper(CMD_WILL, payload, 6, MOSQ_ERR_SUCCESS, PROP_WILL_DELAY_INTERVAL, 0x45342312); } static void TEST_single_maximum_packet_size(void) @@ -627,7 +625,7 @@ static void TEST_single_maximum_packet_size(void) payload[4] = 0x23; payload[5] = 0x12; - int32_prop_read_helper(payload, 6, MOSQ_ERR_SUCCESS, PROP_MAXIMUM_PACKET_SIZE, 0x45342312); + int32_prop_read_helper(CONNECT, payload, 6, MOSQ_ERR_SUCCESS, PROP_MAXIMUM_PACKET_SIZE, 0x45342312); } static void TEST_single_server_keep_alive(void) @@ -640,7 +638,7 @@ static void TEST_single_server_keep_alive(void) payload[2] = 0x45; payload[3] = 0x34; - int16_prop_read_helper(payload, 4, MOSQ_ERR_SUCCESS, PROP_SERVER_KEEP_ALIVE, 0x4534); + int16_prop_read_helper(CONNACK, payload, 4, MOSQ_ERR_SUCCESS, PROP_SERVER_KEEP_ALIVE, 0x4534); } static void TEST_single_receive_maximum(void) @@ -653,7 +651,7 @@ static void TEST_single_receive_maximum(void) payload[2] = 0x68; payload[3] = 0x42; - int16_prop_read_helper(payload, 4, MOSQ_ERR_SUCCESS, PROP_RECEIVE_MAXIMUM, 0x6842); + int16_prop_read_helper(CONNACK, payload, 4, MOSQ_ERR_SUCCESS, PROP_RECEIVE_MAXIMUM, 0x6842); } static void TEST_single_topic_alias_maximum(void) @@ -666,7 +664,7 @@ static void TEST_single_topic_alias_maximum(void) payload[2] = 0x68; payload[3] = 0x42; - int16_prop_read_helper(payload, 4, MOSQ_ERR_SUCCESS, PROP_TOPIC_ALIAS_MAXIMUM, 0x6842); + int16_prop_read_helper(CONNECT, payload, 4, MOSQ_ERR_SUCCESS, PROP_TOPIC_ALIAS_MAXIMUM, 0x6842); } static void TEST_single_topic_alias(void) @@ -679,7 +677,7 @@ static void TEST_single_topic_alias(void) payload[2] = 0x68; payload[3] = 0x42; - int16_prop_read_helper(payload, 4, MOSQ_ERR_SUCCESS, PROP_TOPIC_ALIAS, 0x6842); + int16_prop_read_helper(PUBLISH, payload, 4, MOSQ_ERR_SUCCESS, PROP_TOPIC_ALIAS, 0x6842); } static void TEST_single_content_type(void) @@ -697,7 +695,7 @@ static void TEST_single_content_type(void) payload[7] = 'l'; payload[8] = 'o'; - string_prop_read_helper(payload, 9, MOSQ_ERR_SUCCESS, PROP_CONTENT_TYPE, "hello"); + string_prop_read_helper(PUBLISH, payload, 9, MOSQ_ERR_SUCCESS, PROP_CONTENT_TYPE, "hello"); } static void TEST_single_response_topic(void) @@ -715,7 +713,7 @@ static void TEST_single_response_topic(void) payload[7] = 'l'; payload[8] = 'o'; - string_prop_read_helper(payload, 9, MOSQ_ERR_SUCCESS, PROP_RESPONSE_TOPIC, "hello"); + string_prop_read_helper(CMD_WILL, payload, 9, MOSQ_ERR_SUCCESS, PROP_RESPONSE_TOPIC, "hello"); } static void TEST_single_assigned_client_identifier(void) @@ -733,7 +731,7 @@ static void TEST_single_assigned_client_identifier(void) payload[7] = 'l'; payload[8] = 'o'; - string_prop_read_helper(payload, 9, MOSQ_ERR_SUCCESS, PROP_ASSIGNED_CLIENT_IDENTIFIER, "hello"); + string_prop_read_helper(CONNACK, payload, 9, MOSQ_ERR_SUCCESS, PROP_ASSIGNED_CLIENT_IDENTIFIER, "hello"); } static void TEST_single_authentication_method(void) @@ -751,7 +749,7 @@ static void TEST_single_authentication_method(void) payload[7] = 'l'; payload[8] = 'o'; - string_prop_read_helper(payload, 9, MOSQ_ERR_SUCCESS, PROP_AUTHENTICATION_METHOD, "hello"); + string_prop_read_helper(AUTH, payload, 9, MOSQ_ERR_SUCCESS, PROP_AUTHENTICATION_METHOD, "hello"); } static void TEST_single_response_information(void) @@ -769,7 +767,7 @@ static void TEST_single_response_information(void) payload[7] = 'l'; payload[8] = 'o'; - string_prop_read_helper(payload, 9, MOSQ_ERR_SUCCESS, PROP_RESPONSE_INFO, "hello"); + string_prop_read_helper(CONNACK, payload, 9, MOSQ_ERR_SUCCESS, PROP_RESPONSE_INFO, "hello"); } static void TEST_single_server_reference(void) @@ -787,7 +785,7 @@ static void TEST_single_server_reference(void) payload[7] = 'l'; payload[8] = 'o'; - string_prop_read_helper(payload, 9, MOSQ_ERR_SUCCESS, PROP_SERVER_REFERENCE, "hello"); + string_prop_read_helper(CONNACK, payload, 9, MOSQ_ERR_SUCCESS, PROP_SERVER_REFERENCE, "hello"); } static void TEST_single_reason_string(void) @@ -805,7 +803,7 @@ static void TEST_single_reason_string(void) payload[7] = 'l'; payload[8] = 'o'; - string_prop_read_helper(payload, 9, MOSQ_ERR_SUCCESS, PROP_REASON_STRING, "hello"); + string_prop_read_helper(PUBCOMP, payload, 9, MOSQ_ERR_SUCCESS, PROP_REASON_STRING, "hello"); } static void TEST_single_correlation_data(void) @@ -823,7 +821,7 @@ static void TEST_single_correlation_data(void) payload[7] = 'l'; payload[8] = 9; - binary_prop_read_helper(payload, 9, MOSQ_ERR_SUCCESS, PROP_CORRELATION_DATA, &payload[4], 5); + binary_prop_read_helper(PUBLISH, payload, 9, MOSQ_ERR_SUCCESS, PROP_CORRELATION_DATA, &payload[4], 5); } static void TEST_single_authentication_data(void) @@ -841,7 +839,7 @@ static void TEST_single_authentication_data(void) payload[7] = 'l'; payload[8] = 9; - binary_prop_read_helper(payload, 9, MOSQ_ERR_SUCCESS, PROP_AUTHENTICATION_DATA, &payload[4], 5); + binary_prop_read_helper(CONNECT, payload, 9, MOSQ_ERR_SUCCESS, PROP_AUTHENTICATION_DATA, &payload[4], 5); } static void TEST_single_user_property(void) @@ -926,82 +924,82 @@ static void TEST_single_subscription_identifier(void) static void TEST_duplicate_payload_format_indicator(void) { - duplicate_byte_helper(PROP_PAYLOAD_FORMAT_INDICATOR); + duplicate_byte_helper(PUBLISH, PROP_PAYLOAD_FORMAT_INDICATOR); } static void TEST_duplicate_request_problem_information(void) { - duplicate_byte_helper(PROP_REQUEST_PROBLEM_INFO); + duplicate_byte_helper(CONNECT, PROP_REQUEST_PROBLEM_INFO); } static void TEST_duplicate_request_response_information(void) { - duplicate_byte_helper(PROP_REQUEST_RESPONSE_INFO); + duplicate_byte_helper(CONNECT, PROP_REQUEST_RESPONSE_INFO); } static void TEST_duplicate_maximum_qos(void) { - duplicate_byte_helper(PROP_MAXIMUM_QOS); + duplicate_byte_helper(CONNACK, PROP_MAXIMUM_QOS); } static void TEST_duplicate_retain_available(void) { - duplicate_byte_helper(PROP_RETAIN_AVAILABLE); + duplicate_byte_helper(CONNACK, PROP_RETAIN_AVAILABLE); } static void TEST_duplicate_wildcard_subscription_available(void) { - duplicate_byte_helper(PROP_WILDCARD_SUB_AVAILABLE); + duplicate_byte_helper(CONNACK, PROP_WILDCARD_SUB_AVAILABLE); } static void TEST_duplicate_subscription_identifier_available(void) { - duplicate_byte_helper(PROP_SUBSCRIPTION_ID_AVAILABLE); + duplicate_byte_helper(CONNACK, PROP_SUBSCRIPTION_ID_AVAILABLE); } static void TEST_duplicate_shared_subscription_available(void) { - duplicate_byte_helper(PROP_SHARED_SUB_AVAILABLE); + duplicate_byte_helper(CONNACK, PROP_SHARED_SUB_AVAILABLE); } static void TEST_duplicate_message_expiry_interval(void) { - duplicate_int32_helper(PROP_MESSAGE_EXPIRY_INTERVAL); + duplicate_int32_helper(PUBLISH, PROP_MESSAGE_EXPIRY_INTERVAL); } static void TEST_duplicate_session_expiry_interval(void) { - duplicate_int32_helper(PROP_SESSION_EXPIRY_INTERVAL); + duplicate_int32_helper(DISCONNECT, PROP_SESSION_EXPIRY_INTERVAL); } static void TEST_duplicate_will_delay_interval(void) { - duplicate_int32_helper(PROP_WILL_DELAY_INTERVAL); + duplicate_int32_helper(CMD_WILL, PROP_WILL_DELAY_INTERVAL); } static void TEST_duplicate_maximum_packet_size(void) { - duplicate_int32_helper(PROP_MAXIMUM_PACKET_SIZE); + duplicate_int32_helper(CONNECT, PROP_MAXIMUM_PACKET_SIZE); } static void TEST_duplicate_server_keep_alive(void) { - duplicate_int16_helper(PROP_SERVER_KEEP_ALIVE); + duplicate_int16_helper(CONNACK, PROP_SERVER_KEEP_ALIVE); } static void TEST_duplicate_receive_maximum(void) { - duplicate_int16_helper(PROP_RECEIVE_MAXIMUM); + duplicate_int16_helper(CONNACK, PROP_RECEIVE_MAXIMUM); } static void TEST_duplicate_topic_alias_maximum(void) { - duplicate_int16_helper(PROP_TOPIC_ALIAS_MAXIMUM); + duplicate_int16_helper(CONNECT, PROP_TOPIC_ALIAS_MAXIMUM); } static void TEST_duplicate_topic_alias(void) { - duplicate_int16_helper(PROP_TOPIC_ALIAS); + duplicate_int16_helper(PUBLISH, PROP_TOPIC_ALIAS); } static void TEST_duplicate_content_type(void) @@ -1041,12 +1039,12 @@ static void TEST_duplicate_reason_string(void) static void TEST_duplicate_correlation_data(void) { - duplicate_binary_helper(PROP_CORRELATION_DATA); + duplicate_binary_helper(PUBLISH, PROP_CORRELATION_DATA); } static void TEST_duplicate_authentication_data(void) { - duplicate_binary_helper(PROP_AUTHENTICATION_DATA); + duplicate_binary_helper(CONNACK, PROP_AUTHENTICATION_DATA); } static void TEST_duplicate_user_property(void) @@ -1098,37 +1096,37 @@ static void TEST_duplicate_subscription_identifier(void) static void TEST_bad_request_problem_information(void) { - bad_byte_helper(PROP_REQUEST_PROBLEM_INFO); + bad_byte_helper(CONNECT, PROP_REQUEST_PROBLEM_INFO); } static void TEST_bad_request_response_information(void) { - bad_byte_helper(PROP_REQUEST_RESPONSE_INFO); + bad_byte_helper(CONNECT, PROP_REQUEST_RESPONSE_INFO); } static void TEST_bad_maximum_qos(void) { - bad_byte_helper(PROP_MAXIMUM_QOS); + bad_byte_helper(CONNACK, PROP_MAXIMUM_QOS); } static void TEST_bad_retain_available(void) { - bad_byte_helper(PROP_RETAIN_AVAILABLE); + bad_byte_helper(CONNACK, PROP_RETAIN_AVAILABLE); } static void TEST_bad_wildcard_sub_available(void) { - bad_byte_helper(PROP_WILDCARD_SUB_AVAILABLE); + bad_byte_helper(CONNACK, PROP_WILDCARD_SUB_AVAILABLE); } static void TEST_bad_subscription_id_available(void) { - bad_byte_helper(PROP_SUBSCRIPTION_ID_AVAILABLE); + bad_byte_helper(CONNACK, PROP_SUBSCRIPTION_ID_AVAILABLE); } static void TEST_bad_shared_sub_available(void) { - bad_byte_helper(PROP_SHARED_SUB_AVAILABLE); + bad_byte_helper(CONNACK, PROP_SHARED_SUB_AVAILABLE); } static void TEST_bad_maximum_packet_size(void) @@ -1143,7 +1141,7 @@ static void TEST_bad_maximum_packet_size(void) payload[4] = 0; payload[5] = 0; /* 0 is invalid */ - int32_prop_read_helper(payload, 6, MOSQ_ERR_PROTOCOL, PROP_MAXIMUM_PACKET_SIZE, 0); + int32_prop_read_helper(CONNACK, payload, 6, MOSQ_ERR_PROTOCOL, PROP_MAXIMUM_PACKET_SIZE, 0); } static void TEST_bad_receive_maximum(void) @@ -1156,7 +1154,7 @@ static void TEST_bad_receive_maximum(void) payload[2] = 0; payload[3] = 0; /* 0 is invalid */ - int32_prop_read_helper(payload, 4, MOSQ_ERR_PROTOCOL, PROP_RECEIVE_MAXIMUM, 0); + int32_prop_read_helper(CONNECT, payload, 4, MOSQ_ERR_PROTOCOL, PROP_RECEIVE_MAXIMUM, 0); } static void TEST_bad_topic_alias(void) @@ -1169,7 +1167,7 @@ static void TEST_bad_topic_alias(void) payload[2] = 0; payload[3] = 0; /* 0 is invalid */ - int32_prop_read_helper(payload, 4, MOSQ_ERR_PROTOCOL, PROP_TOPIC_ALIAS, 0); + int32_prop_read_helper(PUBLISH, payload, 4, MOSQ_ERR_PROTOCOL, PROP_TOPIC_ALIAS, 0); } static void TEST_bad_content_type(void) @@ -1219,7 +1217,7 @@ static void TEST_packet_connect(void) memset(&packet, 0, sizeof(struct mosquitto__packet)); packet.payload = payload; packet.remaining_length = sizeof(payload);; - rc = property__read_all(&packet, &properties); + rc = property__read_all(CONNECT, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); CU_ASSERT_PTR_NOT_NULL(properties->next); @@ -1308,7 +1306,7 @@ static void TEST_packet_connack(void) memset(&packet, 0, sizeof(struct mosquitto__packet)); packet.payload = payload; packet.remaining_length = sizeof(payload);; - rc = property__read_all(&packet, &properties); + rc = property__read_all(CONNACK, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); CU_ASSERT_PTR_NOT_NULL(properties->next); @@ -1432,7 +1430,7 @@ static void TEST_packet_publish(void) memset(&packet, 0, sizeof(struct mosquitto__packet)); packet.payload = payload; packet.remaining_length = sizeof(payload);; - rc = property__read_all(&packet, &properties); + rc = property__read_all(PUBLISH, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); CU_ASSERT_PTR_NOT_NULL(properties->next); @@ -1489,22 +1487,22 @@ static void TEST_packet_publish(void) static void TEST_packet_puback(void) { - packet_helper_reason_string_user_property(); + packet_helper_reason_string_user_property(PUBACK); } static void TEST_packet_pubrec(void) { - packet_helper_reason_string_user_property(); + packet_helper_reason_string_user_property(PUBREC); } static void TEST_packet_pubrel(void) { - packet_helper_reason_string_user_property(); + packet_helper_reason_string_user_property(PUBREL); } static void TEST_packet_pubcomp(void) { - packet_helper_reason_string_user_property(); + packet_helper_reason_string_user_property(PUBCOMP); } static void TEST_packet_subscribe(void) @@ -1522,7 +1520,7 @@ static void TEST_packet_subscribe(void) memset(&packet, 0, sizeof(struct mosquitto__packet)); packet.payload = payload; packet.remaining_length = sizeof(payload);; - rc = property__read_all(&packet, &properties); + rc = property__read_all(SUBSCRIBE, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); CU_ASSERT_PTR_NOT_NULL(properties->next); @@ -1545,7 +1543,7 @@ static void TEST_packet_subscribe(void) static void TEST_packet_suback(void) { - packet_helper_reason_string_user_property(); + packet_helper_reason_string_user_property(SUBACK); } static void TEST_packet_unsubscribe(void) @@ -1562,7 +1560,7 @@ static void TEST_packet_unsubscribe(void) memset(&packet, 0, sizeof(struct mosquitto__packet)); packet.payload = payload; packet.remaining_length = sizeof(payload);; - rc = property__read_all(&packet, &properties); + rc = property__read_all(UNSUBSCRIBE, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); p = properties; @@ -1579,7 +1577,7 @@ static void TEST_packet_unsubscribe(void) static void TEST_packet_unsuback(void) { - packet_helper_reason_string_user_property(); + packet_helper_reason_string_user_property(UNSUBACK); } static void TEST_packet_disconnect(void) @@ -1598,7 +1596,7 @@ static void TEST_packet_disconnect(void) memset(&packet, 0, sizeof(struct mosquitto__packet)); packet.payload = payload; packet.remaining_length = sizeof(payload);; - rc = property__read_all(&packet, &properties); + rc = property__read_all(DISCONNECT, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); CU_ASSERT_PTR_NOT_NULL(properties->next); @@ -1642,7 +1640,7 @@ static void TEST_packet_auth(void) memset(&packet, 0, sizeof(struct mosquitto__packet)); packet.payload = payload; packet.remaining_length = sizeof(payload);; - rc = property__read_all(&packet, &properties); + rc = property__read_all(AUTH, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); CU_ASSERT_PTR_NOT_NULL(properties->next); diff --git a/test/unit/property_write.c b/test/unit/property_write.c index dae5282910..5eb9caee7e 100644 --- a/test/unit/property_write.c +++ b/test/unit/property_write.c @@ -6,6 +6,7 @@ #include "packet_mosq.h" static void byte_prop_write_helper( + int command, int remaining_length, int rc_expected, int identifier, @@ -29,7 +30,7 @@ static void byte_prop_write_helper( property__write_all(&packet, &property); packet.pos = 0; - rc = property__read_all(&packet, &properties); + rc = property__read_all(command, &packet, &properties); CU_ASSERT_EQUAL(rc, rc_expected); CU_ASSERT_EQUAL(packet.pos, remaining_length); @@ -45,6 +46,7 @@ static void byte_prop_write_helper( static void int32_prop_write_helper( + int command, int remaining_length, int rc_expected, int identifier, @@ -68,7 +70,7 @@ static void int32_prop_write_helper( property__write_all(&packet, &property); packet.pos = 0; - rc = property__read_all(&packet, &properties); + rc = property__read_all(command, &packet, &properties); CU_ASSERT_EQUAL(rc, rc_expected); CU_ASSERT_EQUAL(packet.pos, remaining_length); @@ -84,6 +86,7 @@ static void int32_prop_write_helper( static void int16_prop_write_helper( + int command, int remaining_length, int rc_expected, int identifier, @@ -107,7 +110,7 @@ static void int16_prop_write_helper( property__write_all(&packet, &property); packet.pos = 0; - rc = property__read_all(&packet, &properties); + rc = property__read_all(command, &packet, &properties); CU_ASSERT_EQUAL(rc, rc_expected); CU_ASSERT_EQUAL(packet.pos, remaining_length); @@ -122,6 +125,7 @@ static void int16_prop_write_helper( } static void string_prop_write_helper( + int command, int remaining_length, int rc_expected, int identifier, @@ -146,7 +150,7 @@ static void string_prop_write_helper( property__write_all(&packet, &property); packet.pos = 0; - rc = property__read_all(&packet, &properties); + rc = property__read_all(command, &packet, &properties); CU_ASSERT_EQUAL(rc, rc_expected); CU_ASSERT_EQUAL(packet.pos, remaining_length); @@ -164,6 +168,7 @@ static void string_prop_write_helper( static void binary_prop_write_helper( + int command, int remaining_length, int rc_expected, int identifier, @@ -190,7 +195,7 @@ static void binary_prop_write_helper( property__write_all(&packet, &property); packet.pos = 0; - rc = property__read_all(&packet, &properties); + rc = property__read_all(command, &packet, &properties); CU_ASSERT_EQUAL(rc, rc_expected); CU_ASSERT_EQUAL(packet.pos, remaining_length); @@ -235,7 +240,7 @@ static void string_pair_prop_write_helper( property__write_all(&packet, &property); packet.pos = 0; - rc = property__read_all(&packet, &properties); + rc = property__read_all(CONNECT, &packet, &properties); CU_ASSERT_EQUAL(rc, rc_expected); CU_ASSERT_EQUAL(packet.pos, remaining_length); @@ -282,7 +287,7 @@ static void varint_prop_write_helper( property__write_all(&packet, &property); packet.pos = 0; - rc = property__read_all(&packet, &properties); + rc = property__read_all(PUBLISH, &packet, &properties); CU_ASSERT_EQUAL(rc, rc_expected); if(properties){ @@ -333,131 +338,131 @@ static void TEST_bad_identifier(void) static void TEST_single_payload_format_indicator(void) { - byte_prop_write_helper(3, MOSQ_ERR_SUCCESS, PROP_PAYLOAD_FORMAT_INDICATOR, 1); + byte_prop_write_helper(PUBLISH, 3, MOSQ_ERR_SUCCESS, PROP_PAYLOAD_FORMAT_INDICATOR, 1); } static void TEST_single_request_problem_information(void) { - byte_prop_write_helper(3, MOSQ_ERR_SUCCESS, PROP_REQUEST_PROBLEM_INFO, 1); + byte_prop_write_helper(CONNECT, 3, MOSQ_ERR_SUCCESS, PROP_REQUEST_PROBLEM_INFO, 1); } static void TEST_single_request_response_information(void) { - byte_prop_write_helper(3, MOSQ_ERR_SUCCESS, PROP_REQUEST_RESPONSE_INFO, 1); + byte_prop_write_helper(CONNECT, 3, MOSQ_ERR_SUCCESS, PROP_REQUEST_RESPONSE_INFO, 1); } static void TEST_single_maximum_qos(void) { - byte_prop_write_helper(3, MOSQ_ERR_SUCCESS, PROP_MAXIMUM_QOS, 1); + byte_prop_write_helper(CONNACK, 3, MOSQ_ERR_SUCCESS, PROP_MAXIMUM_QOS, 1); } static void TEST_single_retain_available(void) { - byte_prop_write_helper(3, MOSQ_ERR_SUCCESS, PROP_RETAIN_AVAILABLE, 1); + byte_prop_write_helper(CONNACK, 3, MOSQ_ERR_SUCCESS, PROP_RETAIN_AVAILABLE, 1); } static void TEST_single_wildcard_subscription_available(void) { - byte_prop_write_helper(3, MOSQ_ERR_SUCCESS, PROP_WILDCARD_SUB_AVAILABLE, 0); + byte_prop_write_helper(CONNACK, 3, MOSQ_ERR_SUCCESS, PROP_WILDCARD_SUB_AVAILABLE, 0); } static void TEST_single_subscription_identifier_available(void) { - byte_prop_write_helper(3, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_ID_AVAILABLE, 0); + byte_prop_write_helper(CONNACK, 3, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_ID_AVAILABLE, 0); } static void TEST_single_shared_subscription_available(void) { - byte_prop_write_helper(3, MOSQ_ERR_SUCCESS, PROP_SHARED_SUB_AVAILABLE, 1); + byte_prop_write_helper(CONNACK, 3, MOSQ_ERR_SUCCESS, PROP_SHARED_SUB_AVAILABLE, 1); } static void TEST_single_message_expiry_interval(void) { - int32_prop_write_helper(6, MOSQ_ERR_SUCCESS, PROP_MESSAGE_EXPIRY_INTERVAL, 0x12233445); + int32_prop_write_helper(PUBLISH, 6, MOSQ_ERR_SUCCESS, PROP_MESSAGE_EXPIRY_INTERVAL, 0x12233445); } static void TEST_single_session_expiry_interval(void) { - int32_prop_write_helper(6, MOSQ_ERR_SUCCESS, PROP_SESSION_EXPIRY_INTERVAL, 0x45342312); + int32_prop_write_helper(CONNACK, 6, MOSQ_ERR_SUCCESS, PROP_SESSION_EXPIRY_INTERVAL, 0x45342312); } static void TEST_single_will_delay_interval(void) { - int32_prop_write_helper(6, MOSQ_ERR_SUCCESS, PROP_WILL_DELAY_INTERVAL, 0x45342312); + int32_prop_write_helper(CMD_WILL, 6, MOSQ_ERR_SUCCESS, PROP_WILL_DELAY_INTERVAL, 0x45342312); } static void TEST_single_maximum_packet_size(void) { - int32_prop_write_helper(6, MOSQ_ERR_SUCCESS, PROP_MAXIMUM_PACKET_SIZE, 0x45342312); + int32_prop_write_helper(CONNECT, 6, MOSQ_ERR_SUCCESS, PROP_MAXIMUM_PACKET_SIZE, 0x45342312); } static void TEST_single_server_keep_alive(void) { - int16_prop_write_helper(4, MOSQ_ERR_SUCCESS, PROP_SERVER_KEEP_ALIVE, 0x4534); + int16_prop_write_helper(CONNACK, 4, MOSQ_ERR_SUCCESS, PROP_SERVER_KEEP_ALIVE, 0x4534); } static void TEST_single_receive_maximum(void) { - int16_prop_write_helper(4, MOSQ_ERR_SUCCESS, PROP_RECEIVE_MAXIMUM, 0x6842); + int16_prop_write_helper(CONNACK, 4, MOSQ_ERR_SUCCESS, PROP_RECEIVE_MAXIMUM, 0x6842); } static void TEST_single_topic_alias_maximum(void) { - int16_prop_write_helper(4, MOSQ_ERR_SUCCESS, PROP_TOPIC_ALIAS_MAXIMUM, 0x6842); + int16_prop_write_helper(CONNECT, 4, MOSQ_ERR_SUCCESS, PROP_TOPIC_ALIAS_MAXIMUM, 0x6842); } static void TEST_single_topic_alias(void) { - int16_prop_write_helper(4, MOSQ_ERR_SUCCESS, PROP_TOPIC_ALIAS, 0x6842); + int16_prop_write_helper(PUBLISH, 4, MOSQ_ERR_SUCCESS, PROP_TOPIC_ALIAS, 0x6842); } static void TEST_single_content_type(void) { - string_prop_write_helper(9, MOSQ_ERR_SUCCESS, PROP_CONTENT_TYPE, "hello"); + string_prop_write_helper(PUBLISH, 9, MOSQ_ERR_SUCCESS, PROP_CONTENT_TYPE, "hello"); } static void TEST_single_response_topic(void) { - string_prop_write_helper(9, MOSQ_ERR_SUCCESS, PROP_RESPONSE_TOPIC, "hello"); + string_prop_write_helper(CMD_WILL, 9, MOSQ_ERR_SUCCESS, PROP_RESPONSE_TOPIC, "hello"); } static void TEST_single_assigned_client_identifier(void) { - string_prop_write_helper(9, MOSQ_ERR_SUCCESS, PROP_ASSIGNED_CLIENT_IDENTIFIER, "hello"); + string_prop_write_helper(CONNACK, 9, MOSQ_ERR_SUCCESS, PROP_ASSIGNED_CLIENT_IDENTIFIER, "hello"); } static void TEST_single_authentication_method(void) { - string_prop_write_helper(9, MOSQ_ERR_SUCCESS, PROP_AUTHENTICATION_METHOD, "hello"); + string_prop_write_helper(CONNECT, 9, MOSQ_ERR_SUCCESS, PROP_AUTHENTICATION_METHOD, "hello"); } static void TEST_single_response_information(void) { - string_prop_write_helper(9, MOSQ_ERR_SUCCESS, PROP_RESPONSE_INFO, "hello"); + string_prop_write_helper(CONNACK, 9, MOSQ_ERR_SUCCESS, PROP_RESPONSE_INFO, "hello"); } static void TEST_single_server_reference(void) { - string_prop_write_helper(9, MOSQ_ERR_SUCCESS, PROP_SERVER_REFERENCE, "hello"); + string_prop_write_helper(CONNACK, 9, MOSQ_ERR_SUCCESS, PROP_SERVER_REFERENCE, "hello"); } static void TEST_single_reason_string(void) { - string_prop_write_helper(9, MOSQ_ERR_SUCCESS, PROP_REASON_STRING, "hello"); + string_prop_write_helper(PUBREC, 9, MOSQ_ERR_SUCCESS, PROP_REASON_STRING, "hello"); } static void TEST_single_correlation_data(void) { uint8_t payload[5] = {1, 'e', 0, 'l', 9}; - binary_prop_write_helper(9, MOSQ_ERR_SUCCESS, PROP_CORRELATION_DATA, payload, 5); + binary_prop_write_helper(PUBLISH, 9, MOSQ_ERR_SUCCESS, PROP_CORRELATION_DATA, payload, 5); } static void TEST_single_authentication_data(void) { uint8_t payload[5] = {1, 'e', 0, 'l', 9}; - binary_prop_write_helper(9, MOSQ_ERR_SUCCESS, PROP_AUTHENTICATION_DATA, payload, 5); + binary_prop_write_helper(CONNECT, 9, MOSQ_ERR_SUCCESS, PROP_AUTHENTICATION_DATA, payload, 5); } static void TEST_single_user_property(void) From eefa7f76047662fd91d16e7f60cde7e03459fec4 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 25 Oct 2018 12:03:22 +0100 Subject: [PATCH 059/254] All existing commands read properties. --- lib/handle_connack.c | 23 +++++++++++++++++------ lib/handle_pubackcomp.c | 9 +++++++++ lib/handle_publish.c | 10 ++++++++++ lib/handle_pubrec.c | 9 +++++++++ lib/handle_pubrel.c | 9 +++++++++ lib/handle_suback.c | 10 ++++++++++ lib/handle_unsuback.c | 10 ++++++++++ src/handle_connack.c | 20 +++++++++++++++----- src/handle_connect.c | 13 ++++++++++++- src/handle_subscribe.c | 1 - src/handle_unsubscribe.c | 15 +++++++++------ 11 files changed, 110 insertions(+), 19 deletions(-) diff --git a/lib/handle_connack.c b/lib/handle_connack.c index 9d0a01cd6d..b312501718 100644 --- a/lib/handle_connack.c +++ b/lib/handle_connack.c @@ -22,35 +22,46 @@ and the Eclipse Distribution License is available at #include "logging_mosq.h" #include "memory_mosq.h" #include "messages_mosq.h" +#include "mqtt_protocol.h" #include "net_mosq.h" #include "packet_mosq.h" +#include "property_mosq.h" #include "read_handle.h" int handle__connack(struct mosquitto *mosq) { uint8_t connect_flags; - uint8_t result; + uint8_t reason_code; int rc; + struct mqtt5__property *properties = NULL; assert(mosq); rc = packet__read_byte(&mosq->in_packet, &connect_flags); if(rc) return rc; - rc = packet__read_byte(&mosq->in_packet, &result); + rc = packet__read_byte(&mosq->in_packet, &reason_code); if(rc) return rc; - log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received CONNACK (%d)", mosq->id, result); + + if(mosq->protocol == mosq_p_mqtt5){ + rc = property__read_all(CONNACK, &mosq->in_packet, &properties); + if(rc) return rc; + property__free_all(&properties); + } + property__free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ + + log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received CONNACK (%d)", mosq->id, reason_code); pthread_mutex_lock(&mosq->callback_mutex); if(mosq->on_connect){ mosq->in_callback = true; - mosq->on_connect(mosq, mosq->userdata, result); + mosq->on_connect(mosq, mosq->userdata, reason_code); mosq->in_callback = false; } if(mosq->on_connect_with_flags){ mosq->in_callback = true; - mosq->on_connect_with_flags(mosq, mosq->userdata, result, connect_flags); + mosq->on_connect_with_flags(mosq, mosq->userdata, reason_code, connect_flags); mosq->in_callback = false; } pthread_mutex_unlock(&mosq->callback_mutex); - switch(result){ + switch(reason_code){ case 0: if(mosq->state != mosq_cs_disconnecting){ mosq->state = mosq_cs_connected; diff --git a/lib/handle_pubackcomp.c b/lib/handle_pubackcomp.c index a6586f8f00..8f5f0a309d 100644 --- a/lib/handle_pubackcomp.c +++ b/lib/handle_pubackcomp.c @@ -44,10 +44,19 @@ int handle__pubackcomp(struct mosquitto *mosq, const char *type) { uint16_t mid; int rc; + struct mqtt5__property *properties = NULL; assert(mosq); rc = packet__read_uint16(&mosq->in_packet, &mid); if(rc) return rc; + + if(mosq->protocol == mosq_p_mqtt5){ + rc = property__read_all(PUBACK, &mosq->in_packet, &properties); + if(rc) return rc; + /* Immediately free, we don't do anything with Reason String or User Property at the moment */ + property__free_all(&properties); + } + #ifdef WITH_BROKER log__printf(NULL, MOSQ_LOG_DEBUG, "Received %s from %s (Mid: %d)", type, mosq->id, mid); diff --git a/lib/handle_publish.c b/lib/handle_publish.c index f8092f8944..5a253aa08e 100644 --- a/lib/handle_publish.c +++ b/lib/handle_publish.c @@ -23,8 +23,10 @@ and the Eclipse Distribution License is available at #include "mosquitto_internal.h" #include "logging_mosq.h" #include "memory_mosq.h" +#include "mqtt_protocol.h" #include "messages_mosq.h" #include "packet_mosq.h" +#include "property_mosq.h" #include "send_mosq.h" #include "time_mosq.h" @@ -36,6 +38,7 @@ int handle__publish(struct mosquitto *mosq) int rc = 0; uint16_t mid; int slen; + struct mqtt5__property *properties = NULL; assert(mosq); @@ -67,6 +70,13 @@ int handle__publish(struct mosquitto *mosq) message->msg.mid = (int)mid; } + if(mosq->protocol == mosq_p_mqtt5){ + rc = property__read_all(PUBLISH, &mosq->in_packet, &properties); + if(rc) return rc; + property__free_all(&properties); + } + property__free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ + message->msg.payloadlen = mosq->in_packet.remaining_length - mosq->in_packet.pos; if(message->msg.payloadlen){ message->msg.payload = mosquitto__calloc(message->msg.payloadlen+1, sizeof(uint8_t)); diff --git a/lib/handle_pubrec.c b/lib/handle_pubrec.c index 3f79d50622..227d27befb 100644 --- a/lib/handle_pubrec.c +++ b/lib/handle_pubrec.c @@ -39,10 +39,19 @@ int handle__pubrec(struct mosquitto *mosq) { uint16_t mid; int rc; + struct mqtt5__property *properties = NULL; assert(mosq); rc = packet__read_uint16(&mosq->in_packet, &mid); if(rc) return rc; + + if(mosq->protocol == mosq_p_mqtt5){ + rc = property__read_all(PUBREC, &mosq->in_packet, &properties); + if(rc) return rc; + /* Immediately free, we don't do anything with Reason String or User Property at the moment */ + property__free_all(&properties); + } + #ifdef WITH_BROKER log__printf(NULL, MOSQ_LOG_DEBUG, "Received PUBREC from %s (Mid: %d)", mosq->id, mid); diff --git a/lib/handle_pubrel.c b/lib/handle_pubrel.c index 4e4bf04863..2630f1f241 100644 --- a/lib/handle_pubrel.c +++ b/lib/handle_pubrel.c @@ -43,6 +43,7 @@ int handle__pubrel(struct mosquitto_db *db, struct mosquitto *mosq) struct mosquitto_message_all *message = NULL; #endif int rc; + struct mqtt5__property *properties = NULL; assert(mosq); if(mosq->protocol != mosq_p_mqtt31){ @@ -52,6 +53,14 @@ int handle__pubrel(struct mosquitto_db *db, struct mosquitto *mosq) } rc = packet__read_uint16(&mosq->in_packet, &mid); if(rc) return rc; + + if(mosq->protocol == mosq_p_mqtt5){ + rc = property__read_all(PUBREL, &mosq->in_packet, &properties); + if(rc) return rc; + /* Immediately free, we don't do anything with Reason String or User Property at the moment */ + property__free_all(&properties); + } + #ifdef WITH_BROKER log__printf(NULL, MOSQ_LOG_DEBUG, "Received PUBREL from %s (Mid: %d)", mosq->id, mid); diff --git a/lib/handle_suback.c b/lib/handle_suback.c index d6e3d19c4a..512415f250 100644 --- a/lib/handle_suback.c +++ b/lib/handle_suback.c @@ -26,7 +26,9 @@ and the Eclipse Distribution License is available at #include "mosquitto_internal.h" #include "logging_mosq.h" #include "memory_mosq.h" +#include "mqtt_protocol.h" #include "packet_mosq.h" +#include "property_mosq.h" int handle__suback(struct mosquitto *mosq) @@ -37,6 +39,7 @@ int handle__suback(struct mosquitto *mosq) int qos_count; int i = 0; int rc; + struct mqtt5__property *properties = NULL; assert(mosq); #ifdef WITH_BROKER @@ -47,6 +50,13 @@ int handle__suback(struct mosquitto *mosq) rc = packet__read_uint16(&mosq->in_packet, &mid); if(rc) return rc; + if(mosq->protocol == mosq_p_mqtt5){ + rc = property__read_all(SUBACK, &mosq->in_packet, &properties); + if(rc) return rc; + /* Immediately free, we don't do anything with Reason String or User Property at the moment */ + property__free_all(&properties); + } + qos_count = mosq->in_packet.remaining_length - mosq->in_packet.pos; granted_qos = mosquitto__malloc(qos_count*sizeof(int)); if(!granted_qos) return MOSQ_ERR_NOMEM; diff --git a/lib/handle_unsuback.c b/lib/handle_unsuback.c index 357ef5c9c8..0c403175e6 100644 --- a/lib/handle_unsuback.c +++ b/lib/handle_unsuback.c @@ -31,6 +31,7 @@ and the Eclipse Distribution License is available at #include "mqtt_protocol.h" #include "net_mosq.h" #include "packet_mosq.h" +#include "property_mosq.h" #include "read_handle.h" #include "send_mosq.h" #include "util_mosq.h" @@ -40,6 +41,7 @@ int handle__unsuback(struct mosquitto *mosq) { uint16_t mid; int rc; + struct mqtt5__property *properties = NULL; assert(mosq); #ifdef WITH_BROKER @@ -49,6 +51,14 @@ int handle__unsuback(struct mosquitto *mosq) #endif rc = packet__read_uint16(&mosq->in_packet, &mid); if(rc) return rc; + + if(mosq->protocol == mosq_p_mqtt5){ + rc = property__read_all(UNSUBACK, &mosq->in_packet, &properties); + if(rc) return rc; + /* Immediately free, we don't do anything with Reason String or User Property at the moment */ + property__free_all(&properties); + } + #ifndef WITH_BROKER pthread_mutex_lock(&mosq->callback_mutex); if(mosq->on_unsubscribe){ diff --git a/src/handle_connack.c b/src/handle_connack.c index 0124ce605f..fd289b5f41 100644 --- a/src/handle_connack.c +++ b/src/handle_connack.c @@ -28,20 +28,30 @@ and the Eclipse Distribution License is available at int handle__connack(struct mosquitto_db *db, struct mosquitto *context) { - uint8_t byte; - uint8_t rc; + int rc; + uint8_t connect_acknowledge; + uint8_t reason_code; int i; char *notification_topic; int notification_topic_len; char notification_payload; + struct mqtt5__property *properties = NULL; if(!context){ return MOSQ_ERR_INVAL; } log__printf(NULL, MOSQ_LOG_DEBUG, "Received CONNACK on connection %s.", context->id); - if(packet__read_byte(&context->in_packet, &byte)) return 1; // Reserved byte, not used - if(packet__read_byte(&context->in_packet, &rc)) return 1; - switch(rc){ + if(packet__read_byte(&context->in_packet, &connect_acknowledge)) return 1; + if(packet__read_byte(&context->in_packet, &reason_code)) return 1; + + if(context->protocol == mosq_p_mqtt5){ + rc = property__read_all(CONNACK, &context->in_packet, &properties); + if(rc) return rc; + property__free_all(&properties); + } + property__free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ + + switch(reason_code){ case CONNACK_ACCEPTED: if(context->bridge){ if(context->bridge->notifications){ diff --git a/src/handle_connect.c b/src/handle_connect.c index c0e42489cf..6a4680aec8 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -304,7 +304,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) if(protocol_version == PROTOCOL_VERSION_v5){ rc = property__read_all(CMD_WILL, &context->in_packet, &will_struct->properties); if(rc) return rc; - property__free_all(&will_struct->properties); + property__free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ } if(packet__read_string(&context->in_packet, &will_topic, &slen)){ rc = 1; @@ -721,9 +721,20 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) int handle__disconnect(struct mosquitto_db *db, struct mosquitto *context) { + int rc; + struct mqtt5__property *properties = NULL; + if(!context){ return MOSQ_ERR_INVAL; } + + if(context->protocol == mosq_p_mqtt5){ + rc = property__read_all(DISCONNECT, &context->in_packet, &properties); + if(rc) return rc; + property__free_all(&properties); + } + property__free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ + if(context->in_packet.remaining_length != 0){ return MOSQ_ERR_PROTOCOL; } diff --git a/src/handle_subscribe.c b/src/handle_subscribe.c index a134bf55ce..e592ec831a 100644 --- a/src/handle_subscribe.c +++ b/src/handle_subscribe.c @@ -43,7 +43,6 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) if(!context) return MOSQ_ERR_INVAL; log__printf(NULL, MOSQ_LOG_DEBUG, "Received SUBSCRIBE from %s", context->id); - /* FIXME - plenty of potential for memory leaks here */ if(context->protocol != mosq_p_mqtt31){ if((context->in_packet.command&0x0F) != 0x02){ diff --git a/src/handle_unsubscribe.c b/src/handle_unsubscribe.c index 03848d8d53..5a13068411 100644 --- a/src/handle_unsubscribe.c +++ b/src/handle_unsubscribe.c @@ -24,18 +24,14 @@ and the Eclipse Distribution License is available at #include "mqtt_protocol.h" #include "packet_mosq.h" #include "send_mosq.h" -/* -#include "sys_tree.h" -#include "time_mosq.h" -#include "tls_mosq.h" -#include "util_mosq.h" -*/ int handle__unsubscribe(struct mosquitto_db *db, struct mosquitto *context) { uint16_t mid; char *sub; int slen; + int rc; + struct mqtt5__property *properties = NULL; if(!context) return MOSQ_ERR_INVAL; log__printf(NULL, MOSQ_LOG_DEBUG, "Received UNSUBSCRIBE from %s", context->id); @@ -47,6 +43,13 @@ int handle__unsubscribe(struct mosquitto_db *db, struct mosquitto *context) } if(packet__read_uint16(&context->in_packet, &mid)) return 1; + if(context->protocol == mosq_p_mqtt5){ + rc = property__read_all(UNSUBSCRIBE, &context->in_packet, &properties); + if(rc) return rc; + /* Immediately free, we don't do anything with User Property at the moment */ + property__free_all(&properties); + } + if(context->protocol == mosq_p_mqtt311 || context->protocol == mosq_p_mqtt5){ if(context->in_packet.pos == context->in_packet.remaining_length){ /* No topic specified, protocol error. */ From ca40255720405528e376a65de9526a27a5ade7d7 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 25 Oct 2018 12:12:57 +0100 Subject: [PATCH 060/254] mid == 0 is a protocol error. --- lib/handle_pubackcomp.c | 1 + lib/handle_publish.c | 4 ++++ lib/handle_pubrec.c | 1 + lib/handle_pubrel.c | 1 + lib/handle_suback.c | 1 + lib/handle_unsuback.c | 1 + src/handle_publish.c | 4 ++++ src/handle_subscribe.c | 1 + src/handle_unsubscribe.c | 1 + 9 files changed, 15 insertions(+) diff --git a/lib/handle_pubackcomp.c b/lib/handle_pubackcomp.c index 8f5f0a309d..e9f0d4f4eb 100644 --- a/lib/handle_pubackcomp.c +++ b/lib/handle_pubackcomp.c @@ -49,6 +49,7 @@ int handle__pubackcomp(struct mosquitto *mosq, const char *type) assert(mosq); rc = packet__read_uint16(&mosq->in_packet, &mid); if(rc) return rc; + if(mid == 0) return MOSQ_ERR_PROTOCOL; if(mosq->protocol == mosq_p_mqtt5){ rc = property__read_all(PUBACK, &mosq->in_packet, &properties); diff --git a/lib/handle_publish.c b/lib/handle_publish.c index 5a253aa08e..44257c6900 100644 --- a/lib/handle_publish.c +++ b/lib/handle_publish.c @@ -67,6 +67,10 @@ int handle__publish(struct mosquitto *mosq) message__cleanup(&message); return rc; } + if(mid == 0){ + message__cleanup(&message); + return MOSQ_ERR_PROTOCOL; + } message->msg.mid = (int)mid; } diff --git a/lib/handle_pubrec.c b/lib/handle_pubrec.c index 227d27befb..1d6401b0b6 100644 --- a/lib/handle_pubrec.c +++ b/lib/handle_pubrec.c @@ -44,6 +44,7 @@ int handle__pubrec(struct mosquitto *mosq) assert(mosq); rc = packet__read_uint16(&mosq->in_packet, &mid); if(rc) return rc; + if(mid == 0) return MOSQ_ERR_PROTOCOL; if(mosq->protocol == mosq_p_mqtt5){ rc = property__read_all(PUBREC, &mosq->in_packet, &properties); diff --git a/lib/handle_pubrel.c b/lib/handle_pubrel.c index 2630f1f241..7ed08010c9 100644 --- a/lib/handle_pubrel.c +++ b/lib/handle_pubrel.c @@ -53,6 +53,7 @@ int handle__pubrel(struct mosquitto_db *db, struct mosquitto *mosq) } rc = packet__read_uint16(&mosq->in_packet, &mid); if(rc) return rc; + if(mid == 0) return MOSQ_ERR_PROTOCOL; if(mosq->protocol == mosq_p_mqtt5){ rc = property__read_all(PUBREL, &mosq->in_packet, &properties); diff --git a/lib/handle_suback.c b/lib/handle_suback.c index 512415f250..2b23e134a5 100644 --- a/lib/handle_suback.c +++ b/lib/handle_suback.c @@ -49,6 +49,7 @@ int handle__suback(struct mosquitto *mosq) #endif rc = packet__read_uint16(&mosq->in_packet, &mid); if(rc) return rc; + if(mid == 0) return MOSQ_ERR_PROTOCOL; if(mosq->protocol == mosq_p_mqtt5){ rc = property__read_all(SUBACK, &mosq->in_packet, &properties); diff --git a/lib/handle_unsuback.c b/lib/handle_unsuback.c index 0c403175e6..1e7fae8df6 100644 --- a/lib/handle_unsuback.c +++ b/lib/handle_unsuback.c @@ -51,6 +51,7 @@ int handle__unsuback(struct mosquitto *mosq) #endif rc = packet__read_uint16(&mosq->in_packet, &mid); if(rc) return rc; + if(mid == 0) return MOSQ_ERR_PROTOCOL; if(mosq->protocol == mosq_p_mqtt5){ rc = property__read_all(UNSUBACK, &mosq->in_packet, &properties); diff --git a/src/handle_publish.c b/src/handle_publish.c index f5850a3241..b51949f56a 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -131,6 +131,10 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) mosquitto__free(topic); return 1; } + if(mid == 0){ + mosquitto__free(topic); + return MOSQ_ERR_PROTOCOL; + } } if(context->protocol == mosq_p_mqtt5){ diff --git a/src/handle_subscribe.c b/src/handle_subscribe.c index e592ec831a..ebab3156df 100644 --- a/src/handle_subscribe.c +++ b/src/handle_subscribe.c @@ -50,6 +50,7 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) } } if(packet__read_uint16(&context->in_packet, &mid)) return 1; + if(mid == 0) return MOSQ_ERR_PROTOCOL; if(context->protocol == mosq_p_mqtt5){ rc = property__read_all(SUBSCRIBE, &context->in_packet, &properties); diff --git a/src/handle_unsubscribe.c b/src/handle_unsubscribe.c index 5a13068411..1838427d3c 100644 --- a/src/handle_unsubscribe.c +++ b/src/handle_unsubscribe.c @@ -42,6 +42,7 @@ int handle__unsubscribe(struct mosquitto_db *db, struct mosquitto *context) } } if(packet__read_uint16(&context->in_packet, &mid)) return 1; + if(mid == 0) return MOSQ_ERR_PROTOCOL; if(context->protocol == mosq_p_mqtt5){ rc = property__read_all(UNSUBSCRIBE, &context->in_packet, &properties); From 8077376a79f441a17f1c195695e34cd05ea26147 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 25 Oct 2018 12:44:41 +0100 Subject: [PATCH 061/254] Add read support for AUTH packets. --- lib/CMakeLists.txt | 1 + lib/Makefile | 4 +++ lib/handle_auth.c | 49 +++++++++++++++++++++++++++++++++ lib/read_handle.c | 2 ++ lib/read_handle.h | 1 + src/CMakeLists.txt | 1 + src/Makefile | 4 +++ src/handle_auth.c | 48 ++++++++++++++++++++++++++++++++ src/mosquitto_broker_internal.h | 1 + src/read_handle.c | 2 ++ 10 files changed, 113 insertions(+) create mode 100644 lib/handle_auth.c create mode 100644 src/handle_auth.c diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index cae15b03ae..dbbf2ca636 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -35,6 +35,7 @@ set(C_SRC actions.c callbacks.c connect.c + handle_auth.c handle_connack.c handle_ping.c handle_pubackcomp.c diff --git a/lib/Makefile b/lib/Makefile index 52d04714f9..9dc330c4a4 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -6,6 +6,7 @@ MOSQ_OBJS=mosquitto.o \ actions.o \ callbacks.o \ connect.o \ + handle_auth.o \ handle_connack.o \ handle_ping.o \ handle_pubackcomp.o \ @@ -94,6 +95,9 @@ callbacks.o : callbacks.c mosquitto.h mosquitto_internal.h connect.o : connect.c mosquitto.h mosquitto_internal.h ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ +handle_auth.o : handle_auth.c read_handle.h + ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ + handle_connack.o : handle_connack.c read_handle.h ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ diff --git a/lib/handle_auth.c b/lib/handle_auth.c new file mode 100644 index 0000000000..ef2b1f8354 --- /dev/null +++ b/lib/handle_auth.c @@ -0,0 +1,49 @@ +/* +Copyright (c) 2018 Roger Light + +All rights reserved. This program and the accompanying materials +are made available under the terms of the Eclipse Public License v1.0 +and Eclipse Distribution License v1.0 which accompany this distribution. + +The Eclipse Public License is available at + http://www.eclipse.org/legal/epl-v10.html +and the Eclipse Distribution License is available at + http://www.eclipse.org/org/documents/edl-v10.php. + +Contributors: + Roger Light - initial implementation and documentation. +*/ + +#include "config.h" + +#include +#include + +#include "logging_mosq.h" +#include "mosquitto_internal.h" +#include "mqtt_protocol.h" +#include "packet_mosq.h" +#include "property_mosq.h" + + +int handle__auth(struct mosquitto *mosq) +{ + int rc = 0; + uint8_t reason_code; + struct mqtt5__property *properties = NULL; + + if(!mosq) return MOSQ_ERR_INVAL; + log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received AUTH", mosq->id); + + if(mosq->protocol != mosq_p_mqtt5){ + return MOSQ_ERR_PROTOCOL; + } + + if(packet__read_byte(&mosq->in_packet, &reason_code)) return 1; + + rc = property__read_all(AUTH, &mosq->in_packet, &properties); + if(rc) return rc; + property__free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ + + return MOSQ_ERR_SUCCESS; +} diff --git a/lib/read_handle.c b/lib/read_handle.c index fab8b7ddca..011c083c3b 100644 --- a/lib/read_handle.c +++ b/lib/read_handle.c @@ -57,6 +57,8 @@ int handle__packet(struct mosquitto *mosq) return handle__suback(mosq); case UNSUBACK: return handle__unsuback(mosq); + case AUTH: + return handle__auth(mosq); default: /* If we don't recognise the command, return an error straight away. */ log__printf(mosq, MOSQ_LOG_ERR, "Error: Unrecognised command %d\n", (mosq->in_packet.command)&0xF0); diff --git a/lib/read_handle.h b/lib/read_handle.h index 887746de4e..8bf20b5f11 100644 --- a/lib/read_handle.h +++ b/lib/read_handle.h @@ -28,6 +28,7 @@ int handle__packet(struct mosquitto *mosq); int handle__connack(struct mosquitto *mosq); int handle__pubackcomp(struct mosquitto *mosq, const char *type); int handle__publish(struct mosquitto *mosq); +int handle__auth(struct mosquitto *mosq); #endif int handle__pubrec(struct mosquitto *mosq); int handle__pubrel(struct mosquitto_db *db, struct mosquitto *mosq); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ba503f6001..97f1d3b4e6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,6 +7,7 @@ set (MOSQ_SRCS conf_includedir.c context.c database.c + handle_auth.c handle_connack.c handle_connect.c ../lib/handle_ping.c diff --git a/src/Makefile b/src/Makefile index 16191e20f9..93b2ea4a8f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -14,6 +14,7 @@ OBJS= mosquitto.o \ conf_includedir.o \ context.o \ database.o \ + handle_auth.o \ handle_connack.o \ handle_connect.o \ handle_ping.o \ @@ -79,6 +80,9 @@ context.o : context.c mosquitto_broker_internal.h database.o : database.c mosquitto_broker_internal.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ +handle_auth.o : handle_auth.c mosquitto_broker_internal.h + ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ + handle_connack.o : handle_connack.c mosquitto_broker_internal.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ diff --git a/src/handle_auth.c b/src/handle_auth.c new file mode 100644 index 0000000000..1941fb954a --- /dev/null +++ b/src/handle_auth.c @@ -0,0 +1,48 @@ +/* +Copyright (c) 2018 Roger Light + +All rights reserved. This program and the accompanying materials +are made available under the terms of the Eclipse Public License v1.0 +and Eclipse Distribution License v1.0 which accompany this distribution. + +The Eclipse Public License is available at + http://www.eclipse.org/legal/epl-v10.html +and the Eclipse Distribution License is available at + http://www.eclipse.org/org/documents/edl-v10.php. + +Contributors: + Roger Light - initial implementation and documentation. +*/ + +#include "config.h" + +#include +#include + +#include "mosquitto_broker_internal.h" +#include "mqtt_protocol.h" +#include "packet_mosq.h" +#include "property_mosq.h" + + +int handle__auth(struct mosquitto_db *db, struct mosquitto *context) +{ + int rc = 0; + uint8_t reason_code; + struct mqtt5__property *properties = NULL; + + if(!context) return MOSQ_ERR_INVAL; + log__printf(NULL, MOSQ_LOG_DEBUG, "Received AUTH from %s", context->id); + + if(context->protocol != mosq_p_mqtt5){ + return MOSQ_ERR_PROTOCOL; + } + + if(packet__read_byte(&context->in_packet, &reason_code)) return 1; + + rc = property__read_all(AUTH, &context->in_packet, &properties); + if(rc) return rc; + property__free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ + + return MOSQ_ERR_SUCCESS; +} diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index de4cb12108..f9970a78f2 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -532,6 +532,7 @@ int handle__disconnect(struct mosquitto_db *db, struct mosquitto *context); int handle__publish(struct mosquitto_db *db, struct mosquitto *context); int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context); int handle__unsubscribe(struct mosquitto_db *db, struct mosquitto *context); +int handle__auth(struct mosquitto_db *db, struct mosquitto *context); /* ============================================================ * Database handling diff --git a/src/read_handle.c b/src/read_handle.c index 9d032ed2f5..a283ca0e21 100644 --- a/src/read_handle.c +++ b/src/read_handle.c @@ -65,6 +65,8 @@ int handle__packet(struct mosquitto_db *db, struct mosquitto *context) case UNSUBACK: return handle__unsuback(context); #endif + case AUTH: + return handle__auth(db, context); default: /* If we don't recognise the command, return an error straight away. */ return MOSQ_ERR_PROTOCOL; From b6c667689dc3ec63d2625e6217397a2049efade8 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 25 Oct 2018 13:21:42 +0100 Subject: [PATCH 062/254] Write properties for all commands apart from AUTH. --- lib/send_connect.c | 13 ++++++++++--- lib/send_disconnect.c | 8 ++++++-- lib/send_mosq.c | 12 ++++++++++-- lib/send_publish.c | 9 ++++----- lib/send_subscribe.c | 8 ++++++-- lib/send_unsubscribe.c | 9 +++++++-- src/handle_unsubscribe.c | 1 + src/send_connack.c | 12 +++++++----- src/send_suback.c | 9 +++++++-- 9 files changed, 58 insertions(+), 23 deletions(-) diff --git a/lib/send_connect.c b/lib/send_connect.c index 5231de784f..4bc7598944 100644 --- a/lib/send_connect.c +++ b/lib/send_connect.c @@ -41,6 +41,8 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session uint8_t version; char *clientid, *username, *password; int headerlen; + struct mqtt5__property *properties = NULL; + int proplen, varbytes; assert(mosq); assert(mosq->id); @@ -63,7 +65,10 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session if(mosq->protocol == mosq_p_mqtt5){ version = MQTT_PROTOCOL_V5; - headerlen = 11; /* FIXME - this has a fixed property length of 0 */ + headerlen = 10; + proplen = property__get_length_all(properties); + varbytes = packet__varint_bytes(proplen); + headerlen += proplen + varbytes; }else if(mosq->protocol == mosq_p_mqtt311){ version = MQTT_PROTOCOL_V311; headerlen = 10; @@ -84,7 +89,9 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session payloadlen += 2+strlen(mosq->will->msg.topic) + 2+mosq->will->msg.payloadlen; if(mosq->protocol == mosq_p_mqtt5){ - payloadlen += 1; + proplen = property__get_length_all(mosq->will->properties); + varbytes = packet__varint_bytes(proplen); + payloadlen += proplen + varbytes; } } if(username){ @@ -95,7 +102,7 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session } packet->command = CONNECT; - packet->remaining_length = headerlen+payloadlen; + packet->remaining_length = headerlen + payloadlen; rc = packet__alloc(packet); if(rc){ mosquitto__free(packet); diff --git a/lib/send_disconnect.c b/lib/send_disconnect.c index 18c5b92437..61c979a904 100644 --- a/lib/send_disconnect.c +++ b/lib/send_disconnect.c @@ -36,6 +36,8 @@ int send__disconnect(struct mosquitto *mosq) { struct mosquitto__packet *packet = NULL; int rc; + struct mqtt5__property *properties = NULL; + int proplen, varbytes; assert(mosq); #ifdef WITH_BROKER @@ -51,7 +53,9 @@ int send__disconnect(struct mosquitto *mosq) packet->command = DISCONNECT; if(mosq->protocol == mosq_p_mqtt5){ - packet->remaining_length = 1; + proplen = property__get_length_all(properties); + varbytes = packet__varint_bytes(proplen); + packet->remaining_length = proplen+varbytes; }else{ packet->remaining_length = 0; } @@ -62,7 +66,7 @@ int send__disconnect(struct mosquitto *mosq) return rc; } if(mosq->protocol == mosq_p_mqtt5){ - property__write_all(packet, NULL); + property__write_all(packet, properties); } return packet__queue(mosq, packet); diff --git a/lib/send_mosq.c b/lib/send_mosq.c index ca01c0108e..f944c6a929 100644 --- a/lib/send_mosq.c +++ b/lib/send_mosq.c @@ -72,6 +72,7 @@ int send__puback(struct mosquitto *mosq, uint16_t mid) #else if(mosq) log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBACK (Mid: %d)", mosq->id, mid); #endif + /* We don't use Reason String or User Property yet. */ return send__command_with_mid(mosq, PUBACK, mid, false, NULL); } @@ -82,6 +83,7 @@ int send__pubcomp(struct mosquitto *mosq, uint16_t mid) #else if(mosq) log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBCOMP (Mid: %d)", mosq->id, mid); #endif + /* We don't use Reason String or User Property yet. */ return send__command_with_mid(mosq, PUBCOMP, mid, false, NULL); } @@ -93,6 +95,7 @@ int send__pubrec(struct mosquitto *mosq, uint16_t mid) #else if(mosq) log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBREC (Mid: %d)", mosq->id, mid); #endif + /* We don't use Reason String or User Property yet. */ return send__command_with_mid(mosq, PUBREC, mid, false, NULL); } @@ -103,6 +106,7 @@ int send__pubrel(struct mosquitto *mosq, uint16_t mid) #else if(mosq) log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBREL (Mid: %d)", mosq->id, mid); #endif + /* We don't use Reason String or User Property yet. */ return send__command_with_mid(mosq, PUBREL|2, mid, false, NULL); } @@ -111,6 +115,7 @@ int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid { struct mosquitto__packet *packet = NULL; int rc; + int proplen, varbytes; assert(mosq); packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet)); @@ -121,8 +126,11 @@ int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid packet->command |= 8; } packet->remaining_length = 2; + if(mosq->protocol == mosq_p_mqtt5){ - packet->remaining_length += 1; + proplen = property__get_length_all(properties); + varbytes = packet__varint_bytes(proplen); + packet->remaining_length += varbytes + proplen; } rc = packet__alloc(packet); @@ -134,7 +142,7 @@ int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid packet__write_uint16(packet, mid); if(mosq->protocol == mosq_p_mqtt5){ - property__write_all(packet, NULL); + property__write_all(packet, properties); } return packet__queue(mosq, packet); diff --git a/lib/send_publish.c b/lib/send_publish.c index 2cd703c756..4f54acbac6 100644 --- a/lib/send_publish.c +++ b/lib/send_publish.c @@ -133,8 +133,7 @@ int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, { struct mosquitto__packet *packet = NULL; int packetlen; - int proplen; - int varlen; + int proplen, varbytes; int rc; assert(mosq); @@ -144,12 +143,12 @@ int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, if(qos > 0) packetlen += 2; /* For message id */ if(mosq->protocol == mosq_p_mqtt5){ proplen = property__get_length_all(properties); - varlen = packet__varint_bytes(proplen); - if(varlen > 4){ + varbytes = packet__varint_bytes(proplen); + if(varbytes > 4){ /* FIXME - Properties too big, don't publish any - should remove some first really */ properties = NULL; }else{ - packetlen += proplen + varlen; + packetlen += proplen + varbytes; } } packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet)); diff --git a/lib/send_subscribe.c b/lib/send_subscribe.c index 8e6e5eb613..c950b12a1c 100644 --- a/lib/send_subscribe.c +++ b/lib/send_subscribe.c @@ -40,6 +40,8 @@ int send__subscribe(struct mosquitto *mosq, int *mid, int topic_count, const cha uint16_t local_mid; int rc; int i; + struct mqtt5__property *properties = NULL; + int proplen, varbytes; assert(mosq); assert(topic); @@ -49,7 +51,9 @@ int send__subscribe(struct mosquitto *mosq, int *mid, int topic_count, const cha packetlen = 2; if(mosq->protocol == mosq_p_mqtt5){ - packetlen += 1; + proplen = property__get_length_all(properties); + varbytes = packet__varint_bytes(proplen); + packetlen += proplen + varbytes; } for(i=0; iprotocol == mosq_p_mqtt5){ - property__write_all(packet, NULL); + property__write_all(packet, properties); } /* Payload */ diff --git a/lib/send_unsubscribe.c b/lib/send_unsubscribe.c index e1dcbfe20a..db59fc9874 100644 --- a/lib/send_unsubscribe.c +++ b/lib/send_unsubscribe.c @@ -39,6 +39,8 @@ int send__unsubscribe(struct mosquitto *mosq, int *mid, const char *topic) uint32_t packetlen; uint16_t local_mid; int rc; + struct mqtt5__property *properties = NULL; + int proplen, varbytes; assert(mosq); assert(topic); @@ -48,7 +50,9 @@ int send__unsubscribe(struct mosquitto *mosq, int *mid, const char *topic) packetlen = 2 + 2+strlen(topic); if(mosq->protocol == mosq_p_mqtt5){ - packetlen += 1; + proplen = property__get_length_all(properties); + varbytes = packet__varint_bytes(proplen); + packetlen += proplen + varbytes; } packet->command = UNSUBSCRIBE | (1<<1); @@ -65,7 +69,8 @@ int send__unsubscribe(struct mosquitto *mosq, int *mid, const char *topic) packet__write_uint16(packet, local_mid); if(mosq->protocol == mosq_p_mqtt5){ - property__write_all(packet, NULL); + /* We don't use User Property yet. */ + property__write_all(packet, properties); } /* Payload */ diff --git a/src/handle_unsubscribe.c b/src/handle_unsubscribe.c index 1838427d3c..56da9957c0 100644 --- a/src/handle_unsubscribe.c +++ b/src/handle_unsubscribe.c @@ -91,6 +91,7 @@ int handle__unsubscribe(struct mosquitto_db *db, struct mosquitto *context) log__printf(NULL, MOSQ_LOG_DEBUG, "Sending UNSUBACK to %s", context->id); + /* We don't use Reason String or User Property yet. */ return send__command_with_mid(context, UNSUBACK, mid, false, NULL); } diff --git a/src/send_connack.c b/src/send_connack.c index 00a394719e..ba19b30511 100644 --- a/src/send_connack.c +++ b/src/send_connack.c @@ -27,6 +27,8 @@ int send__connack(struct mosquitto *context, int ack, int result) { struct mosquitto__packet *packet = NULL; int rc; + struct mqtt5__property *properties = NULL; + int proplen, varbytes; if(context){ if(context->id){ @@ -40,11 +42,11 @@ int send__connack(struct mosquitto *context, int ack, int result) if(!packet) return MOSQ_ERR_NOMEM; packet->command = CONNACK; + packet->remaining_length = 2; if(context->protocol == mosq_p_mqtt5){ - /* FIXME - proper property support */ - packet->remaining_length = 3; - }else{ - packet->remaining_length = 2; + proplen = property__get_length_all(properties); + varbytes = packet__varint_bytes(proplen); + packet->remaining_length += proplen + varbytes; } rc = packet__alloc(packet); if(rc){ @@ -54,7 +56,7 @@ int send__connack(struct mosquitto *context, int ack, int result) packet__write_byte(packet, ack); packet__write_byte(packet, result); if(context->protocol == mosq_p_mqtt5){ - property__write_all(packet, NULL); + property__write_all(packet, properties); } return packet__queue(context, packet); diff --git a/src/send_suback.c b/src/send_suback.c index b1718872b8..a276f81ccf 100644 --- a/src/send_suback.c +++ b/src/send_suback.c @@ -28,6 +28,8 @@ int send__suback(struct mosquitto *context, uint16_t mid, uint32_t payloadlen, c { struct mosquitto__packet *packet = NULL; int rc; + struct mqtt5__property *properties = NULL; + int proplen, varbytes; log__printf(NULL, MOSQ_LOG_DEBUG, "Sending SUBACK to %s", context->id); @@ -37,7 +39,9 @@ int send__suback(struct mosquitto *context, uint16_t mid, uint32_t payloadlen, c packet->command = SUBACK; packet->remaining_length = 2+payloadlen; if(context->protocol == mosq_p_mqtt5){ - packet->remaining_length += 1; + proplen = property__get_length_all(properties); + varbytes = packet__varint_bytes(proplen); + packet->remaining_length += proplen + varbytes; } rc = packet__alloc(packet); if(rc){ @@ -47,7 +51,8 @@ int send__suback(struct mosquitto *context, uint16_t mid, uint32_t payloadlen, c packet__write_uint16(packet, mid); if(context->protocol == mosq_p_mqtt5){ - property__write_all(packet, NULL); + /* We don't use Reason String or User Property yet. */ + property__write_all(packet, properties); } if(payloadlen){ From 52c25fa8996d30d0ed83432a24962acfa2cfa29d Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 25 Oct 2018 14:43:43 +0100 Subject: [PATCH 063/254] Simple connect test for v5. --- test/broker/01-connect-success-v5.py | 34 ++++++++++++++++++++++++++++ test/broker/Makefile | 1 + test/broker/ptest.py | 1 + test/mosq_test.py | 23 +++++++++++++++---- 4 files changed, 54 insertions(+), 5 deletions(-) create mode 100755 test/broker/01-connect-success-v5.py diff --git a/test/broker/01-connect-success-v5.py b/test/broker/01-connect-success-v5.py new file mode 100755 index 0000000000..4d5201a18c --- /dev/null +++ b/test/broker/01-connect-success-v5.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python + +# Test whether a valid CONNECT results in the correct CONNACK packet for MQTT v5. + +import inspect, os, sys + +# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder +cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) +if cmd_subfolder not in sys.path: + sys.path.insert(0, cmd_subfolder) + +import mosq_test + +rc = 1 +keepalive = 10 +connect_packet = mosq_test.gen_connect("connect-success-test", proto_ver=5, keepalive=keepalive) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +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, port=port) + sock.close() + rc = 0 +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index 0b4fee0848..0bed129085 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -19,6 +19,7 @@ test : test-compile 01 02 03 04 05 06 07 08 09 10 11 01 : ./01-connect-success.py + ./01-connect-success-v5.py ./01-connect-invalid-protonum.py ./01-connect-invalid-id-0.py ./01-connect-invalid-id-0-311.py diff --git a/test/broker/ptest.py b/test/broker/ptest.py index 27b0df6d77..dad3b42d18 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -8,6 +8,7 @@ tests = [ #(ports required, 'path'), (1, './01-connect-success.py'), + (1, './01-connect-success-v5.py'), (1, './01-connect-invalid-protonum.py'), (1, './01-connect-invalid-id-0.py'), (1, './01-connect-invalid-id-0-311.py'), diff --git a/test/mosq_test.py b/test/mosq_test.py index a28f2eb1ce..43d26369e9 100644 --- a/test/mosq_test.py +++ b/test/mosq_test.py @@ -72,6 +72,8 @@ def packet_matches(name, recvd, expected): print("Received: "+to_string(recvd)) except struct.error: print("Received (not decoded, len=%d): %s" % (len(recvd), recvd)) + for i in range(0, len(recvd)): + print('%c'%(recvd[i]),) try: print("Expected: "+to_string(expected)) except struct.error: @@ -292,10 +294,10 @@ def to_string(packet): # Reserved return "0xF0" -def gen_connect(client_id, clean_session=True, keepalive=60, username=None, password=None, will_topic=None, will_qos=0, will_retain=False, will_payload="", proto_ver=4, connect_reserved=False): +def gen_connect(client_id, clean_session=True, keepalive=60, username=None, password=None, will_topic=None, will_qos=0, will_retain=False, will_payload="", proto_ver=4, connect_reserved=False, properties=None): if (proto_ver&0x7F) == 3 or proto_ver == 0: remaining_length = 12 - elif (proto_ver&0x7F) == 4: + elif (proto_ver&0x7F) == 4 or proto_ver == 5: remaining_length = 10 else: raise ValueError @@ -311,6 +313,9 @@ def gen_connect(client_id, clean_session=True, keepalive=60, username=None, pass if clean_session: connect_flags = connect_flags | 0x02 + if proto_ver == 5: + remaining_length += 1 + if will_topic != None: remaining_length = remaining_length + 2+len(will_topic) + 2+len(will_payload) connect_flags = connect_flags | 0x04 | ((will_qos&0x03) << 3) @@ -328,9 +333,12 @@ def gen_connect(client_id, clean_session=True, keepalive=60, username=None, pass packet = struct.pack("!B"+str(len(rl))+"s", 0x10, rl) if (proto_ver&0x7F) == 3 or proto_ver == 0: packet = packet + struct.pack("!H6sBBH", len("MQIsdp"), "MQIsdp", proto_ver, connect_flags, keepalive) - elif (proto_ver&0x7F) == 4: + elif (proto_ver&0x7F) == 4 or proto_ver == 5: packet = packet + struct.pack("!H4sBBH", len("MQTT"), "MQTT", proto_ver, connect_flags, keepalive) + if proto_ver == 5: + packet += struct.pack("B", 0) + if client_id != None: packet = packet + struct.pack("!H"+str(len(client_id))+"s", len(client_id), client_id) @@ -347,8 +355,13 @@ def gen_connect(client_id, clean_session=True, keepalive=60, username=None, pass packet = packet + struct.pack("!H"+str(len(password))+"s", len(password), password) return packet -def gen_connack(resv=0, rc=0): - return struct.pack('!BBBB', 32, 2, resv, rc); +def gen_connack(resv=0, rc=0, proto_ver=4): + if proto_ver == 5: + packet = struct.pack('!BBBBB', 32, 3, resv, rc, 0); + else: + packet = struct.pack('!BBBB', 32, 2, resv, rc); + + return packet def gen_publish(topic, qos, payload=None, retain=False, dup=False, mid=0): rl = 2+len(topic) From 6996fd450a9c9e96efe4b9ffa447ef8937b33014 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 25 Oct 2018 14:57:41 +0100 Subject: [PATCH 064/254] Simple pub/sub/unsub tests for v5. --- test/broker/02-subpub-qos0-v5.py | 45 +++++++++++++++ test/broker/02-subpub-qos1-v5.py | 53 ++++++++++++++++++ test/broker/02-subpub-qos2-v5.py | 60 ++++++++++++++++++++ test/broker/02-unsubscribe-qos2-v5.py | 41 ++++++++++++++ test/broker/Makefile | 4 ++ test/broker/ptest.py | 4 ++ test/mosq_test.py | 80 +++++++++++++++++++-------- 7 files changed, 265 insertions(+), 22 deletions(-) create mode 100755 test/broker/02-subpub-qos0-v5.py create mode 100755 test/broker/02-subpub-qos1-v5.py create mode 100755 test/broker/02-subpub-qos2-v5.py create mode 100755 test/broker/02-unsubscribe-qos2-v5.py diff --git a/test/broker/02-subpub-qos0-v5.py b/test/broker/02-subpub-qos0-v5.py new file mode 100755 index 0000000000..ef3c900943 --- /dev/null +++ b/test/broker/02-subpub-qos0-v5.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +# Test whether a client subscribed to a topic receives its own message sent to that topic. +# MQTT v5 + +import inspect, os, sys +# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder +cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) +if cmd_subfolder not in sys.path: + sys.path.insert(0, cmd_subfolder) + +import mosq_test + +rc = 1 +mid = 53 +keepalive = 60 +connect_packet = mosq_test.gen_connect("subpub-qos0-test", keepalive=keepalive, proto_ver=5) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +subscribe_packet = mosq_test.gen_subscribe(mid, "subpub/qos0", 0, proto_ver=5) +suback_packet = mosq_test.gen_suback(mid, 0, proto_ver=5) + +publish_packet = mosq_test.gen_publish("subpub/qos0", qos=0, payload="message", proto_ver=5) + +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) + + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback") + mosq_test.do_send_receive(sock, publish_packet, publish_packet, "publish") + + rc = 0 + + sock.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/02-subpub-qos1-v5.py b/test/broker/02-subpub-qos1-v5.py new file mode 100755 index 0000000000..2d08f43d0d --- /dev/null +++ b/test/broker/02-subpub-qos1-v5.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +# Test whether a client subscribed to a topic receives its own message sent to that topic. +# MQTT v5 + +import inspect, os, sys +# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder +cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) +if cmd_subfolder not in sys.path: + sys.path.insert(0, cmd_subfolder) + +import mosq_test + +rc = 1 +mid = 530 +keepalive = 60 +connect_packet = mosq_test.gen_connect("subpub-qos1-test", keepalive=keepalive, proto_ver=5) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +subscribe_packet = mosq_test.gen_subscribe(mid, "subpub/qos1", 1, proto_ver=5) +suback_packet = mosq_test.gen_suback(mid, 1, proto_ver=5) + +mid = 300 +publish_packet = mosq_test.gen_publish("subpub/qos1", qos=1, mid=mid, payload="message", proto_ver=5) +puback_packet = mosq_test.gen_puback(mid, proto_ver=5) + +mid = 1 +publish_packet2 = mosq_test.gen_publish("subpub/qos1", qos=1, mid=mid, payload="message", proto_ver=5) + + +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) + + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback") + + mosq_test.do_send_receive(sock, publish_packet, puback_packet, "puback") + + if mosq_test.expect_packet(sock, "publish2", publish_packet2): + rc = 0 + + sock.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/02-subpub-qos2-v5.py b/test/broker/02-subpub-qos2-v5.py new file mode 100755 index 0000000000..796ed82127 --- /dev/null +++ b/test/broker/02-subpub-qos2-v5.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python + +# Test whether a client subscribed to a topic receives its own message sent to that topic. +# MQTT v5 + +import inspect, os, sys +# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder +cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) +if cmd_subfolder not in sys.path: + sys.path.insert(0, cmd_subfolder) + +import mosq_test + +rc = 1 +mid = 530 +keepalive = 60 +connect_packet = mosq_test.gen_connect("subpub-qos2-test", keepalive=keepalive, proto_ver=5) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +subscribe_packet = mosq_test.gen_subscribe(mid, "subpub/qos2", 2, proto_ver=5) +suback_packet = mosq_test.gen_suback(mid, 2, proto_ver=5) + +mid = 301 +publish_packet = mosq_test.gen_publish("subpub/qos2", qos=2, mid=mid, payload="message", proto_ver=5) +pubrec_packet = mosq_test.gen_pubrec(mid, proto_ver=5) +pubrel_packet = mosq_test.gen_pubrel(mid, proto_ver=5) +pubcomp_packet = mosq_test.gen_pubcomp(mid, proto_ver=5) + +mid = 1 +publish_packet2 = mosq_test.gen_publish("subpub/qos2", qos=2, mid=mid, payload="message", proto_ver=5) +pubrec_packet2 = mosq_test.gen_pubrec(mid, proto_ver=5) +pubrel_packet2 = mosq_test.gen_pubrel(mid, proto_ver=5) +pubcomp_packet2 = mosq_test.gen_pubcomp(mid, proto_ver=5) + + +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) + + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback") + mosq_test.do_send_receive(sock, publish_packet, pubrec_packet, "pubrec") + mosq_test.do_send_receive(sock, pubrel_packet, pubcomp_packet, "pubcomp") + + if mosq_test.expect_packet(sock, "publish2", publish_packet2): + mosq_test.do_send_receive(sock, pubrec_packet2, pubrel_packet2, "pubrel2") + # Broker side of flow complete so can quit here. + rc = 0 + + sock.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/02-unsubscribe-qos2-v5.py b/test/broker/02-unsubscribe-qos2-v5.py new file mode 100755 index 0000000000..64d71963ba --- /dev/null +++ b/test/broker/02-unsubscribe-qos2-v5.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +# Test whether a SUBSCRIBE to a topic with QoS 2 results in the correct SUBACK packet. +# MQTT 5 + +import inspect, os, sys +# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder +cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) +if cmd_subfolder not in sys.path: + sys.path.insert(0, cmd_subfolder) + +import mosq_test + +rc = 1 +mid = 3 +keepalive = 60 +connect_packet = mosq_test.gen_connect("unsubscribe-qos2-test", keepalive=keepalive, proto_ver=5) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +unsubscribe_packet = mosq_test.gen_unsubscribe(mid, "qos2/test", proto_ver=5) +unsuback_packet = mosq_test.gen_unsuback(mid, proto_ver=5) + +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, port=port) + mosq_test.do_send_receive(sock, unsubscribe_packet, unsuback_packet, "unsuback") + + rc = 0 + + sock.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index 0bed129085..7466f05221 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -46,9 +46,13 @@ endif ./02-subpub-qos0.py ./02-subpub-qos1.py ./02-subpub-qos2.py + ./02-subpub-qos0-v5.py + ./02-subpub-qos1-v5.py + ./02-subpub-qos2-v5.py ./02-unsubscribe-qos0.py ./02-unsubscribe-qos1.py ./02-unsubscribe-qos2.py + ./02-unsubscribe-qos2-v5.py ./02-unsubscribe-invalid-no-topic.py ./02-subscribe-invalid-utf8.py ./02-subscribe-persistence-flipflop.py diff --git a/test/broker/ptest.py b/test/broker/ptest.py index dad3b42d18..71ffdf7556 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -29,9 +29,13 @@ (1, './02-subpub-qos0.py'), (1, './02-subpub-qos1.py'), (1, './02-subpub-qos2.py'), + (1, './02-subpub-qos0-v5.py'), + (1, './02-subpub-qos1-v5.py'), + (1, './02-subpub-qos2-v5.py'), (1, './02-unsubscribe-qos0.py'), (1, './02-unsubscribe-qos1.py'), (1, './02-unsubscribe-qos2.py'), + (1, './02-unsubscribe-qos2-v5.py'), (1, './02-unsubscribe-invalid-no-topic.py'), (1, './02-subscribe-invalid-utf8.py'), (1, './02-subscribe-persistence-flipflop.py'), diff --git a/test/mosq_test.py b/test/mosq_test.py index 43d26369e9..972a81c8a8 100644 --- a/test/mosq_test.py +++ b/test/mosq_test.py @@ -363,12 +363,16 @@ def gen_connack(resv=0, rc=0, proto_ver=4): return packet -def gen_publish(topic, qos, payload=None, retain=False, dup=False, mid=0): +def gen_publish(topic, qos, payload=None, retain=False, dup=False, mid=0, proto_ver=4): rl = 2+len(topic) pack_format = "H"+str(len(topic))+"s" if qos > 0: rl = rl + 2 pack_format = pack_format + "H" + if proto_ver == 5: + rl += 1 + pack_format = pack_format + "B" + if payload != None: rl = rl + len(payload) pack_format = pack_format + str(len(payload))+"s" @@ -383,40 +387,72 @@ def gen_publish(topic, qos, payload=None, retain=False, dup=False, mid=0): if dup: cmd = cmd + 8 - if qos > 0: - return struct.pack("!B" + str(len(rlpacked))+"s" + pack_format, cmd, rlpacked, len(topic), topic, mid, payload) + if proto_ver == 5: + if qos > 0: + return struct.pack("!B" + str(len(rlpacked))+"s" + pack_format, cmd, rlpacked, len(topic), topic, mid, 0, payload) + else: + return struct.pack("!B" + str(len(rlpacked))+"s" + pack_format, cmd, rlpacked, len(topic), topic, 0, payload) else: - return struct.pack("!B" + str(len(rlpacked))+"s" + pack_format, cmd, rlpacked, len(topic), topic, payload) + if qos > 0: + return struct.pack("!B" + str(len(rlpacked))+"s" + pack_format, cmd, rlpacked, len(topic), topic, mid, payload) + else: + return struct.pack("!B" + str(len(rlpacked))+"s" + pack_format, cmd, rlpacked, len(topic), topic, payload) -def gen_puback(mid): - return struct.pack('!BBH', 64, 2, mid) +def gen_puback(mid, proto_ver=4): + if proto_ver == 5: + return struct.pack('!BBHB', 64, 3, mid, 0) + else: + return struct.pack('!BBH', 64, 2, mid) -def gen_pubrec(mid): - return struct.pack('!BBH', 80, 2, mid) +def gen_pubrec(mid, proto_ver=4): + if proto_ver == 5: + return struct.pack('!BBHB', 80, 3, mid, 0) + else: + return struct.pack('!BBH', 80, 2, mid) -def gen_pubrel(mid, dup=False): +def gen_pubrel(mid, dup=False, proto_ver=4): if dup: cmd = 96+8+2 else: cmd = 96+2 - return struct.pack('!BBH', cmd, 2, mid) + if proto_ver == 5: + return struct.pack('!BBHB', cmd, 3, mid, 0) + else: + return struct.pack('!BBH', cmd, 2, mid) -def gen_pubcomp(mid): - return struct.pack('!BBH', 112, 2, mid) +def gen_pubcomp(mid, proto_ver=4): + if proto_ver == 5: + return struct.pack('!BBHB', 112, 3, mid, 0) + else: + return struct.pack('!BBH', 112, 2, mid) -def gen_subscribe(mid, topic, qos): - pack_format = "!BBHH"+str(len(topic))+"sB" - return struct.pack(pack_format, 130, 2+2+len(topic)+1, mid, len(topic), topic, qos) +def gen_subscribe(mid, topic, qos, proto_ver=4): + if proto_ver == 5: + pack_format = "!BBHBH"+str(len(topic))+"sB" + return struct.pack(pack_format, 130, 2+1+2+len(topic)+1, mid, 0, len(topic), topic, qos) + else: + pack_format = "!BBHH"+str(len(topic))+"sB" + return struct.pack(pack_format, 130, 2+2+len(topic)+1, mid, len(topic), topic, qos) -def gen_suback(mid, qos): - return struct.pack('!BBHB', 144, 2+1, mid, qos) +def gen_suback(mid, qos, proto_ver=4): + if proto_ver == 5: + return struct.pack('!BBHBB', 144, 2+1+1, mid, 0, qos) + else: + return struct.pack('!BBHB', 144, 2+1, mid, qos) -def gen_unsubscribe(mid, topic): - pack_format = "!BBHH"+str(len(topic))+"s" - return struct.pack(pack_format, 162, 2+2+len(topic), mid, len(topic), topic) +def gen_unsubscribe(mid, topic, proto_ver=4): + if proto_ver == 5: + pack_format = "!BBHBH"+str(len(topic))+"s" + return struct.pack(pack_format, 162, 2+2+len(topic)+1, mid, 0, len(topic), topic) + else: + pack_format = "!BBHH"+str(len(topic))+"s" + return struct.pack(pack_format, 162, 2+2+len(topic), mid, len(topic), topic) -def gen_unsuback(mid): - return struct.pack('!BBH', 176, 2, mid) +def gen_unsuback(mid, proto_ver=4): + if proto_ver == 5: + return struct.pack('!BBHB', 176, 3, mid, 0) + else: + return struct.pack('!BBH', 176, 2, mid) def gen_pingreq(): return struct.pack('!BB', 192, 0) From 12fa336140593cce5d79d94337679b9433f50df4 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 25 Oct 2018 16:35:24 +0100 Subject: [PATCH 065/254] Handle some incoming PUBLISH properties. PAYLOAD_FORMAT_INDICATOR, CORRELATION_DATA, USER_PROPERTY, CONTENT_TYPE are now all passed on to subscribing clients from an incoming PUBLISH only (not from Wills). The other PUBLISH properties are silently dropped. --- src/handle_publish.c | 63 ++++++++++++++++-- .../02-subpub-qos0-payload-format-v5.py | 54 +++++++++++++++ test/broker/Makefile | 1 + test/broker/ptest.py | 1 + test/mosq_test.py | 12 ++-- test/mqtt5_props.py | 66 +++++++++++++++++++ 6 files changed, 185 insertions(+), 12 deletions(-) create mode 100755 test/broker/02-subpub-qos0-payload-format-v5.py create mode 100644 test/mqtt5_props.py diff --git a/src/handle_publish.c b/src/handle_publish.c index b51949f56a..20c5165949 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -46,6 +46,8 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) int slen; char *topic_mount; struct mqtt5__property *properties = NULL; + struct mqtt5__property *p, *p_prev; + struct mqtt5__property *msg_properties = NULL, *msg_properties_last; #ifdef WITH_BRIDGE char *topic_temp; @@ -137,10 +139,62 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) } } + /* Handle properties */ if(context->protocol == mosq_p_mqtt5){ rc = property__read_all(PUBLISH, &context->in_packet, &properties); if(rc) return rc; + + p = properties; + p_prev = NULL; + msg_properties = NULL; + msg_properties_last = NULL; + while(p){ + switch(p->identifier){ + case PROP_PAYLOAD_FORMAT_INDICATOR: + case PROP_CORRELATION_DATA: + case PROP_USER_PROPERTY: + case PROP_CONTENT_TYPE: + if(msg_properties){ + msg_properties_last->next = p; + msg_properties_last = p; + }else{ + msg_properties = p; + msg_properties_last = p; + } + if(p_prev){ + p_prev->next = p->next; + msg_properties_last->next = NULL; + p = p_prev->next; + }else{ + properties = p->next; + msg_properties_last->next = NULL; + p = properties; + } + break; + + case PROP_TOPIC_ALIAS: + p = p->next; + break; + + case PROP_RESPONSE_TOPIC: + p = p->next; + break; + + case PROP_MESSAGE_EXPIRY_INTERVAL: + p = p->next; + break; + + case PROP_SUBSCRIPTION_IDENTIFIER: + p = p->next; + break; + + default: + p = p->next; + break; + } + } } + property__free_all(&properties); payloadlen = context->in_packet.remaining_length - context->in_packet.pos; G_PUB_BYTES_RECEIVED_INC(payloadlen); @@ -149,7 +203,6 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) topic_mount = mosquitto__malloc(len+1); if(!topic_mount){ mosquitto__free(topic); - property__free_all(&properties); return MOSQ_ERR_NOMEM; } snprintf(topic_mount, len, "%s%s", context->listener->mount_point, topic); @@ -166,13 +219,11 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) } if(UHPA_ALLOC(payload, payloadlen+1) == 0){ mosquitto__free(topic); - property__free_all(&properties); return MOSQ_ERR_NOMEM; } if(packet__read_bytes(&context->in_packet, UHPA_ACCESS(payload, payloadlen), payloadlen)){ mosquitto__free(topic); UHPA_FREE(payload, payloadlen); - property__free_all(&properties); return 1; } } @@ -185,7 +236,6 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) }else if(rc != MOSQ_ERR_SUCCESS){ mosquitto__free(topic); UHPA_FREE(payload, payloadlen); - property__free_all(&properties); return rc; } @@ -195,10 +245,10 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) } if(!stored){ dup = 0; - if(db__message_store(db, context->id, mid, topic, qos, payloadlen, &payload, retain, &stored, properties, 0)){ + if(db__message_store(db, context->id, mid, topic, qos, payloadlen, &payload, retain, &stored, msg_properties, 0)){ return 1; } - properties = NULL; /* Now belongs to db__message_store() */ + msg_properties = NULL; /* Now belongs to db__message_store() */ }else{ mosquitto__free(topic); topic = stored->topic; @@ -232,7 +282,6 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) return rc; process_bad_message: mosquitto__free(topic); - property__free_all(&properties); UHPA_FREE(payload, payloadlen); switch(qos){ case 0: diff --git a/test/broker/02-subpub-qos0-payload-format-v5.py b/test/broker/02-subpub-qos0-payload-format-v5.py new file mode 100755 index 0000000000..5c9670a704 --- /dev/null +++ b/test/broker/02-subpub-qos0-payload-format-v5.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python + +# Test whether a client subscribed to a topic receives its own message sent to that topic. +# Does the Payload Format Indicator property get sent through? +# MQTT v5 + +import inspect, os, sys +# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder +cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) +if cmd_subfolder not in sys.path: + sys.path.insert(0, cmd_subfolder) + +import mosq_test +import mqtt5_props + +rc = 1 +mid = 53 +keepalive = 60 +connect_packet = mosq_test.gen_connect("subpub-qos0-test", keepalive=keepalive, proto_ver=5) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +subscribe_packet = mosq_test.gen_subscribe(mid, "subpub/qos0", 0, proto_ver=5) +suback_packet = mosq_test.gen_suback(mid, 0, proto_ver=5) + +props = mqtt5_props.gen_byte_prop(mqtt5_props.PROP_PAYLOAD_FORMAT_INDICATOR, 0xed) +props = props+mqtt5_props.gen_uint16_prop(mqtt5_props.PROP_TOPIC_ALIAS, 1) +props = mqtt5_props.prop_finalise(props) +publish_packet_out = mosq_test.gen_publish("subpub/qos0", qos=0, payload="message", proto_ver=5, properties=props) + +props = mqtt5_props.gen_byte_prop(mqtt5_props.PROP_PAYLOAD_FORMAT_INDICATOR, 0xed) +props = mqtt5_props.prop_finalise(props) +publish_packet_expected = mosq_test.gen_publish("subpub/qos0", qos=0, payload="message", proto_ver=5, properties=props) + +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) + + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback") + mosq_test.do_send_receive(sock, publish_packet_out, publish_packet_expected, "publish") + + rc = 0 + + sock.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index 7466f05221..be9cb84b86 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -53,6 +53,7 @@ endif ./02-unsubscribe-qos1.py ./02-unsubscribe-qos2.py ./02-unsubscribe-qos2-v5.py + ./02-subpub-qos0-payload-format-v5.py ./02-unsubscribe-invalid-no-topic.py ./02-subscribe-invalid-utf8.py ./02-subscribe-persistence-flipflop.py diff --git a/test/broker/ptest.py b/test/broker/ptest.py index 71ffdf7556..920dee7b13 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -32,6 +32,7 @@ (1, './02-subpub-qos0-v5.py'), (1, './02-subpub-qos1-v5.py'), (1, './02-subpub-qos2-v5.py'), + (1, './02-subpub-qos0-payload-format-v5.py'), (1, './02-unsubscribe-qos0.py'), (1, './02-unsubscribe-qos1.py'), (1, './02-unsubscribe-qos2.py'), diff --git a/test/mosq_test.py b/test/mosq_test.py index 972a81c8a8..18cdec8743 100644 --- a/test/mosq_test.py +++ b/test/mosq_test.py @@ -363,15 +363,17 @@ def gen_connack(resv=0, rc=0, proto_ver=4): return packet -def gen_publish(topic, qos, payload=None, retain=False, dup=False, mid=0, proto_ver=4): +def gen_publish(topic, qos, payload=None, retain=False, dup=False, mid=0, proto_ver=4, properties=None): rl = 2+len(topic) pack_format = "H"+str(len(topic))+"s" if qos > 0: rl = rl + 2 pack_format = pack_format + "H" + if proto_ver == 5: - rl += 1 - pack_format = pack_format + "B" + rl += len(properties) + # This will break if len(properties) > 127 + pack_format = pack_format + "%ds"%(len(properties)) if payload != None: rl = rl + len(payload) @@ -389,9 +391,9 @@ def gen_publish(topic, qos, payload=None, retain=False, dup=False, mid=0, proto_ if proto_ver == 5: if qos > 0: - return struct.pack("!B" + str(len(rlpacked))+"s" + pack_format, cmd, rlpacked, len(topic), topic, mid, 0, payload) + return struct.pack("!B" + str(len(rlpacked))+"s" + pack_format, cmd, rlpacked, len(topic), topic, mid, properties, payload) else: - return struct.pack("!B" + str(len(rlpacked))+"s" + pack_format, cmd, rlpacked, len(topic), topic, 0, payload) + return struct.pack("!B" + str(len(rlpacked))+"s" + pack_format, cmd, rlpacked, len(topic), topic, properties, payload) else: if qos > 0: return struct.pack("!B" + str(len(rlpacked))+"s" + pack_format, cmd, rlpacked, len(topic), topic, mid, payload) diff --git a/test/mqtt5_props.py b/test/mqtt5_props.py new file mode 100644 index 0000000000..bdd5b1b31e --- /dev/null +++ b/test/mqtt5_props.py @@ -0,0 +1,66 @@ +import struct + +PROP_PAYLOAD_FORMAT_INDICATOR = 1 +PROP_MESSAGE_EXPIRY_INTERVAL = 2 +PROP_CONTENT_TYPE = 3 +PROP_RESPONSE_TOPIC = 8 +PROP_CORRELATION_DATA = 9 +PROP_SUBSCRIPTION_IDENTIFIER = 11 +PROP_SESSION_EXPIRY_INTERVAL = 17 +PROP_ASSIGNED_CLIENT_IDENTIFIER = 18 +PROP_SERVER_KEEP_ALIVE = 19 +PROP_AUTHENTICATION_METHOD = 21 +PROP_AUTHENTICATION_DATA = 22 +PROP_REQUEST_PROBLEM_INFO = 23 +PROP_WILL_DELAY_INTERVAL = 24 +PROP_REQUEST_RESPONSE_INFO = 25 +PROP_RESPONSE_INFO = 26 +PROP_SERVER_REFERENCE = 28 +PROP_REASON_STRING = 31 +PROP_RECEIVE_MAXIMUM = 33 +PROP_TOPIC_ALIAS_MAXIMUM = 34 +PROP_TOPIC_ALIAS = 35 +PROP_MAXIMUM_QOS = 36 +PROP_RETAIN_AVAILABLE = 37 +PROP_USER_PROPERTY = 38 +PROP_MAXIMUM_PACKET_SIZE = 39 +PROP_WILDCARD_SUB_AVAILABLE = 40 +PROP_SUBSCRIPTION_ID_AVAILABLE = 41 +PROP_SHARED_SUB_AVAILABLE = 42 + +def gen_byte_prop(identifier, byte): + prop = struct.pack('BB', identifier, byte) + return prop + +def gen_uint16_prop(identifier, word): + prop = struct.pack('!BH', identifier, word) + return prop + +def gen_uint32_prop(identifier, word): + prop = struct.pack('!BI', identifier, word) + return prop + +def gen_string_prop(identifier, s): + prop = struct.pack('!BH%ds'%(len(s)), identifier, len(s), s) + return prop + +def gen_string_pair_prop(identifier, s1, s2): + prop = struct.pack('!BH%dsH%ds'%(len(s1), len(s2)), identifier, len(s1), s1, len(s2), s2) + return prop + +def pack_varint(varint): + s = "" + while True: + byte = varint % 128 + varint = varint // 128 + # If there are more digits to encode, set the top bit of this digit + if varint > 0: + byte = byte | 0x80 + + s = s + struct.pack("!B", byte) + if varint == 0: + return s + +def prop_finalise(props): + return pack_varint(len(props)) + props + From 5aa983c21048a7c1e2ba9f60965c14e576177bb4 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 25 Oct 2018 20:41:34 +0100 Subject: [PATCH 066/254] Fix copy/paste error. --- lib/send_connect.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/send_connect.c b/lib/send_connect.c index 4bc7598944..841bf93673 100644 --- a/lib/send_connect.c +++ b/lib/send_connect.c @@ -137,7 +137,7 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session if(mosq->protocol == mosq_p_mqtt5){ /* Write properties */ - property__write_all(packet, mosq->will->properties); + property__write_all(packet, properties); } /* Payload */ @@ -145,7 +145,7 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session if(will){ if(mosq->protocol == mosq_p_mqtt5){ /* Write will properties */ - property__write_all(packet, NULL); + property__write_all(packet, mosq->will->properties); } packet__write_string(packet, mosq->will->msg.topic, strlen(mosq->will->msg.topic)); packet__write_string(packet, (const char *)mosq->will->msg.payload, mosq->will->msg.payloadlen); From be5602be286c21e010b28063c50bd7f69df76053 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 30 Oct 2018 10:03:08 +0000 Subject: [PATCH 067/254] Add sections to mosquitto.h. --- lib/mosquitto.h | 295 ++++++++++++++++++++++++++++++------------------ 1 file changed, 187 insertions(+), 108 deletions(-) diff --git a/lib/mosquitto.h b/lib/mosquitto.h index 45e3b825ba..374c67e68d 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -145,6 +145,12 @@ struct mosquitto; * mosquitto_publish() ***************************************************/ + +/* ====================================================================== + * + * Section: Library version, init, and cleanup + * + * ====================================================================== */ /* * Function: mosquitto_lib_version * @@ -197,6 +203,12 @@ libmosq_EXPORT int mosquitto_lib_init(void); */ libmosq_EXPORT int mosquitto_lib_cleanup(void); + +/* ====================================================================== + * + * Section: Client creation, destruction, and reinitialisation + * + * ====================================================================== */ /* * Function: mosquitto_new * @@ -270,6 +282,12 @@ libmosq_EXPORT void mosquitto_destroy(struct mosquitto *mosq); */ libmosq_EXPORT int mosquitto_reinitialise(struct mosquitto *mosq, const char *id, bool clean_session, void *obj); + +/* ====================================================================== + * + * Section: Will + * + * ====================================================================== */ /* * Function: mosquitto_will_set * @@ -311,6 +329,12 @@ libmosq_EXPORT int mosquitto_will_set(struct mosquitto *mosq, const char *topic, */ libmosq_EXPORT int mosquitto_will_clear(struct mosquitto *mosq); + +/* ====================================================================== + * + * Section: Username and password + * + * ====================================================================== */ /* * Function: mosquitto_username_pw_set * @@ -336,6 +360,12 @@ libmosq_EXPORT int mosquitto_will_clear(struct mosquitto *mosq); */ libmosq_EXPORT int mosquitto_username_pw_set(struct mosquitto *mosq, const char *username, const char *password); + +/* ====================================================================== + * + * Section: Connecting, reconnecting, disconnecting + * + * ====================================================================== */ /* * Function: mosquitto_connect * @@ -573,6 +603,12 @@ libmosq_EXPORT int mosquitto_reconnect_async(struct mosquitto *mosq); */ libmosq_EXPORT int mosquitto_disconnect(struct mosquitto *mosq); + +/* ====================================================================== + * + * Section: Publishing, subscribing, unsubscribing + * + * ====================================================================== */ /* * Function: mosquitto_publish * @@ -684,6 +720,12 @@ int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count */ libmosq_EXPORT int mosquitto_unsubscribe(struct mosquitto *mosq, int *mid, const char *sub); + +/* ====================================================================== + * + * Section: Struct mosquitto_message helper functions + * + * ====================================================================== */ /* * Function: mosquitto_message_copy * @@ -730,6 +772,12 @@ libmosq_EXPORT void mosquitto_message_free(struct mosquitto_message **message); */ libmosq_EXPORT void mosquitto_message_free_contents(struct mosquitto_message *message); + +/* ====================================================================== + * + * Section: Network loop (managed by libmosquitto) + * + * ====================================================================== */ /* * Function: mosquitto_loop * @@ -856,20 +904,12 @@ libmosq_EXPORT int mosquitto_loop_start(struct mosquitto *mosq); */ libmosq_EXPORT int mosquitto_loop_stop(struct mosquitto *mosq, bool force); -/* - * Function: mosquitto_socket - * - * Return the socket handle for a mosquitto instance. Useful if you want to - * include a mosquitto client in your own select() calls. + +/* ====================================================================== * - * Parameters: - * mosq - a valid mosquitto instance. + * Section: Network loop (for use in other event loops) * - * Returns: - * The socket for the mosquitto client or -1 on failure. - */ -libmosq_EXPORT int mosquitto_socket(struct mosquitto *mosq); - + * ====================================================================== */ /* * Function: mosquitto_loop_read * @@ -953,6 +993,26 @@ libmosq_EXPORT int mosquitto_loop_write(struct mosquitto *mosq, int max_packets) */ libmosq_EXPORT int mosquitto_loop_misc(struct mosquitto *mosq); + +/* ====================================================================== + * + * Section: Network loop (helper functions) + * + * ====================================================================== */ +/* + * Function: mosquitto_socket + * + * Return the socket handle for a mosquitto instance. Useful if you want to + * include a mosquitto client in your own select() calls. + * + * Parameters: + * mosq - a valid mosquitto instance. + * + * Returns: + * The socket for the mosquitto client or -1 on failure. + */ +libmosq_EXPORT int mosquitto_socket(struct mosquitto *mosq); + /* * Function: mosquitto_want_write * @@ -983,6 +1043,12 @@ libmosq_EXPORT bool mosquitto_want_write(struct mosquitto *mosq); */ libmosq_EXPORT int mosquitto_threaded_set(struct mosquitto *mosq, bool threaded); + +/* ====================================================================== + * + * Section: Client options + * + * ====================================================================== */ /* * Function: mosquitto_opts_set * @@ -1020,7 +1086,109 @@ libmosq_EXPORT int mosquitto_threaded_set(struct mosquitto *mosq, bool threaded) */ libmosq_EXPORT int mosquitto_opts_set(struct mosquitto *mosq, enum mosq_opt_t option, void *value); +/* + * Function: mosquitto_reconnect_delay_set + * + * Control the behaviour of the client when it has unexpectedly disconnected in + * or after . The default + * behaviour if this function is not used is to repeatedly attempt to reconnect + * with a delay of 1 second until the connection succeeds. + * + * Use reconnect_delay parameter to change the delay between successive + * reconnection attempts. You may also enable exponential backoff of the time + * between reconnections by setting reconnect_exponential_backoff to true and + * set an upper bound on the delay with reconnect_delay_max. + * + * Example 1: + * delay=2, delay_max=10, exponential_backoff=False + * Delays would be: 2, 4, 6, 8, 10, 10, ... + * + * Example 2: + * delay=3, delay_max=30, exponential_backoff=True + * Delays would be: 3, 6, 12, 24, 30, 30, ... + * + * Parameters: + * mosq - a valid mosquitto instance. + * reconnect_delay - the number of seconds to wait between + * reconnects. + * reconnect_delay_max - the maximum number of seconds to wait + * between reconnects. + * reconnect_exponential_backoff - use exponential backoff between + * reconnect attempts. Set to true to enable + * exponential backoff. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + */ +libmosq_EXPORT int mosquitto_reconnect_delay_set(struct mosquitto *mosq, unsigned int reconnect_delay, unsigned int reconnect_delay_max, bool reconnect_exponential_backoff); + +/* + * Function: mosquitto_max_inflight_messages_set + * + * Set the number of QoS 1 and 2 messages that can be "in flight" at one time. + * An in flight message is part way through its delivery flow. Attempts to send + * further messages with will result in the messages being + * queued until the number of in flight messages reduces. + * + * A higher number here results in greater message throughput, but if set + * higher than the maximum in flight messages on the broker may lead to + * delays in the messages being acknowledged. + * + * Set to 0 for no maximum. + * + * Parameters: + * mosq - a valid mosquitto instance. + * max_inflight_messages - the maximum number of inflight messages. Defaults + * to 20. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + */ +libmosq_EXPORT int mosquitto_max_inflight_messages_set(struct mosquitto *mosq, unsigned int max_inflight_messages); + +/* + * Function: mosquitto_message_retry_set + * + * This function now has no effect. + */ +libmosq_EXPORT void mosquitto_message_retry_set(struct mosquitto *mosq, unsigned int message_retry); + +/* + * Function: mosquitto_user_data_set + * + * When is called, the pointer given as the "obj" parameter + * will be passed to the callbacks as user data. The + * function allows this obj parameter to be updated at any time. This function + * will not modify the memory pointed to by the current user data pointer. If + * it is dynamically allocated memory you must free it yourself. + * + * Parameters: + * mosq - a valid mosquitto instance. + * obj - A user pointer that will be passed as an argument to any callbacks + * that are specified. + */ +libmosq_EXPORT void mosquitto_user_data_set(struct mosquitto *mosq, void *obj); + +/* Function: mosquitto_userdata + * + * Retrieve the "userdata" variable for a mosquitto client. + * + * Parameters: + * mosq - a valid mosquitto instance. + * + * Returns: + * A pointer to the userdata member variable. + */ +libmosq_EXPORT void *mosquitto_userdata(struct mosquitto *mosq); + +/* ====================================================================== + * + * Section: TLS support + * + * ====================================================================== */ /* * Function: mosquitto_tls_set * @@ -1162,6 +1330,12 @@ libmosq_EXPORT int mosquitto_tls_opts_set(struct mosquitto *mosq, int cert_reqs, */ libmosq_EXPORT int mosquitto_tls_psk_set(struct mosquitto *mosq, const char *psk, const char *identity, const char *ciphers); + +/* ====================================================================== + * + * Section: Callbacks + * + * ====================================================================== */ /* * Function: mosquitto_connect_callback_set * @@ -1334,90 +1508,6 @@ libmosq_EXPORT void mosquitto_unsubscribe_callback_set(struct mosquitto *mosq, v */ libmosq_EXPORT void mosquitto_log_callback_set(struct mosquitto *mosq, void (*on_log)(struct mosquitto *, void *, int, const char *)); -/* - * Function: mosquitto_reconnect_delay_set - * - * Control the behaviour of the client when it has unexpectedly disconnected in - * or after . The default - * behaviour if this function is not used is to repeatedly attempt to reconnect - * with a delay of 1 second until the connection succeeds. - * - * Use reconnect_delay parameter to change the delay between successive - * reconnection attempts. You may also enable exponential backoff of the time - * between reconnections by setting reconnect_exponential_backoff to true and - * set an upper bound on the delay with reconnect_delay_max. - * - * Example 1: - * delay=2, delay_max=10, exponential_backoff=False - * Delays would be: 2, 4, 6, 8, 10, 10, ... - * - * Example 2: - * delay=3, delay_max=30, exponential_backoff=True - * Delays would be: 3, 6, 12, 24, 30, 30, ... - * - * Parameters: - * mosq - a valid mosquitto instance. - * reconnect_delay - the number of seconds to wait between - * reconnects. - * reconnect_delay_max - the maximum number of seconds to wait - * between reconnects. - * reconnect_exponential_backoff - use exponential backoff between - * reconnect attempts. Set to true to enable - * exponential backoff. - * - * Returns: - * MOSQ_ERR_SUCCESS - on success. - * MOSQ_ERR_INVAL - if the input parameters were invalid. - */ -libmosq_EXPORT int mosquitto_reconnect_delay_set(struct mosquitto *mosq, unsigned int reconnect_delay, unsigned int reconnect_delay_max, bool reconnect_exponential_backoff); - -/* - * Function: mosquitto_max_inflight_messages_set - * - * Set the number of QoS 1 and 2 messages that can be "in flight" at one time. - * An in flight message is part way through its delivery flow. Attempts to send - * further messages with will result in the messages being - * queued until the number of in flight messages reduces. - * - * A higher number here results in greater message throughput, but if set - * higher than the maximum in flight messages on the broker may lead to - * delays in the messages being acknowledged. - * - * Set to 0 for no maximum. - * - * Parameters: - * mosq - a valid mosquitto instance. - * max_inflight_messages - the maximum number of inflight messages. Defaults - * to 20. - * - * Returns: - * MOSQ_ERR_SUCCESS - on success. - * MOSQ_ERR_INVAL - if the input parameters were invalid. - */ -libmosq_EXPORT int mosquitto_max_inflight_messages_set(struct mosquitto *mosq, unsigned int max_inflight_messages); - -/* - * Function: mosquitto_message_retry_set - * - * This function now has no effect. - */ -libmosq_EXPORT void mosquitto_message_retry_set(struct mosquitto *mosq, unsigned int message_retry); - -/* - * Function: mosquitto_user_data_set - * - * When is called, the pointer given as the "obj" parameter - * will be passed to the callbacks as user data. The - * function allows this obj parameter to be updated at any time. This function - * will not modify the memory pointed to by the current user data pointer. If - * it is dynamically allocated memory you must free it yourself. - * - * Parameters: - * mosq - a valid mosquitto instance. - * obj - A user pointer that will be passed as an argument to any callbacks - * that are specified. - */ -libmosq_EXPORT void mosquitto_user_data_set(struct mosquitto *mosq, void *obj); /* ============================================================================= * @@ -1443,6 +1533,7 @@ libmosq_EXPORT void mosquitto_user_data_set(struct mosquitto *mosq, void *obj); */ libmosq_EXPORT int mosquitto_socks5_set(struct mosquitto *mosq, const char *host, int port, const char *username, const char *password); + /* ============================================================================= * * Section: Utility functions @@ -1783,18 +1874,6 @@ libmosq_EXPORT int mosquitto_subscribe_callback( libmosq_EXPORT int mosquitto_validate_utf8(const char *str, int len); -/* Function: mosquitto_userdata - * - * Retrieve the "userdata" variable for a mosquitto client. - * - * Parameters: - * mosq - a valid mosquitto instance. - * - * Returns: - * A pointer to the userdata member variable. - */ -libmosq_EXPORT void *mosquitto_userdata(struct mosquitto *mosq); - #ifdef __cplusplus } #endif From 9eebcf6704558d0925025a21dd00783b8ebbdc51 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 30 Oct 2018 10:11:20 +0000 Subject: [PATCH 068/254] Rename property__free_all->mosquitto_property_free_all Make public function. --- lib/handle_auth.c | 2 +- lib/handle_connack.c | 4 ++-- lib/handle_pubackcomp.c | 2 +- lib/handle_publish.c | 4 ++-- lib/handle_pubrec.c | 2 +- lib/handle_pubrel.c | 2 +- lib/handle_suback.c | 2 +- lib/handle_unsuback.c | 2 +- lib/linker.version | 1 + lib/mosquitto.h | 24 ++++++++++++++++++++++++ lib/property_mosq.c | 14 +++++++------- lib/property_mosq.h | 1 - src/context.c | 2 +- src/database.c | 4 ++-- src/handle_auth.c | 2 +- src/handle_connack.c | 4 ++-- src/handle_connect.c | 12 ++++++------ src/handle_publish.c | 2 +- src/handle_subscribe.c | 4 ++-- src/handle_unsubscribe.c | 2 +- test/unit/property_read.c | 30 +++++++++++++++--------------- test/unit/property_write.c | 14 +++++++------- 22 files changed, 80 insertions(+), 56 deletions(-) diff --git a/lib/handle_auth.c b/lib/handle_auth.c index ef2b1f8354..670c8f07d5 100644 --- a/lib/handle_auth.c +++ b/lib/handle_auth.c @@ -43,7 +43,7 @@ int handle__auth(struct mosquitto *mosq) rc = property__read_all(AUTH, &mosq->in_packet, &properties); if(rc) return rc; - property__free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ + mosquitto_property_free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ return MOSQ_ERR_SUCCESS; } diff --git a/lib/handle_connack.c b/lib/handle_connack.c index b312501718..f8155fd1f3 100644 --- a/lib/handle_connack.c +++ b/lib/handle_connack.c @@ -44,9 +44,9 @@ int handle__connack(struct mosquitto *mosq) if(mosq->protocol == mosq_p_mqtt5){ rc = property__read_all(CONNACK, &mosq->in_packet, &properties); if(rc) return rc; - property__free_all(&properties); + mosquitto_property_free_all(&properties); } - property__free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ + mosquitto_property_free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received CONNACK (%d)", mosq->id, reason_code); pthread_mutex_lock(&mosq->callback_mutex); diff --git a/lib/handle_pubackcomp.c b/lib/handle_pubackcomp.c index e9f0d4f4eb..fb649ff8b8 100644 --- a/lib/handle_pubackcomp.c +++ b/lib/handle_pubackcomp.c @@ -55,7 +55,7 @@ int handle__pubackcomp(struct mosquitto *mosq, const char *type) rc = property__read_all(PUBACK, &mosq->in_packet, &properties); if(rc) return rc; /* Immediately free, we don't do anything with Reason String or User Property at the moment */ - property__free_all(&properties); + mosquitto_property_free_all(&properties); } #ifdef WITH_BROKER diff --git a/lib/handle_publish.c b/lib/handle_publish.c index 44257c6900..a3fb99dced 100644 --- a/lib/handle_publish.c +++ b/lib/handle_publish.c @@ -77,9 +77,9 @@ int handle__publish(struct mosquitto *mosq) if(mosq->protocol == mosq_p_mqtt5){ rc = property__read_all(PUBLISH, &mosq->in_packet, &properties); if(rc) return rc; - property__free_all(&properties); + mosquitto_property_free_all(&properties); } - property__free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ + mosquitto_property_free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ message->msg.payloadlen = mosq->in_packet.remaining_length - mosq->in_packet.pos; if(message->msg.payloadlen){ diff --git a/lib/handle_pubrec.c b/lib/handle_pubrec.c index 1d6401b0b6..a0cdaf1ba9 100644 --- a/lib/handle_pubrec.c +++ b/lib/handle_pubrec.c @@ -50,7 +50,7 @@ int handle__pubrec(struct mosquitto *mosq) rc = property__read_all(PUBREC, &mosq->in_packet, &properties); if(rc) return rc; /* Immediately free, we don't do anything with Reason String or User Property at the moment */ - property__free_all(&properties); + mosquitto_property_free_all(&properties); } #ifdef WITH_BROKER diff --git a/lib/handle_pubrel.c b/lib/handle_pubrel.c index 7ed08010c9..b3f426dcc7 100644 --- a/lib/handle_pubrel.c +++ b/lib/handle_pubrel.c @@ -59,7 +59,7 @@ int handle__pubrel(struct mosquitto_db *db, struct mosquitto *mosq) rc = property__read_all(PUBREL, &mosq->in_packet, &properties); if(rc) return rc; /* Immediately free, we don't do anything with Reason String or User Property at the moment */ - property__free_all(&properties); + mosquitto_property_free_all(&properties); } #ifdef WITH_BROKER diff --git a/lib/handle_suback.c b/lib/handle_suback.c index 2b23e134a5..0da0375810 100644 --- a/lib/handle_suback.c +++ b/lib/handle_suback.c @@ -55,7 +55,7 @@ int handle__suback(struct mosquitto *mosq) rc = property__read_all(SUBACK, &mosq->in_packet, &properties); if(rc) return rc; /* Immediately free, we don't do anything with Reason String or User Property at the moment */ - property__free_all(&properties); + mosquitto_property_free_all(&properties); } qos_count = mosq->in_packet.remaining_length - mosq->in_packet.pos; diff --git a/lib/handle_unsuback.c b/lib/handle_unsuback.c index 1e7fae8df6..0b1232d395 100644 --- a/lib/handle_unsuback.c +++ b/lib/handle_unsuback.c @@ -57,7 +57,7 @@ int handle__unsuback(struct mosquitto *mosq) rc = property__read_all(UNSUBACK, &mosq->in_packet, &properties); if(rc) return rc; /* Immediately free, we don't do anything with Reason String or User Property at the moment */ - property__free_all(&properties); + mosquitto_property_free_all(&properties); } #ifndef WITH_BROKER diff --git a/lib/linker.version b/lib/linker.version index fb18c049a3..727f85b0bf 100644 --- a/lib/linker.version +++ b/lib/linker.version @@ -95,4 +95,5 @@ MOSQ_1.5 { MOSQ_1.6 { global: mosquitto_subscribe_multiple; + mosquitto_property_free_all; } MOSQ_1.5; diff --git a/lib/mosquitto.h b/lib/mosquitto.h index 374c67e68d..668de8147f 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -114,6 +114,7 @@ struct mosquitto_message{ }; struct mosquitto; +typedef struct mqtt5__property mosquitto_property; /* * Topic: Threads @@ -1874,6 +1875,29 @@ libmosq_EXPORT int mosquitto_subscribe_callback( libmosq_EXPORT int mosquitto_validate_utf8(const char *str, int len); +/* ============================================================================= + * + * Section: Properties + * + * ============================================================================= + */ + +/* + * Function: mosquitto_property_free_all + * + * Free all properties from a list of properties. Frees the list and sets *properties to NULL. + * + * Parameters: + * properties - list of properties to free + * + * Example: + * mosquitto_properties *properties = NULL; + * // Add properties + * mosquitto_property_free_all(&properties); + */ +libmosq_EXPORT void mosquitto_property_free_all(mosquitto_property **properties); + + #ifdef __cplusplus } #endif diff --git a/lib/property_mosq.c b/lib/property_mosq.c index b4f44c845e..3c932cea14 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -161,7 +161,7 @@ int property__read_all(int command, struct mosquitto__packet *packet, struct mqt rc = property__read(packet, &proplen, p); if(rc){ mosquitto__free(p); - property__free_all(properties); + mosquitto_property_free_all(properties); return rc; } @@ -182,19 +182,19 @@ int property__read_all(int command, struct mosquitto__packet *packet, struct mqt || p->identifier == PROP_SHARED_SUB_AVAILABLE){ if(p->value.i8 > 1){ - property__free_all(properties); + mosquitto_property_free_all(properties); return MOSQ_ERR_PROTOCOL; } }else if(p->identifier == PROP_MAXIMUM_PACKET_SIZE){ if( p->value.i32 == 0){ - property__free_all(properties); + mosquitto_property_free_all(properties); return MOSQ_ERR_PROTOCOL; } }else if(p->identifier == PROP_RECEIVE_MAXIMUM || p->identifier == PROP_TOPIC_ALIAS){ if(p->value.i16 == 0){ - property__free_all(properties); + mosquitto_property_free_all(properties); return MOSQ_ERR_PROTOCOL; } } @@ -208,7 +208,7 @@ int property__read_all(int command, struct mosquitto__packet *packet, struct mqt if(current->identifier == tail->identifier && current->identifier != PROP_USER_PROPERTY){ - property__free_all(properties); + mosquitto_property_free_all(properties); return MOSQ_ERR_PROTOCOL; } tail = tail->next; @@ -218,7 +218,7 @@ int property__read_all(int command, struct mosquitto__packet *packet, struct mqt /* Check for properties on incorrect commands */ if(property__command_check(command, *properties)){ - property__free_all(properties); + mosquitto_property_free_all(properties); return MOSQ_ERR_PROTOCOL; } return MOSQ_ERR_SUCCESS; @@ -276,7 +276,7 @@ void property__free(struct mqtt5__property **property) } -void property__free_all(struct mqtt5__property **property) +void mosquitto_property_free_all(struct mqtt5__property **property) { struct mqtt5__property *p, *next; diff --git a/lib/property_mosq.h b/lib/property_mosq.h index 1253063a5a..5fbd311f2f 100644 --- a/lib/property_mosq.h +++ b/lib/property_mosq.h @@ -42,7 +42,6 @@ struct mqtt5__property { int property__read_all(int command, struct mosquitto__packet *packet, struct mqtt5__property **property); int property__write_all(struct mosquitto__packet *packet, struct mqtt5__property *property); void property__free(struct mqtt5__property **property); -void property__free_all(struct mqtt5__property **property); int property__get_length(struct mqtt5__property *property); int property__get_length_all(struct mqtt5__property *property); diff --git a/src/context.c b/src/context.c index f4fe9a43ce..a78ea1e170 100644 --- a/src/context.c +++ b/src/context.c @@ -226,7 +226,7 @@ void context__send_will(struct mosquitto_db *db, struct mosquitto *ctxt) } } if(ctxt->will){ - property__free_all(&ctxt->will->properties); + mosquitto_property_free_all(&ctxt->will->properties); mosquitto__free(ctxt->will->msg.topic); mosquitto__free(ctxt->will->msg.payload); mosquitto__free(ctxt->will); diff --git a/src/database.c b/src/database.c index 1595be214f..236d5bf052 100644 --- a/src/database.c +++ b/src/database.c @@ -207,7 +207,7 @@ void db__msg_store_remove(struct mosquitto_db *db, struct mosquitto_msg_store *s mosquitto__free(store->dest_ids); } mosquitto__free(store->topic); - property__free_all(&store->properties); + mosquitto_property_free_all(&store->properties); UHPA_FREE_PAYLOAD(store); mosquitto__free(store); } @@ -661,7 +661,7 @@ int db__message_store(struct mosquitto_db *db, const char *source, uint16_t sour mosquitto__free(temp->topic); mosquitto__free(temp); } - property__free_all(&properties); + mosquitto_property_free_all(&properties); return rc; } diff --git a/src/handle_auth.c b/src/handle_auth.c index 1941fb954a..083e6406f4 100644 --- a/src/handle_auth.c +++ b/src/handle_auth.c @@ -42,7 +42,7 @@ int handle__auth(struct mosquitto_db *db, struct mosquitto *context) rc = property__read_all(AUTH, &context->in_packet, &properties); if(rc) return rc; - property__free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ + mosquitto_property_free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ return MOSQ_ERR_SUCCESS; } diff --git a/src/handle_connack.c b/src/handle_connack.c index fd289b5f41..4fb76c4cbe 100644 --- a/src/handle_connack.c +++ b/src/handle_connack.c @@ -47,9 +47,9 @@ int handle__connack(struct mosquitto_db *db, struct mosquitto *context) if(context->protocol == mosq_p_mqtt5){ rc = property__read_all(CONNACK, &context->in_packet, &properties); if(rc) return rc; - property__free_all(&properties); + mosquitto_property_free_all(&properties); } - property__free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ + mosquitto_property_free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ switch(reason_code){ case CONNACK_ACCEPTED: diff --git a/src/handle_connect.c b/src/handle_connect.c index 6a4680aec8..a60e1f9ba2 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -244,9 +244,9 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) if(protocol_version == PROTOCOL_VERSION_v5){ rc = property__read_all(CONNECT, &context->in_packet, &properties); if(rc) return rc; - property__free_all(&properties); + mosquitto_property_free_all(&properties); } - property__free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ + mosquitto_property_free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ if(packet__read_string(&context->in_packet, &client_id, &slen)){ rc = 1; @@ -304,7 +304,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) if(protocol_version == PROTOCOL_VERSION_v5){ rc = property__read_all(CMD_WILL, &context->in_packet, &will_struct->properties); if(rc) return rc; - property__free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ + mosquitto_property_free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ } if(packet__read_string(&context->in_packet, &will_topic, &slen)){ rc = 1; @@ -709,7 +709,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) mosquitto__free(will_payload); mosquitto__free(will_topic); if(will_struct){ - property__free_all(&will_struct->properties); + mosquitto_property_free_all(&will_struct->properties); } mosquitto__free(will_struct); #ifdef WITH_TLS @@ -731,9 +731,9 @@ int handle__disconnect(struct mosquitto_db *db, struct mosquitto *context) if(context->protocol == mosq_p_mqtt5){ rc = property__read_all(DISCONNECT, &context->in_packet, &properties); if(rc) return rc; - property__free_all(&properties); + mosquitto_property_free_all(&properties); } - property__free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ + mosquitto_property_free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ if(context->in_packet.remaining_length != 0){ return MOSQ_ERR_PROTOCOL; diff --git a/src/handle_publish.c b/src/handle_publish.c index 20c5165949..a071481d81 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -194,7 +194,7 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) } } } - property__free_all(&properties); + mosquitto_property_free_all(&properties); payloadlen = context->in_packet.remaining_length - context->in_packet.pos; G_PUB_BYTES_RECEIVED_INC(payloadlen); diff --git a/src/handle_subscribe.c b/src/handle_subscribe.c index ebab3156df..0bd7b70205 100644 --- a/src/handle_subscribe.c +++ b/src/handle_subscribe.c @@ -55,9 +55,9 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) if(context->protocol == mosq_p_mqtt5){ rc = property__read_all(SUBSCRIBE, &context->in_packet, &properties); if(rc) return rc; - property__free_all(&properties); + mosquitto_property_free_all(&properties); } - property__free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ + mosquitto_property_free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ while(context->in_packet.pos < context->in_packet.remaining_length){ sub = NULL; diff --git a/src/handle_unsubscribe.c b/src/handle_unsubscribe.c index 56da9957c0..c64ae66c6f 100644 --- a/src/handle_unsubscribe.c +++ b/src/handle_unsubscribe.c @@ -48,7 +48,7 @@ int handle__unsubscribe(struct mosquitto_db *db, struct mosquitto *context) rc = property__read_all(UNSUBSCRIBE, &context->in_packet, &properties); if(rc) return rc; /* Immediately free, we don't do anything with User Property at the moment */ - property__free_all(&properties); + mosquitto_property_free_all(&properties); } if(context->protocol == mosq_p_mqtt311 || context->protocol == mosq_p_mqtt5){ diff --git a/test/unit/property_read.c b/test/unit/property_read.c index 86fb5ad691..2b34773529 100644 --- a/test/unit/property_read.c +++ b/test/unit/property_read.c @@ -29,7 +29,7 @@ static void byte_prop_read_helper( CU_ASSERT_EQUAL(properties->value.i8, value_expected); CU_ASSERT_PTR_EQUAL(properties->next, NULL); CU_ASSERT_EQUAL(property__get_length_all(properties), 2); - property__free_all(&properties); + mosquitto_property_free_all(&properties); } CU_ASSERT_PTR_EQUAL(properties, NULL); } @@ -85,7 +85,7 @@ static void int32_prop_read_helper( CU_ASSERT_EQUAL(properties->value.i32, value_expected); CU_ASSERT_PTR_EQUAL(properties->next, NULL); CU_ASSERT_EQUAL(property__get_length_all(properties), 5); - property__free_all(&properties); + mosquitto_property_free_all(&properties); } CU_ASSERT_PTR_EQUAL(properties, NULL); } @@ -135,7 +135,7 @@ static void int16_prop_read_helper( CU_ASSERT_EQUAL(properties->value.i16, value_expected); CU_ASSERT_PTR_EQUAL(properties->next, NULL); CU_ASSERT_EQUAL(property__get_length_all(properties), 3); - property__free_all(&properties); + mosquitto_property_free_all(&properties); } CU_ASSERT_PTR_EQUAL(properties, NULL); } @@ -181,7 +181,7 @@ static void string_prop_read_helper( CU_ASSERT_STRING_EQUAL(properties->value.s.v, value_expected); CU_ASSERT_PTR_EQUAL(properties->next, NULL); CU_ASSERT_EQUAL(property__get_length_all(properties), 1+2+strlen(value_expected)); - property__free_all(&properties); + mosquitto_property_free_all(&properties); } CU_ASSERT_PTR_EQUAL(properties, NULL); } @@ -246,7 +246,7 @@ static void binary_prop_read_helper( CU_ASSERT_EQUAL(memcmp(properties->value.bin.v, value_expected, len_expected), 0); CU_ASSERT_PTR_EQUAL(properties->next, NULL); CU_ASSERT_EQUAL(property__get_length_all(properties), 1+2+len_expected); - property__free_all(&properties); + mosquitto_property_free_all(&properties); } CU_ASSERT_PTR_EQUAL(properties, NULL); } @@ -301,7 +301,7 @@ static void string_pair_prop_read_helper( CU_ASSERT_PTR_NULL(properties->next); CU_ASSERT_EQUAL(property__get_length_all(properties), 1+2+strlen(name_expected)+2+strlen(value_expected)); } - property__free_all(&properties); + mosquitto_property_free_all(&properties); } CU_ASSERT_PTR_NULL(properties); } @@ -328,7 +328,7 @@ static void varint_prop_read_helper( CU_ASSERT_EQUAL(properties->value.varint, value_expected); CU_ASSERT_PTR_NULL(properties->next); CU_ASSERT_EQUAL(property__get_length_all(properties), packet__varint_bytes(value_expected)+1); - property__free_all(&properties); + mosquitto_property_free_all(&properties); } CU_ASSERT_PTR_NULL(properties); } @@ -367,7 +367,7 @@ static void packet_helper_reason_string_user_property(int command) CU_ASSERT_STRING_EQUAL(p->name.v, "name"); CU_ASSERT_EQUAL(p->name.len, strlen("name")); - property__free_all(&properties); + mosquitto_property_free_all(&properties); } } @@ -1273,7 +1273,7 @@ static void TEST_packet_connect(void) CU_ASSERT_EQUAL(p->value.bin.v[1], 2); CU_ASSERT_EQUAL(p->value.s.len, 2); - property__free_all(&properties); + mosquitto_property_free_all(&properties); } static void TEST_packet_connack(void) @@ -1406,7 +1406,7 @@ static void TEST_packet_connack(void) CU_ASSERT_EQUAL(p->value.bin.v[1], 2); CU_ASSERT_EQUAL(p->value.s.len, 2); - property__free_all(&properties); + mosquitto_property_free_all(&properties); } static void TEST_packet_publish(void) @@ -1482,7 +1482,7 @@ static void TEST_packet_publish(void) CU_ASSERT_STRING_EQUAL(p->value.s.v, "empty"); CU_ASSERT_EQUAL(p->value.s.len, strlen("empty")); - property__free_all(&properties); + mosquitto_property_free_all(&properties); } static void TEST_packet_puback(void) @@ -1538,7 +1538,7 @@ static void TEST_packet_subscribe(void) CU_ASSERT_EQUAL(p->identifier, PROP_SUBSCRIPTION_IDENTIFIER); CU_ASSERT_EQUAL(p->value.varint, 0x00000004); - property__free_all(&properties); + mosquitto_property_free_all(&properties); } static void TEST_packet_suback(void) @@ -1572,7 +1572,7 @@ static void TEST_packet_unsubscribe(void) CU_ASSERT_STRING_EQUAL(p->name.v, "name"); CU_ASSERT_EQUAL(p->name.len, strlen("name")); - property__free_all(&properties); + mosquitto_property_free_all(&properties); } static void TEST_packet_unsuback(void) @@ -1620,7 +1620,7 @@ static void TEST_packet_disconnect(void) CU_ASSERT_STRING_EQUAL(p->name.v, "name"); CU_ASSERT_EQUAL(p->name.len, strlen("name")); - property__free_all(&properties); + mosquitto_property_free_all(&properties); } static void TEST_packet_auth(void) @@ -1672,7 +1672,7 @@ static void TEST_packet_auth(void) CU_ASSERT_STRING_EQUAL(p->name.v, "name"); CU_ASSERT_EQUAL(p->name.len, strlen("name")); - property__free_all(&properties); + mosquitto_property_free_all(&properties); } diff --git a/test/unit/property_write.c b/test/unit/property_write.c index 5eb9caee7e..950034122f 100644 --- a/test/unit/property_write.c +++ b/test/unit/property_write.c @@ -39,7 +39,7 @@ static void byte_prop_write_helper( CU_ASSERT_EQUAL(properties->value.i8, value_expected); CU_ASSERT_PTR_EQUAL(properties->next, NULL); CU_ASSERT_EQUAL(property__get_length_all(properties), 2); - property__free_all(&properties); + mosquitto_property_free_all(&properties); } CU_ASSERT_PTR_EQUAL(properties, NULL); } @@ -79,7 +79,7 @@ static void int32_prop_write_helper( CU_ASSERT_EQUAL(properties->value.i32, value_expected); CU_ASSERT_PTR_EQUAL(properties->next, NULL); CU_ASSERT_EQUAL(property__get_length_all(properties), 5); - property__free_all(&properties); + mosquitto_property_free_all(&properties); } CU_ASSERT_PTR_EQUAL(properties, NULL); } @@ -119,7 +119,7 @@ static void int16_prop_write_helper( CU_ASSERT_EQUAL(properties->value.i16, value_expected); CU_ASSERT_PTR_EQUAL(properties->next, NULL); CU_ASSERT_EQUAL(property__get_length_all(properties), 3); - property__free_all(&properties); + mosquitto_property_free_all(&properties); } CU_ASSERT_PTR_EQUAL(properties, NULL); } @@ -160,7 +160,7 @@ static void string_prop_write_helper( CU_ASSERT_STRING_EQUAL(properties->value.s.v, value_expected); CU_ASSERT_PTR_EQUAL(properties->next, NULL); CU_ASSERT_EQUAL(property__get_length_all(properties), 1+2+strlen(value_expected)); - property__free_all(&properties); + mosquitto_property_free_all(&properties); } CU_ASSERT_PTR_EQUAL(properties, NULL); free(property.value.s.v); @@ -205,7 +205,7 @@ static void binary_prop_write_helper( CU_ASSERT_EQUAL(memcmp(properties->value.bin.v, value_expected, len_expected), 0); CU_ASSERT_PTR_EQUAL(properties->next, NULL); CU_ASSERT_EQUAL(property__get_length_all(properties), 1+2+len_expected); - property__free_all(&properties); + mosquitto_property_free_all(&properties); } CU_ASSERT_PTR_EQUAL(properties, NULL); free(property.value.bin.v); @@ -256,7 +256,7 @@ static void string_pair_prop_write_helper( CU_ASSERT_PTR_NULL(properties->next); CU_ASSERT_EQUAL(property__get_length_all(properties), 1+2+strlen(name_expected)+2+strlen(value_expected)); } - property__free_all(&properties); + mosquitto_property_free_all(&properties); } CU_ASSERT_PTR_NULL(properties); free(property.value.s.v); @@ -305,7 +305,7 @@ static void varint_prop_write_helper( }else{ CU_FAIL("Incorrect varint value."); } - property__free_all(&properties); + mosquitto_property_free_all(&properties); } CU_ASSERT_PTR_NULL(properties); } From 636e813d1c1b35dec189115fd621a19d97f141b4 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 30 Oct 2018 11:00:16 +0000 Subject: [PATCH 069/254] Load of constant renames ahead of making mqtt_protocol.h public. --- lib/handle_auth.c | 2 +- lib/handle_connack.c | 2 +- lib/handle_pubackcomp.c | 2 +- lib/handle_publish.c | 2 +- lib/handle_pubrec.c | 2 +- lib/handle_pubrel.c | 2 +- lib/handle_suback.c | 2 +- lib/handle_unsuback.c | 2 +- lib/mosquitto.c | 86 +++---- lib/mqtt_protocol.h | 188 ++++++++------- lib/packet_mosq.c | 8 +- lib/property_mosq.c | 314 ++++++++++++------------- lib/read_handle.c | 22 +- lib/send_connect.c | 2 +- lib/send_disconnect.c | 2 +- lib/send_mosq.c | 12 +- lib/send_publish.c | 2 +- lib/send_subscribe.c | 2 +- lib/send_unsubscribe.c | 2 +- src/handle_auth.c | 2 +- src/handle_connack.c | 2 +- src/handle_connect.c | 4 +- src/handle_publish.c | 18 +- src/handle_subscribe.c | 2 +- src/handle_unsubscribe.c | 4 +- src/read_handle.c | 30 +-- src/send_connack.c | 2 +- src/send_suback.c | 2 +- test/unit/property_read.c | 462 ++++++++++++++++++------------------- test/unit/property_write.c | 72 +++--- 30 files changed, 627 insertions(+), 629 deletions(-) diff --git a/lib/handle_auth.c b/lib/handle_auth.c index 670c8f07d5..fa798ee333 100644 --- a/lib/handle_auth.c +++ b/lib/handle_auth.c @@ -41,7 +41,7 @@ int handle__auth(struct mosquitto *mosq) if(packet__read_byte(&mosq->in_packet, &reason_code)) return 1; - rc = property__read_all(AUTH, &mosq->in_packet, &properties); + rc = property__read_all(CMD_AUTH, &mosq->in_packet, &properties); if(rc) return rc; mosquitto_property_free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ diff --git a/lib/handle_connack.c b/lib/handle_connack.c index f8155fd1f3..0c96fdf9f1 100644 --- a/lib/handle_connack.c +++ b/lib/handle_connack.c @@ -42,7 +42,7 @@ int handle__connack(struct mosquitto *mosq) if(rc) return rc; if(mosq->protocol == mosq_p_mqtt5){ - rc = property__read_all(CONNACK, &mosq->in_packet, &properties); + rc = property__read_all(CMD_CONNACK, &mosq->in_packet, &properties); if(rc) return rc; mosquitto_property_free_all(&properties); } diff --git a/lib/handle_pubackcomp.c b/lib/handle_pubackcomp.c index fb649ff8b8..3f8ae22f9e 100644 --- a/lib/handle_pubackcomp.c +++ b/lib/handle_pubackcomp.c @@ -52,7 +52,7 @@ int handle__pubackcomp(struct mosquitto *mosq, const char *type) if(mid == 0) return MOSQ_ERR_PROTOCOL; if(mosq->protocol == mosq_p_mqtt5){ - rc = property__read_all(PUBACK, &mosq->in_packet, &properties); + rc = property__read_all(CMD_PUBACK, &mosq->in_packet, &properties); if(rc) return rc; /* Immediately free, we don't do anything with Reason String or User Property at the moment */ mosquitto_property_free_all(&properties); diff --git a/lib/handle_publish.c b/lib/handle_publish.c index a3fb99dced..3bfd19fb9b 100644 --- a/lib/handle_publish.c +++ b/lib/handle_publish.c @@ -75,7 +75,7 @@ int handle__publish(struct mosquitto *mosq) } if(mosq->protocol == mosq_p_mqtt5){ - rc = property__read_all(PUBLISH, &mosq->in_packet, &properties); + rc = property__read_all(CMD_PUBLISH, &mosq->in_packet, &properties); if(rc) return rc; mosquitto_property_free_all(&properties); } diff --git a/lib/handle_pubrec.c b/lib/handle_pubrec.c index a0cdaf1ba9..778db6aacf 100644 --- a/lib/handle_pubrec.c +++ b/lib/handle_pubrec.c @@ -47,7 +47,7 @@ int handle__pubrec(struct mosquitto *mosq) if(mid == 0) return MOSQ_ERR_PROTOCOL; if(mosq->protocol == mosq_p_mqtt5){ - rc = property__read_all(PUBREC, &mosq->in_packet, &properties); + rc = property__read_all(CMD_PUBREC, &mosq->in_packet, &properties); if(rc) return rc; /* Immediately free, we don't do anything with Reason String or User Property at the moment */ mosquitto_property_free_all(&properties); diff --git a/lib/handle_pubrel.c b/lib/handle_pubrel.c index b3f426dcc7..440791e871 100644 --- a/lib/handle_pubrel.c +++ b/lib/handle_pubrel.c @@ -56,7 +56,7 @@ int handle__pubrel(struct mosquitto_db *db, struct mosquitto *mosq) if(mid == 0) return MOSQ_ERR_PROTOCOL; if(mosq->protocol == mosq_p_mqtt5){ - rc = property__read_all(PUBREL, &mosq->in_packet, &properties); + rc = property__read_all(CMD_PUBREL, &mosq->in_packet, &properties); if(rc) return rc; /* Immediately free, we don't do anything with Reason String or User Property at the moment */ mosquitto_property_free_all(&properties); diff --git a/lib/handle_suback.c b/lib/handle_suback.c index 0da0375810..c41297b8a6 100644 --- a/lib/handle_suback.c +++ b/lib/handle_suback.c @@ -52,7 +52,7 @@ int handle__suback(struct mosquitto *mosq) if(mid == 0) return MOSQ_ERR_PROTOCOL; if(mosq->protocol == mosq_p_mqtt5){ - rc = property__read_all(SUBACK, &mosq->in_packet, &properties); + rc = property__read_all(CMD_SUBACK, &mosq->in_packet, &properties); if(rc) return rc; /* Immediately free, we don't do anything with Reason String or User Property at the moment */ mosquitto_property_free_all(&properties); diff --git a/lib/handle_unsuback.c b/lib/handle_unsuback.c index 0b1232d395..83050f6569 100644 --- a/lib/handle_unsuback.c +++ b/lib/handle_unsuback.c @@ -54,7 +54,7 @@ int handle__unsuback(struct mosquitto *mosq) if(mid == 0) return MOSQ_ERR_PROTOCOL; if(mosq->protocol == mosq_p_mqtt5){ - rc = property__read_all(UNSUBACK, &mosq->in_packet, &properties); + rc = property__read_all(CMD_UNSUBACK, &mosq->in_packet, &properties); if(rc) return rc; /* Immediately free, we don't do anything with Reason String or User Property at the moment */ mosquitto_property_free_all(&properties); diff --git a/lib/mosquitto.c b/lib/mosquitto.c index 9c3261de09..e5bd32927c 100644 --- a/lib/mosquitto.c +++ b/lib/mosquitto.c @@ -401,92 +401,92 @@ const char *mosquitto_connack_string(int connack_code) const char *mosquitto_reason_string(int reason_code) { switch(reason_code){ - case RC5_SUCCESS: + case MQTT_RC_SUCCESS: return "Success"; - case RC5_GRANTED_QOS1: + case MQTT_RC_GRANTED_QOS1: return "Granted QoS 1"; - case RC5_GRANTED_QOS2: + case MQTT_RC_GRANTED_QOS2: return "Granted QoS 2"; - case RC5_DISCONNECT_WITH_WILL_MSG: + case MQTT_RC_DISCONNECT_WITH_WILL_MSG: return "Disconnect with Will Message"; - case RC5_NO_MATCHING_SUBSCRIBERS: + case MQTT_RC_NO_MATCHING_SUBSCRIBERS: return "No matching subscribers"; - case RC5_NO_SUBSCRIPTION_EXISTED: + case MQTT_RC_NO_SUBSCRIPTION_EXISTED: return "No subscription existed"; - case RC5_CONTINUE_AUTHENTICATION: + case MQTT_RC_CONTINUE_AUTHENTICATION: return "Continue authentication"; - case RC5_REAUTHENTICATE: + case MQTT_RC_REAUTHENTICATE: return "Re-authenticate"; - case RC5_UNSPECIFIED: + case MQTT_RC_UNSPECIFIED: return "Unspecified error"; - case RC5_MALFORMED_PACKET: + case MQTT_RC_MALFORMED_PACKET: return "Malformed Packet"; - case RC5_PROTOCOL_ERROR: + case MQTT_RC_PROTOCOL_ERROR: return "Protocol Error"; - case RC5_IMPLEMENTATION_SPECIFIC: + case MQTT_RC_IMPLEMENTATION_SPECIFIC: return "Implementation specific error"; - case RC5_UNSUPPORTED_PROTOCOL_VERSION: + case MQTT_RC_UNSUPPORTED_PROTOCOL_VERSION: return "Unsupported Protocol Version"; - case RC5_CLIENTID_NOT_VALID: + case MQTT_RC_CLIENTID_NOT_VALID: return "Client Identifier not valid"; - case RC5_BAD_USERNAME_OR_PASSWORD: + case MQTT_RC_BAD_USERNAME_OR_PASSWORD: return "Bad User Name or Password"; - case RC5_NOT_AUTHORIZED: + case MQTT_RC_NOT_AUTHORIZED: return "Not authorized"; - case RC5_SERVER_UNAVAILABLE: + case MQTT_RC_SERVER_UNAVAILABLE: return "Server unavailable"; - case RC5_SERVER_BUSY: + case MQTT_RC_SERVER_BUSY: return "Server busy"; - case RC5_BANNED: + case MQTT_RC_BANNED: return "Banned"; - case RC5_SERVER_SHUTTING_DOWN: + case MQTT_RC_SERVER_SHUTTING_DOWN: return "Server shutting down"; - case RC5_BAD_AUTHENTICATION_METHOD: + case MQTT_RC_BAD_AUTHENTICATION_METHOD: return "Bad authentication method"; - case RC5_KEEP_ALIVE_TIMEOUT: + case MQTT_RC_KEEP_ALIVE_TIMEOUT: return "Keep Alive timeout"; - case RC5_SESSION_TAKEN_OVER: + case MQTT_RC_SESSION_TAKEN_OVER: return "Session taken over"; - case RC5_TOPIC_FILTER_INVALID: + case MQTT_RC_TOPIC_FILTER_INVALID: return "Topic Filter invalid"; - case RC5_TOPIC_NAME_INVALID: + case MQTT_RC_TOPIC_NAME_INVALID: return "Topic Name invalid"; - case RC5_PACKET_ID_IN_USE: + case MQTT_RC_PACKET_ID_IN_USE: return "Packet Identifier in use"; - case RC5_PACKET_ID_NOT_FOUND: + case MQTT_RC_PACKET_ID_NOT_FOUND: return "Packet Identifier not found"; - case RC5_RECEIVE_MAXIMUM_EXCEEDED: + case MQTT_RC_RECEIVE_MAXIMUM_EXCEEDED: return "Receive Maximum exceeded"; - case RC5_TOPIC_ALIAS_INVALID: + case MQTT_RC_TOPIC_ALIAS_INVALID: return "Topic Alias invalid"; - case RC5_PACKET_TOO_LARGE: + case MQTT_RC_PACKET_TOO_LARGE: return "Packet too large"; - case RC5_MESSAGE_RATE_TOO_HIGH: + case MQTT_RC_MESSAGE_RATE_TOO_HIGH: return "Message rate too high"; - case RC5_QUOTA_EXCEEDED: + case MQTT_RC_QUOTA_EXCEEDED: return "Quota exceeded"; - case RC5_ADMINISTRATIVE_ACTION: + case MQTT_RC_ADMINISTRATIVE_ACTION: return "Administrative action"; - case RC5_PAYLOAD_FORMAT_INVALID: + case MQTT_RC_PAYLOAD_FORMAT_INVALID: return "Payload format invalid"; - case RC5_RETAIN_NOT_SUPPORTED: + case MQTT_RC_RETAIN_NOT_SUPPORTED: return "Retain not supported"; - case RC5_QOS_NOT_SUPPORTED: + case MQTT_RC_QOS_NOT_SUPPORTED: return "QoS not supported"; - case RC5_USE_ANOTHER_SERVER: + case MQTT_RC_USE_ANOTHER_SERVER: return "Use another server"; - case RC5_SERVER_MOVED: + case MQTT_RC_SERVER_MOVED: return "Server moved"; - case RC5_SHARED_SUBS_NOT_SUPPORTED: + case MQTT_RC_SHARED_SUBS_NOT_SUPPORTED: return "Shared Subscriptions not supported"; - case RC5_CONNECTION_RATE_EXCEEDED: + case MQTT_RC_CONNECTION_RATE_EXCEEDED: return "Connection rate exceeded"; - case RC5_MAXIMUM_CONNECT_TIME: + case MQTT_RC_MAXIMUM_CONNECT_TIME: return "Maximum connect time"; - case RC5_SUBSCRIPTION_IDS_NOT_SUPPORTED: + case MQTT_RC_SUBSCRIPTION_IDS_NOT_SUPPORTED: return "Subscription identifiers not supported"; - case RC5_WILDCARD_SUBS_NOT_SUPPORTED: + case MQTT_RC_WILDCARD_SUBS_NOT_SUPPORTED: return "Wildcard Subscriptions not supported"; default: return "Unknown reason"; diff --git a/lib/mqtt_protocol.h b/lib/mqtt_protocol.h index 62befba6f1..4b132018a9 100644 --- a/lib/mqtt_protocol.h +++ b/lib/mqtt_protocol.h @@ -14,10 +14,8 @@ and the Eclipse Distribution License is available at Roger Light - initial implementation and documentation. */ -#ifndef MQTT3_PROTOCOL_H -#define MQTT3_PROTOCOL_H - -/* For version 3 of the MQTT protocol */ +#ifndef MQTT_PROTOCOL_H +#define MQTT_PROTOCOL_H #define PROTOCOL_NAME_v31 "MQIsdp" #define PROTOCOL_VERSION_v31 3 @@ -29,24 +27,24 @@ and the Eclipse Distribution License is available at /* Message types */ -#define CONNECT 0x10 -#define CONNACK 0x20 -#define PUBLISH 0x30 -#define PUBACK 0x40 -#define PUBREC 0x50 -#define PUBREL 0x60 -#define PUBCOMP 0x70 -#define SUBSCRIBE 0x80 -#define SUBACK 0x90 -#define UNSUBSCRIBE 0xA0 -#define UNSUBACK 0xB0 -#define PINGREQ 0xC0 -#define PINGRESP 0xD0 -#define DISCONNECT 0xE0 -#define AUTH 0xF0 - -/* For distinguishing CONNECT and WILL properties */ -#define CMD_WILL 0 +#define CMD_CONNECT 0x10 +#define CMD_CONNACK 0x20 +#define CMD_PUBLISH 0x30 +#define CMD_PUBACK 0x40 +#define CMD_PUBREC 0x50 +#define CMD_PUBREL 0x60 +#define CMD_PUBCOMP 0x70 +#define CMD_SUBSCRIBE 0x80 +#define CMD_SUBACK 0x90 +#define CMD_UNSUBSCRIBE 0xA0 +#define CMD_UNSUBACK 0xB0 +#define CMD_PINGREQ 0xC0 +#define CMD_PINGRESP 0xD0 +#define CMD_DISCONNECT 0xE0 +#define CMD_AUTH 0xF0 + +/* Mosquitto only: for distinguishing CONNECT and WILL properties */ +#define CMD_WILL 0x100 enum mqtt311_connack_codes { CONNACK_ACCEPTED = 0, @@ -59,82 +57,82 @@ enum mqtt311_connack_codes { enum mqtt5_return_codes { - RC5_SUCCESS = 0, /* CONNACK, PUBACK, PUBREC, PUBREL, PUBCOMP, UNSUBACK, AUTH */ - RC5_NORMAL_DISCONNECTION = 0, /* DISCONNECT */ - RC5_GRANTED_QOS0 = 0, /* SUBACK */ - RC5_GRANTED_QOS1 = 1, /* SUBACK */ - RC5_GRANTED_QOS2 = 2, /* SUBACK */ - RC5_DISCONNECT_WITH_WILL_MSG = 4, /* DISCONNECT */ - RC5_NO_MATCHING_SUBSCRIBERS = 16, /* PUBACK, PUBREC */ - RC5_NO_SUBSCRIPTION_EXISTED = 17, /* UNSUBACK */ - RC5_CONTINUE_AUTHENTICATION = 24, /* AUTH */ - RC5_REAUTHENTICATE = 25, /* AUTH */ - - RC5_UNSPECIFIED = 128, /* CONNACK, PUBACK, PUBREC, SUBACK, UNSUBACK, DISCONNECT */ - RC5_MALFORMED_PACKET = 129, /* CONNACK, DISCONNECT */ - RC5_PROTOCOL_ERROR = 130, /* DISCONNECT */ - RC5_IMPLEMENTATION_SPECIFIC = 131, /* CONNACK, PUBACK, PUBREC, SUBACK, UNSUBACK, DISCONNECT */ - RC5_UNSUPPORTED_PROTOCOL_VERSION = 132, /* CONNACK */ - RC5_CLIENTID_NOT_VALID = 133, /* CONNACK */ - RC5_BAD_USERNAME_OR_PASSWORD = 134, /* CONNACK */ - RC5_NOT_AUTHORIZED = 135, /* CONNACK, PUBACK, PUBREC, SUBACK, UNSUBACK, DISCONNECT */ - RC5_SERVER_UNAVAILABLE = 136, /* CONNACK */ - RC5_SERVER_BUSY = 137, /* CONNACK, DISCONNECT */ - RC5_BANNED = 138, /* CONNACK */ - RC5_SERVER_SHUTTING_DOWN = 139, /* DISCONNECT */ - RC5_BAD_AUTHENTICATION_METHOD = 140, /* CONNACK */ - RC5_KEEP_ALIVE_TIMEOUT = 141, /* DISCONNECT */ - RC5_SESSION_TAKEN_OVER = 142, /* DISCONNECT */ - RC5_TOPIC_FILTER_INVALID = 143, /* SUBACK, UNSUBACK, DISCONNECT */ - RC5_TOPIC_NAME_INVALID = 144, /* CONNACK, PUBACK, PUBREC, DISCONNECT */ - RC5_PACKET_ID_IN_USE = 145, /* PUBACK, SUBACK, UNSUBACK */ - RC5_PACKET_ID_NOT_FOUND = 146, /* PUBREL, PUBCOMP */ - RC5_RECEIVE_MAXIMUM_EXCEEDED = 147, /* DISCONNECT */ - RC5_TOPIC_ALIAS_INVALID = 148, /* DISCONNECT */ - RC5_PACKET_TOO_LARGE = 149, /* CONNACK, PUBACK, PUBREC, DISCONNECT */ - RC5_MESSAGE_RATE_TOO_HIGH = 150, /* DISCONNECT */ - RC5_QUOTA_EXCEEDED = 151, /* PUBACK, PUBREC, SUBACK, DISCONNECT */ - RC5_ADMINISTRATIVE_ACTION = 152, /* DISCONNECT */ - RC5_PAYLOAD_FORMAT_INVALID = 153, /* CONNACK, DISCONNECT */ - RC5_RETAIN_NOT_SUPPORTED = 154, /* CONNACK, DISCONNECT */ - RC5_QOS_NOT_SUPPORTED = 155, /* CONNACK, DISCONNECT */ - RC5_USE_ANOTHER_SERVER = 156, /* CONNACK, DISCONNECT */ - RC5_SERVER_MOVED = 157, /* CONNACK, DISCONNECT */ - RC5_SHARED_SUBS_NOT_SUPPORTED = 158, /* SUBACK, DISCONNECT */ - RC5_CONNECTION_RATE_EXCEEDED = 159, /* CONNACK, DISCONNECT */ - RC5_MAXIMUM_CONNECT_TIME = 160, /* DISCONNECT */ - RC5_SUBSCRIPTION_IDS_NOT_SUPPORTED = 161, /* SUBACK, DISCONNECT */ - RC5_WILDCARD_SUBS_NOT_SUPPORTED = 162, /* SUBACK, DISCONNECT */ + MQTT_RC_SUCCESS = 0, /* CONNACK, PUBACK, PUBREC, PUBREL, PUBCOMP, UNSUBACK, AUTH */ + MQTT_RC_NORMAL_DISCONNECTION = 0, /* DISCONNECT */ + MQTT_RC_GRANTED_QOS0 = 0, /* SUBACK */ + MQTT_RC_GRANTED_QOS1 = 1, /* SUBACK */ + MQTT_RC_GRANTED_QOS2 = 2, /* SUBACK */ + MQTT_RC_DISCONNECT_WITH_WILL_MSG = 4, /* DISCONNECT */ + MQTT_RC_NO_MATCHING_SUBSCRIBERS = 16, /* PUBACK, PUBREC */ + MQTT_RC_NO_SUBSCRIPTION_EXISTED = 17, /* UNSUBACK */ + MQTT_RC_CONTINUE_AUTHENTICATION = 24, /* AUTH */ + MQTT_RC_REAUTHENTICATE = 25, /* AUTH */ + + MQTT_RC_UNSPECIFIED = 128, /* CONNACK, PUBACK, PUBREC, SUBACK, UNSUBACK, DISCONNECT */ + MQTT_RC_MALFORMED_PACKET = 129, /* CONNACK, DISCONNECT */ + MQTT_RC_PROTOCOL_ERROR = 130, /* DISCONNECT */ + MQTT_RC_IMPLEMENTATION_SPECIFIC = 131, /* CONNACK, PUBACK, PUBREC, SUBACK, UNSUBACK, DISCONNECT */ + MQTT_RC_UNSUPPORTED_PROTOCOL_VERSION = 132, /* CONNACK */ + MQTT_RC_CLIENTID_NOT_VALID = 133, /* CONNACK */ + MQTT_RC_BAD_USERNAME_OR_PASSWORD = 134, /* CONNACK */ + MQTT_RC_NOT_AUTHORIZED = 135, /* CONNACK, PUBACK, PUBREC, SUBACK, UNSUBACK, DISCONNECT */ + MQTT_RC_SERVER_UNAVAILABLE = 136, /* CONNACK */ + MQTT_RC_SERVER_BUSY = 137, /* CONNACK, DISCONNECT */ + MQTT_RC_BANNED = 138, /* CONNACK */ + MQTT_RC_SERVER_SHUTTING_DOWN = 139, /* DISCONNECT */ + MQTT_RC_BAD_AUTHENTICATION_METHOD = 140, /* CONNACK */ + MQTT_RC_KEEP_ALIVE_TIMEOUT = 141, /* DISCONNECT */ + MQTT_RC_SESSION_TAKEN_OVER = 142, /* DISCONNECT */ + MQTT_RC_TOPIC_FILTER_INVALID = 143, /* SUBACK, UNSUBACK, DISCONNECT */ + MQTT_RC_TOPIC_NAME_INVALID = 144, /* CONNACK, PUBACK, PUBREC, DISCONNECT */ + MQTT_RC_PACKET_ID_IN_USE = 145, /* PUBACK, SUBACK, UNSUBACK */ + MQTT_RC_PACKET_ID_NOT_FOUND = 146, /* PUBREL, PUBCOMP */ + MQTT_RC_RECEIVE_MAXIMUM_EXCEEDED = 147, /* DISCONNECT */ + MQTT_RC_TOPIC_ALIAS_INVALID = 148, /* DISCONNECT */ + MQTT_RC_PACKET_TOO_LARGE = 149, /* CONNACK, PUBACK, PUBREC, DISCONNECT */ + MQTT_RC_MESSAGE_RATE_TOO_HIGH = 150, /* DISCONNECT */ + MQTT_RC_QUOTA_EXCEEDED = 151, /* PUBACK, PUBREC, SUBACK, DISCONNECT */ + MQTT_RC_ADMINISTRATIVE_ACTION = 152, /* DISCONNECT */ + MQTT_RC_PAYLOAD_FORMAT_INVALID = 153, /* CONNACK, DISCONNECT */ + MQTT_RC_RETAIN_NOT_SUPPORTED = 154, /* CONNACK, DISCONNECT */ + MQTT_RC_QOS_NOT_SUPPORTED = 155, /* CONNACK, DISCONNECT */ + MQTT_RC_USE_ANOTHER_SERVER = 156, /* CONNACK, DISCONNECT */ + MQTT_RC_SERVER_MOVED = 157, /* CONNACK, DISCONNECT */ + MQTT_RC_SHARED_SUBS_NOT_SUPPORTED = 158, /* SUBACK, DISCONNECT */ + MQTT_RC_CONNECTION_RATE_EXCEEDED = 159, /* CONNACK, DISCONNECT */ + MQTT_RC_MAXIMUM_CONNECT_TIME = 160, /* DISCONNECT */ + MQTT_RC_SUBSCRIPTION_IDS_NOT_SUPPORTED = 161, /* SUBACK, DISCONNECT */ + MQTT_RC_WILDCARD_SUBS_NOT_SUPPORTED = 162, /* SUBACK, DISCONNECT */ }; enum mqtt5_property { - PROP_PAYLOAD_FORMAT_INDICATOR = 1, /* Byte : PUBLISH, Will Properties */ - PROP_MESSAGE_EXPIRY_INTERVAL = 2, /* 4 byte int : PUBLISH, Will Properties */ - PROP_CONTENT_TYPE = 3, /* UTF-8 string : PUBLISH, Will Properties */ - PROP_RESPONSE_TOPIC = 8, /* UTF-8 string : PUBLISH, Will Properties */ - PROP_CORRELATION_DATA = 9, /* Binary Data : PUBLISH, Will Properties */ - PROP_SUBSCRIPTION_IDENTIFIER = 11, /* Variable byte int : PUBLISH, SUBSCRIBE */ - PROP_SESSION_EXPIRY_INTERVAL = 17, /* 4 byte int : CONNECT, CONNACK, DISCONNECT */ - PROP_ASSIGNED_CLIENT_IDENTIFIER = 18, /* UTF-8 string : CONNACK */ - PROP_SERVER_KEEP_ALIVE = 19, /* 2 byte int : CONNACK */ - PROP_AUTHENTICATION_METHOD = 21, /* UTF-8 string : CONNECT, CONNACK, AUTH */ - PROP_AUTHENTICATION_DATA = 22, /* Binary Data : CONNECT, CONNACK, AUTH */ - PROP_REQUEST_PROBLEM_INFO = 23, /* Byte : CONNECT */ - PROP_WILL_DELAY_INTERVAL = 24, /* 4 byte int : Will properties */ - PROP_REQUEST_RESPONSE_INFO = 25, /* Byte : CONNECT */ - PROP_RESPONSE_INFO = 26, /* UTF-8 string : CONNACK */ - PROP_SERVER_REFERENCE = 28, /* UTF-8 string : CONNACK, DISCONNECT */ - PROP_REASON_STRING = 31, /* UTF-8 string : All except Will properties */ - PROP_RECEIVE_MAXIMUM = 33, /* 2 byte int : CONNECT, CONNACK */ - PROP_TOPIC_ALIAS_MAXIMUM = 34, /* 2 byte int : CONNECT, CONNACK */ - PROP_TOPIC_ALIAS = 35, /* 2 byte int : PUBLISH */ - PROP_MAXIMUM_QOS = 36, /* Byte : CONNACK */ - PROP_RETAIN_AVAILABLE = 37, /* Byte : CONNACK */ - PROP_USER_PROPERTY = 38, /* UTF-8 string pair : All */ - PROP_MAXIMUM_PACKET_SIZE = 39, /* 4 byte int : CONNECT, CONNACK */ - PROP_WILDCARD_SUB_AVAILABLE = 40, /* Byte : CONNACK */ - PROP_SUBSCRIPTION_ID_AVAILABLE = 41, /* Byte : CONNACK */ - PROP_SHARED_SUB_AVAILABLE = 42, /* Byte : CONNACK */ + MQTT_PROP_PAYLOAD_FORMAT_INDICATOR = 1, /* Byte : PUBLISH, Will Properties */ + MQTT_PROP_MESSAGE_EXPIRY_INTERVAL = 2, /* 4 byte int : PUBLISH, Will Properties */ + MQTT_PROP_CONTENT_TYPE = 3, /* UTF-8 string : PUBLISH, Will Properties */ + MQTT_PROP_RESPONSE_TOPIC = 8, /* UTF-8 string : PUBLISH, Will Properties */ + MQTT_PROP_CORRELATION_DATA = 9, /* Binary Data : PUBLISH, Will Properties */ + MQTT_PROP_SUBSCRIPTION_IDENTIFIER = 11, /* Variable byte int : PUBLISH, SUBSCRIBE */ + MQTT_PROP_SESSION_EXPIRY_INTERVAL = 17, /* 4 byte int : CONNECT, CONNACK, DISCONNECT */ + MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER = 18, /* UTF-8 string : CONNACK */ + MQTT_PROP_SERVER_KEEP_ALIVE = 19, /* 2 byte int : CONNACK */ + MQTT_PROP_AUTHENTICATION_METHOD = 21, /* UTF-8 string : CONNECT, CONNACK, AUTH */ + MQTT_PROP_AUTHENTICATION_DATA = 22, /* Binary Data : CONNECT, CONNACK, AUTH */ + MQTT_PROP_REQUEST_PROBLEM_INFORMATION = 23, /* Byte : CONNECT */ + MQTT_PROP_WILL_DELAY_INTERVAL = 24, /* 4 byte int : Will properties */ + MQTT_PROP_REQUEST_RESPONSE_INFORMATION = 25,/* Byte : CONNECT */ + MQTT_PROP_RESPONSE_INFORMATION = 26, /* UTF-8 string : CONNACK */ + MQTT_PROP_SERVER_REFERENCE = 28, /* UTF-8 string : CONNACK, DISCONNECT */ + MQTT_PROP_REASON_STRING = 31, /* UTF-8 string : All except Will properties */ + MQTT_PROP_RECEIVE_MAXIMUM = 33, /* 2 byte int : CONNECT, CONNACK */ + MQTT_PROP_TOPIC_ALIAS_MAXIMUM = 34, /* 2 byte int : CONNECT, CONNACK */ + MQTT_PROP_TOPIC_ALIAS = 35, /* 2 byte int : PUBLISH */ + MQTT_PROP_MAXIMUM_QOS = 36, /* Byte : CONNACK */ + MQTT_PROP_RETAIN_AVAILABLE = 37, /* Byte : CONNACK */ + MQTT_PROP_USER_PROPERTY = 38, /* UTF-8 string pair : All */ + MQTT_PROP_MAXIMUM_PACKET_SIZE = 39, /* 4 byte int : CONNECT, CONNACK */ + MQTT_PROP_WILDCARD_SUB_AVAILABLE = 40, /* Byte : CONNACK */ + MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE = 41, /* Byte : CONNACK */ + MQTT_PROP_SHARED_SUB_AVAILABLE = 42, /* Byte : CONNACK */ }; #define MQTT_MAX_PAYLOAD 268435455 diff --git a/lib/packet_mosq.c b/lib/packet_mosq.c index e7ffe0b459..1994df252c 100644 --- a/lib/packet_mosq.c +++ b/lib/packet_mosq.c @@ -207,7 +207,7 @@ int packet__write(struct mosquitto *mosq) } G_MSGS_SENT_INC(1); - if(((packet->command)&0xF6) == PUBLISH){ + if(((packet->command)&0xF6) == CMD_PUBLISH){ G_PUB_MSGS_SENT_INC(1); #ifndef WITH_BROKER pthread_mutex_lock(&mosq->callback_mutex); @@ -218,7 +218,7 @@ int packet__write(struct mosquitto *mosq) mosq->in_callback = false; } pthread_mutex_unlock(&mosq->callback_mutex); - }else if(((packet->command)&0xF0) == DISCONNECT){ + }else if(((packet->command)&0xF0) == CMD_DISCONNECT){ /* FIXME what cleanup needs doing here? * incoming/outgoing messages? */ net__socket_close(mosq); @@ -316,7 +316,7 @@ int packet__read(struct mosquitto *mosq) #ifdef WITH_BROKER G_BYTES_RECEIVED_INC(1); /* Clients must send CONNECT as their first command. */ - if(!(mosq->bridge) && mosq->state == mosq_cs_new && (byte&0xF0) != CONNECT) return MOSQ_ERR_PROTOCOL; + if(!(mosq->bridge) && mosq->state == mosq_cs_new && (byte&0xF0) != CMD_CONNECT) return MOSQ_ERR_PROTOCOL; #endif }else{ if(read_length == 0) return MOSQ_ERR_CONN_LOST; /* EOF */ @@ -421,7 +421,7 @@ int packet__read(struct mosquitto *mosq) mosq->in_packet.pos = 0; #ifdef WITH_BROKER G_MSGS_RECEIVED_INC(1); - if(((mosq->in_packet.command)&0xF5) == PUBLISH){ + if(((mosq->in_packet.command)&0xF5) == CMD_PUBLISH){ G_PUB_MSGS_RECEIVED_INC(1); } rc = handle__packet(db, mosq); diff --git a/lib/property_mosq.c b/lib/property_mosq.c index 3c932cea14..a970ef9f7f 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -50,54 +50,54 @@ int property__read(struct mosquitto__packet *packet, int32_t *len, struct mqtt5_ property->identifier = property_identifier; switch(property_identifier){ - case PROP_PAYLOAD_FORMAT_INDICATOR: - case PROP_REQUEST_PROBLEM_INFO: - case PROP_REQUEST_RESPONSE_INFO: - case PROP_MAXIMUM_QOS: - case PROP_RETAIN_AVAILABLE: - case PROP_WILDCARD_SUB_AVAILABLE: - case PROP_SUBSCRIPTION_ID_AVAILABLE: - case PROP_SHARED_SUB_AVAILABLE: + case MQTT_PROP_PAYLOAD_FORMAT_INDICATOR: + case MQTT_PROP_REQUEST_PROBLEM_INFORMATION: + case MQTT_PROP_REQUEST_RESPONSE_INFORMATION: + case MQTT_PROP_MAXIMUM_QOS: + case MQTT_PROP_RETAIN_AVAILABLE: + case MQTT_PROP_WILDCARD_SUB_AVAILABLE: + case MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE: + case MQTT_PROP_SHARED_SUB_AVAILABLE: rc = packet__read_byte(packet, &byte); if(rc) return rc; *len -= 1; /* byte */ property->value.i8 = byte; break; - case PROP_SERVER_KEEP_ALIVE: - case PROP_RECEIVE_MAXIMUM: - case PROP_TOPIC_ALIAS_MAXIMUM: - case PROP_TOPIC_ALIAS: + case MQTT_PROP_SERVER_KEEP_ALIVE: + case MQTT_PROP_RECEIVE_MAXIMUM: + case MQTT_PROP_TOPIC_ALIAS_MAXIMUM: + case MQTT_PROP_TOPIC_ALIAS: rc = packet__read_uint16(packet, &uint16); if(rc) return rc; *len -= 2; /* uint16 */ property->value.i16 = uint16; break; - case PROP_MESSAGE_EXPIRY_INTERVAL: - case PROP_SESSION_EXPIRY_INTERVAL: - case PROP_WILL_DELAY_INTERVAL: - case PROP_MAXIMUM_PACKET_SIZE: + case MQTT_PROP_MESSAGE_EXPIRY_INTERVAL: + case MQTT_PROP_SESSION_EXPIRY_INTERVAL: + case MQTT_PROP_WILL_DELAY_INTERVAL: + case MQTT_PROP_MAXIMUM_PACKET_SIZE: rc = packet__read_uint32(packet, &uint32); if(rc) return rc; *len -= 4; /* uint32 */ property->value.i32 = uint32; break; - case PROP_SUBSCRIPTION_IDENTIFIER: + case MQTT_PROP_SUBSCRIPTION_IDENTIFIER: rc = packet__read_varint(packet, &varint, &byte_count); if(rc) return rc; *len -= byte_count; property->value.varint = varint; break; - case PROP_CONTENT_TYPE: - case PROP_RESPONSE_TOPIC: - case PROP_ASSIGNED_CLIENT_IDENTIFIER: - case PROP_AUTHENTICATION_METHOD: - case PROP_RESPONSE_INFO: - case PROP_SERVER_REFERENCE: - case PROP_REASON_STRING: + case MQTT_PROP_CONTENT_TYPE: + case MQTT_PROP_RESPONSE_TOPIC: + case MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER: + case MQTT_PROP_AUTHENTICATION_METHOD: + case MQTT_PROP_RESPONSE_INFORMATION: + case MQTT_PROP_SERVER_REFERENCE: + case MQTT_PROP_REASON_STRING: rc = packet__read_string(packet, &str1, &slen1); if(rc) return rc; *len = (*len) - 2 - slen1; /* uint16, string len */ @@ -105,8 +105,8 @@ int property__read(struct mosquitto__packet *packet, int32_t *len, struct mqtt5_ property->value.s.len = slen1; break; - case PROP_AUTHENTICATION_DATA: - case PROP_CORRELATION_DATA: + case MQTT_PROP_AUTHENTICATION_DATA: + case MQTT_PROP_CORRELATION_DATA: rc = packet__read_binary(packet, (uint8_t **)&str1, &slen1); if(rc) return rc; *len = (*len) - 2 - slen1; /* uint16, binary len */ @@ -114,7 +114,7 @@ int property__read(struct mosquitto__packet *packet, int32_t *len, struct mqtt5_ property->value.bin.len = slen1; break; - case PROP_USER_PROPERTY: + case MQTT_PROP_USER_PROPERTY: rc = packet__read_string(packet, &str1, &slen1); if(rc) return rc; *len = (*len) - 2 - slen1; /* uint16, string len */ @@ -173,25 +173,25 @@ int property__read_all(int command, struct mosquitto__packet *packet, struct mqt tail = p; /* Validity checks */ - if(p->identifier == PROP_REQUEST_PROBLEM_INFO - || p->identifier == PROP_REQUEST_RESPONSE_INFO - || p->identifier == PROP_MAXIMUM_QOS - || p->identifier == PROP_RETAIN_AVAILABLE - || p->identifier == PROP_WILDCARD_SUB_AVAILABLE - || p->identifier == PROP_SUBSCRIPTION_ID_AVAILABLE - || p->identifier == PROP_SHARED_SUB_AVAILABLE){ + if(p->identifier == MQTT_PROP_REQUEST_PROBLEM_INFORMATION + || p->identifier == MQTT_PROP_REQUEST_RESPONSE_INFORMATION + || p->identifier == MQTT_PROP_MAXIMUM_QOS + || p->identifier == MQTT_PROP_RETAIN_AVAILABLE + || p->identifier == MQTT_PROP_WILDCARD_SUB_AVAILABLE + || p->identifier == MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE + || p->identifier == MQTT_PROP_SHARED_SUB_AVAILABLE){ if(p->value.i8 > 1){ mosquitto_property_free_all(properties); return MOSQ_ERR_PROTOCOL; } - }else if(p->identifier == PROP_MAXIMUM_PACKET_SIZE){ + }else if(p->identifier == MQTT_PROP_MAXIMUM_PACKET_SIZE){ if( p->value.i32 == 0){ mosquitto_property_free_all(properties); return MOSQ_ERR_PROTOCOL; } - }else if(p->identifier == PROP_RECEIVE_MAXIMUM - || p->identifier == PROP_TOPIC_ALIAS){ + }else if(p->identifier == MQTT_PROP_RECEIVE_MAXIMUM + || p->identifier == MQTT_PROP_TOPIC_ALIAS){ if(p->value.i16 == 0){ mosquitto_property_free_all(properties); @@ -206,7 +206,7 @@ int property__read_all(int command, struct mosquitto__packet *packet, struct mqt tail = current->next; while(tail){ if(current->identifier == tail->identifier - && current->identifier != PROP_USER_PROPERTY){ + && current->identifier != MQTT_PROP_USER_PROPERTY){ mosquitto_property_free_all(properties); return MOSQ_ERR_PROTOCOL; @@ -230,43 +230,43 @@ void property__free(struct mqtt5__property **property) if(!property || !(*property)) return; switch((*property)->identifier){ - case PROP_CONTENT_TYPE: - case PROP_RESPONSE_TOPIC: - case PROP_ASSIGNED_CLIENT_IDENTIFIER: - case PROP_AUTHENTICATION_METHOD: - case PROP_RESPONSE_INFO: - case PROP_SERVER_REFERENCE: - case PROP_REASON_STRING: + case MQTT_PROP_CONTENT_TYPE: + case MQTT_PROP_RESPONSE_TOPIC: + case MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER: + case MQTT_PROP_AUTHENTICATION_METHOD: + case MQTT_PROP_RESPONSE_INFORMATION: + case MQTT_PROP_SERVER_REFERENCE: + case MQTT_PROP_REASON_STRING: mosquitto__free((*property)->value.s.v); break; - case PROP_AUTHENTICATION_DATA: - case PROP_CORRELATION_DATA: + case MQTT_PROP_AUTHENTICATION_DATA: + case MQTT_PROP_CORRELATION_DATA: mosquitto__free((*property)->value.bin.v); break; - case PROP_USER_PROPERTY: + case MQTT_PROP_USER_PROPERTY: mosquitto__free((*property)->name.v); mosquitto__free((*property)->value.s.v); break; - case PROP_PAYLOAD_FORMAT_INDICATOR: - case PROP_MESSAGE_EXPIRY_INTERVAL: - case PROP_SUBSCRIPTION_IDENTIFIER: - case PROP_SESSION_EXPIRY_INTERVAL: - case PROP_SERVER_KEEP_ALIVE: - case PROP_REQUEST_PROBLEM_INFO: - case PROP_WILL_DELAY_INTERVAL: - case PROP_REQUEST_RESPONSE_INFO: - case PROP_RECEIVE_MAXIMUM: - case PROP_TOPIC_ALIAS_MAXIMUM: - case PROP_TOPIC_ALIAS: - case PROP_MAXIMUM_QOS: - case PROP_RETAIN_AVAILABLE: - case PROP_MAXIMUM_PACKET_SIZE: - case PROP_WILDCARD_SUB_AVAILABLE: - case PROP_SUBSCRIPTION_ID_AVAILABLE: - case PROP_SHARED_SUB_AVAILABLE: + case MQTT_PROP_PAYLOAD_FORMAT_INDICATOR: + case MQTT_PROP_MESSAGE_EXPIRY_INTERVAL: + case MQTT_PROP_SUBSCRIPTION_IDENTIFIER: + case MQTT_PROP_SESSION_EXPIRY_INTERVAL: + case MQTT_PROP_SERVER_KEEP_ALIVE: + case MQTT_PROP_REQUEST_PROBLEM_INFORMATION: + case MQTT_PROP_WILL_DELAY_INTERVAL: + case MQTT_PROP_REQUEST_RESPONSE_INFORMATION: + case MQTT_PROP_RECEIVE_MAXIMUM: + case MQTT_PROP_TOPIC_ALIAS_MAXIMUM: + case MQTT_PROP_TOPIC_ALIAS: + case MQTT_PROP_MAXIMUM_QOS: + case MQTT_PROP_RETAIN_AVAILABLE: + case MQTT_PROP_MAXIMUM_PACKET_SIZE: + case MQTT_PROP_WILDCARD_SUB_AVAILABLE: + case MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE: + case MQTT_PROP_SHARED_SUB_AVAILABLE: /* Nothing to free */ break; } @@ -295,29 +295,29 @@ int property__get_length(struct mqtt5__property *property) if(!property) return 0; switch(property->identifier){ - case PROP_PAYLOAD_FORMAT_INDICATOR: - case PROP_REQUEST_PROBLEM_INFO: - case PROP_REQUEST_RESPONSE_INFO: - case PROP_MAXIMUM_QOS: - case PROP_RETAIN_AVAILABLE: - case PROP_WILDCARD_SUB_AVAILABLE: - case PROP_SUBSCRIPTION_ID_AVAILABLE: - case PROP_SHARED_SUB_AVAILABLE: + case MQTT_PROP_PAYLOAD_FORMAT_INDICATOR: + case MQTT_PROP_REQUEST_PROBLEM_INFORMATION: + case MQTT_PROP_REQUEST_RESPONSE_INFORMATION: + case MQTT_PROP_MAXIMUM_QOS: + case MQTT_PROP_RETAIN_AVAILABLE: + case MQTT_PROP_WILDCARD_SUB_AVAILABLE: + case MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE: + case MQTT_PROP_SHARED_SUB_AVAILABLE: return 2; /* 1 (identifier) + 1 byte */ - case PROP_SERVER_KEEP_ALIVE: - case PROP_RECEIVE_MAXIMUM: - case PROP_TOPIC_ALIAS_MAXIMUM: - case PROP_TOPIC_ALIAS: + case MQTT_PROP_SERVER_KEEP_ALIVE: + case MQTT_PROP_RECEIVE_MAXIMUM: + case MQTT_PROP_TOPIC_ALIAS_MAXIMUM: + case MQTT_PROP_TOPIC_ALIAS: return 3; /* 1 (identifier) + 2 bytes */ - case PROP_MESSAGE_EXPIRY_INTERVAL: - case PROP_WILL_DELAY_INTERVAL: - case PROP_MAXIMUM_PACKET_SIZE: - case PROP_SESSION_EXPIRY_INTERVAL: + case MQTT_PROP_MESSAGE_EXPIRY_INTERVAL: + case MQTT_PROP_WILL_DELAY_INTERVAL: + case MQTT_PROP_MAXIMUM_PACKET_SIZE: + case MQTT_PROP_SESSION_EXPIRY_INTERVAL: return 5; /* 1 (identifier) + 5 bytes */ - case PROP_SUBSCRIPTION_IDENTIFIER: + case MQTT_PROP_SUBSCRIPTION_IDENTIFIER: if(property->value.varint < 128){ return 2; }else if(property->value.varint < 16384){ @@ -330,20 +330,20 @@ int property__get_length(struct mqtt5__property *property) return 0; } - case PROP_CORRELATION_DATA: - case PROP_AUTHENTICATION_DATA: + case MQTT_PROP_CORRELATION_DATA: + case MQTT_PROP_AUTHENTICATION_DATA: return 3 + property->value.bin.len; /* 1 + 2 bytes (len) + X bytes (payload) */ - case PROP_CONTENT_TYPE: - case PROP_RESPONSE_TOPIC: - case PROP_ASSIGNED_CLIENT_IDENTIFIER: - case PROP_AUTHENTICATION_METHOD: - case PROP_RESPONSE_INFO: - case PROP_SERVER_REFERENCE: - case PROP_REASON_STRING: + case MQTT_PROP_CONTENT_TYPE: + case MQTT_PROP_RESPONSE_TOPIC: + case MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER: + case MQTT_PROP_AUTHENTICATION_METHOD: + case MQTT_PROP_RESPONSE_INFORMATION: + case MQTT_PROP_SERVER_REFERENCE: + case MQTT_PROP_REASON_STRING: return 3 + property->value.s.len; /* 1 + 2 bytes (len) + X bytes (string) */ - case PROP_USER_PROPERTY: + case MQTT_PROP_USER_PROPERTY: return 5 + property->value.s.len + property->name.len; /* 1 + 2*(2 bytes (len) + X bytes (string))*/ default: @@ -375,50 +375,50 @@ int property__write(struct mosquitto__packet *packet, struct mqtt5__property *pr if(rc) return rc; switch(property->identifier){ - case PROP_PAYLOAD_FORMAT_INDICATOR: - case PROP_REQUEST_PROBLEM_INFO: - case PROP_REQUEST_RESPONSE_INFO: - case PROP_MAXIMUM_QOS: - case PROP_RETAIN_AVAILABLE: - case PROP_WILDCARD_SUB_AVAILABLE: - case PROP_SUBSCRIPTION_ID_AVAILABLE: - case PROP_SHARED_SUB_AVAILABLE: + case MQTT_PROP_PAYLOAD_FORMAT_INDICATOR: + case MQTT_PROP_REQUEST_PROBLEM_INFORMATION: + case MQTT_PROP_REQUEST_RESPONSE_INFORMATION: + case MQTT_PROP_MAXIMUM_QOS: + case MQTT_PROP_RETAIN_AVAILABLE: + case MQTT_PROP_WILDCARD_SUB_AVAILABLE: + case MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE: + case MQTT_PROP_SHARED_SUB_AVAILABLE: packet__write_byte(packet, property->value.i8); break; - case PROP_SERVER_KEEP_ALIVE: - case PROP_RECEIVE_MAXIMUM: - case PROP_TOPIC_ALIAS_MAXIMUM: - case PROP_TOPIC_ALIAS: + case MQTT_PROP_SERVER_KEEP_ALIVE: + case MQTT_PROP_RECEIVE_MAXIMUM: + case MQTT_PROP_TOPIC_ALIAS_MAXIMUM: + case MQTT_PROP_TOPIC_ALIAS: packet__write_uint16(packet, property->value.i16); break; - case PROP_MESSAGE_EXPIRY_INTERVAL: - case PROP_SESSION_EXPIRY_INTERVAL: - case PROP_WILL_DELAY_INTERVAL: - case PROP_MAXIMUM_PACKET_SIZE: + case MQTT_PROP_MESSAGE_EXPIRY_INTERVAL: + case MQTT_PROP_SESSION_EXPIRY_INTERVAL: + case MQTT_PROP_WILL_DELAY_INTERVAL: + case MQTT_PROP_MAXIMUM_PACKET_SIZE: packet__write_uint32(packet, property->value.i32); break; - case PROP_SUBSCRIPTION_IDENTIFIER: + case MQTT_PROP_SUBSCRIPTION_IDENTIFIER: return packet__write_varint(packet, property->value.varint); - case PROP_CONTENT_TYPE: - case PROP_RESPONSE_TOPIC: - case PROP_ASSIGNED_CLIENT_IDENTIFIER: - case PROP_AUTHENTICATION_METHOD: - case PROP_RESPONSE_INFO: - case PROP_SERVER_REFERENCE: - case PROP_REASON_STRING: + case MQTT_PROP_CONTENT_TYPE: + case MQTT_PROP_RESPONSE_TOPIC: + case MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER: + case MQTT_PROP_AUTHENTICATION_METHOD: + case MQTT_PROP_RESPONSE_INFORMATION: + case MQTT_PROP_SERVER_REFERENCE: + case MQTT_PROP_REASON_STRING: packet__write_string(packet, property->value.s.v, property->value.s.len); break; - case PROP_AUTHENTICATION_DATA: - case PROP_CORRELATION_DATA: + case MQTT_PROP_AUTHENTICATION_DATA: + case MQTT_PROP_CORRELATION_DATA: packet__write_uint16(packet, property->value.bin.len); packet__write_bytes(packet, property->value.bin.v, property->value.bin.len); - case PROP_USER_PROPERTY: + case MQTT_PROP_USER_PROPERTY: packet__write_string(packet, property->name.v, property->name.len); packet__write_string(packet, property->value.s.v, property->value.s.len); break; @@ -458,88 +458,88 @@ static int property__command_check(int command, struct mqtt5__property *properti p = properties; while(p){ switch(p->identifier){ - case PROP_PAYLOAD_FORMAT_INDICATOR: - case PROP_MESSAGE_EXPIRY_INTERVAL: - case PROP_CONTENT_TYPE: - case PROP_RESPONSE_TOPIC: - case PROP_CORRELATION_DATA: - if(command != PUBLISH && command != 0){ + case MQTT_PROP_PAYLOAD_FORMAT_INDICATOR: + case MQTT_PROP_MESSAGE_EXPIRY_INTERVAL: + case MQTT_PROP_CONTENT_TYPE: + case MQTT_PROP_RESPONSE_TOPIC: + case MQTT_PROP_CORRELATION_DATA: + if(command != CMD_PUBLISH && command != CMD_WILL){ return MOSQ_ERR_PROTOCOL; } break; - case PROP_SUBSCRIPTION_IDENTIFIER: - if(command != PUBLISH && command != SUBSCRIBE){ + case MQTT_PROP_SUBSCRIPTION_IDENTIFIER: + if(command != CMD_PUBLISH && command != CMD_SUBSCRIBE){ return MOSQ_ERR_PROTOCOL; } break; - case PROP_SESSION_EXPIRY_INTERVAL: - if(command != CONNECT && command != CONNACK && command != DISCONNECT){ + case MQTT_PROP_SESSION_EXPIRY_INTERVAL: + if(command != CMD_CONNECT && command != CMD_CONNACK && command != CMD_DISCONNECT){ return MOSQ_ERR_PROTOCOL; } break; - case PROP_AUTHENTICATION_METHOD: - case PROP_AUTHENTICATION_DATA: - if(command != CONNECT && command != CONNACK && command != AUTH){ + case MQTT_PROP_AUTHENTICATION_METHOD: + case MQTT_PROP_AUTHENTICATION_DATA: + if(command != CMD_CONNECT && command != CMD_CONNACK && command != CMD_AUTH){ return MOSQ_ERR_PROTOCOL; } break; - case PROP_ASSIGNED_CLIENT_IDENTIFIER: - case PROP_SERVER_KEEP_ALIVE: - case PROP_RESPONSE_INFO: - case PROP_MAXIMUM_QOS: - case PROP_RETAIN_AVAILABLE: - case PROP_WILDCARD_SUB_AVAILABLE: - case PROP_SUBSCRIPTION_ID_AVAILABLE: - case PROP_SHARED_SUB_AVAILABLE: - if(command != CONNACK){ + case MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER: + case MQTT_PROP_SERVER_KEEP_ALIVE: + case MQTT_PROP_RESPONSE_INFORMATION: + case MQTT_PROP_MAXIMUM_QOS: + case MQTT_PROP_RETAIN_AVAILABLE: + case MQTT_PROP_WILDCARD_SUB_AVAILABLE: + case MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE: + case MQTT_PROP_SHARED_SUB_AVAILABLE: + if(command != CMD_CONNACK){ return MOSQ_ERR_PROTOCOL; } break; - case PROP_WILL_DELAY_INTERVAL: - if(command != 0){ + case MQTT_PROP_WILL_DELAY_INTERVAL: + if(command != CMD_WILL){ return MOSQ_ERR_PROTOCOL; } break; - case PROP_REQUEST_PROBLEM_INFO: - case PROP_REQUEST_RESPONSE_INFO: - if(command != CONNECT){ + case MQTT_PROP_REQUEST_PROBLEM_INFORMATION: + case MQTT_PROP_REQUEST_RESPONSE_INFORMATION: + if(command != CMD_CONNECT){ return MOSQ_ERR_PROTOCOL; } break; - case PROP_SERVER_REFERENCE: - if(command != CONNACK && command != DISCONNECT){ + case MQTT_PROP_SERVER_REFERENCE: + if(command != CMD_CONNACK && command != CMD_DISCONNECT){ return MOSQ_ERR_PROTOCOL; } break; - case PROP_REASON_STRING: - if(command == CONNECT || command == PUBLISH || command == SUBSCRIBE || command == UNSUBSCRIBE){ + case MQTT_PROP_REASON_STRING: + if(command == CMD_CONNECT || command == CMD_PUBLISH || command == CMD_SUBSCRIBE || command == CMD_UNSUBSCRIBE){ return MOSQ_ERR_PROTOCOL; } break; - case PROP_RECEIVE_MAXIMUM: - case PROP_TOPIC_ALIAS_MAXIMUM: - case PROP_MAXIMUM_PACKET_SIZE: - if(command != CONNECT && command != CONNACK){ + case MQTT_PROP_RECEIVE_MAXIMUM: + case MQTT_PROP_TOPIC_ALIAS_MAXIMUM: + case MQTT_PROP_MAXIMUM_PACKET_SIZE: + if(command != CMD_CONNECT && command != CMD_CONNACK){ return MOSQ_ERR_PROTOCOL; } break; - case PROP_TOPIC_ALIAS: - if(command != PUBLISH){ + case MQTT_PROP_TOPIC_ALIAS: + if(command != CMD_PUBLISH){ return MOSQ_ERR_PROTOCOL; } break; - case PROP_USER_PROPERTY: + case MQTT_PROP_USER_PROPERTY: break; default: diff --git a/lib/read_handle.c b/lib/read_handle.c index 011c083c3b..1da41aa79a 100644 --- a/lib/read_handle.c +++ b/lib/read_handle.c @@ -37,27 +37,27 @@ int handle__packet(struct mosquitto *mosq) assert(mosq); switch((mosq->in_packet.command)&0xF0){ - case PINGREQ: + case CMD_PINGREQ: return handle__pingreq(mosq); - case PINGRESP: + case CMD_PINGRESP: return handle__pingresp(mosq); - case PUBACK: + case CMD_PUBACK: return handle__pubackcomp(mosq, "PUBACK"); - case PUBCOMP: + case CMD_PUBCOMP: return handle__pubackcomp(mosq, "PUBCOMP"); - case PUBLISH: + case CMD_PUBLISH: return handle__publish(mosq); - case PUBREC: + case CMD_PUBREC: return handle__pubrec(mosq); - case PUBREL: + case CMD_PUBREL: return handle__pubrel(NULL, mosq); - case CONNACK: + case CMD_CONNACK: return handle__connack(mosq); - case SUBACK: + case CMD_SUBACK: return handle__suback(mosq); - case UNSUBACK: + case CMD_UNSUBACK: return handle__unsuback(mosq); - case AUTH: + case CMD_AUTH: return handle__auth(mosq); default: /* If we don't recognise the command, return an error straight away. */ diff --git a/lib/send_connect.c b/lib/send_connect.c index 4bc7598944..ee59fc0213 100644 --- a/lib/send_connect.c +++ b/lib/send_connect.c @@ -101,7 +101,7 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session } } - packet->command = CONNECT; + packet->command = CMD_CONNECT; packet->remaining_length = headerlen + payloadlen; rc = packet__alloc(packet); if(rc){ diff --git a/lib/send_disconnect.c b/lib/send_disconnect.c index 61c979a904..1258f5c08c 100644 --- a/lib/send_disconnect.c +++ b/lib/send_disconnect.c @@ -51,7 +51,7 @@ int send__disconnect(struct mosquitto *mosq) packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet)); if(!packet) return MOSQ_ERR_NOMEM; - packet->command = DISCONNECT; + packet->command = CMD_DISCONNECT; if(mosq->protocol == mosq_p_mqtt5){ proplen = property__get_length_all(properties); varbytes = packet__varint_bytes(proplen); diff --git a/lib/send_mosq.c b/lib/send_mosq.c index f944c6a929..a29d091934 100644 --- a/lib/send_mosq.c +++ b/lib/send_mosq.c @@ -48,7 +48,7 @@ int send__pingreq(struct mosquitto *mosq) #else log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PINGREQ", mosq->id); #endif - rc = send__simple_command(mosq, PINGREQ); + rc = send__simple_command(mosq, CMD_PINGREQ); if(rc == MOSQ_ERR_SUCCESS){ mosq->ping_t = mosquitto_time(); } @@ -62,7 +62,7 @@ int send__pingresp(struct mosquitto *mosq) #else if(mosq) log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PINGRESP", mosq->id); #endif - return send__simple_command(mosq, PINGRESP); + return send__simple_command(mosq, CMD_PINGRESP); } int send__puback(struct mosquitto *mosq, uint16_t mid) @@ -73,7 +73,7 @@ int send__puback(struct mosquitto *mosq, uint16_t mid) if(mosq) log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBACK (Mid: %d)", mosq->id, mid); #endif /* We don't use Reason String or User Property yet. */ - return send__command_with_mid(mosq, PUBACK, mid, false, NULL); + return send__command_with_mid(mosq, CMD_PUBACK, mid, false, NULL); } int send__pubcomp(struct mosquitto *mosq, uint16_t mid) @@ -84,7 +84,7 @@ int send__pubcomp(struct mosquitto *mosq, uint16_t mid) if(mosq) log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBCOMP (Mid: %d)", mosq->id, mid); #endif /* We don't use Reason String or User Property yet. */ - return send__command_with_mid(mosq, PUBCOMP, mid, false, NULL); + return send__command_with_mid(mosq, CMD_PUBCOMP, mid, false, NULL); } @@ -96,7 +96,7 @@ int send__pubrec(struct mosquitto *mosq, uint16_t mid) if(mosq) log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBREC (Mid: %d)", mosq->id, mid); #endif /* We don't use Reason String or User Property yet. */ - return send__command_with_mid(mosq, PUBREC, mid, false, NULL); + return send__command_with_mid(mosq, CMD_PUBREC, mid, false, NULL); } int send__pubrel(struct mosquitto *mosq, uint16_t mid) @@ -107,7 +107,7 @@ int send__pubrel(struct mosquitto *mosq, uint16_t mid) if(mosq) log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBREL (Mid: %d)", mosq->id, mid); #endif /* We don't use Reason String or User Property yet. */ - return send__command_with_mid(mosq, PUBREL|2, mid, false, NULL); + return send__command_with_mid(mosq, CMD_PUBREL|2, mid, false, NULL); } /* For PUBACK, PUBCOMP, PUBREC, and PUBREL */ diff --git a/lib/send_publish.c b/lib/send_publish.c index 4f54acbac6..9ac9d8d238 100644 --- a/lib/send_publish.c +++ b/lib/send_publish.c @@ -155,7 +155,7 @@ int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, if(!packet) return MOSQ_ERR_NOMEM; packet->mid = mid; - packet->command = PUBLISH | ((dup&0x1)<<3) | (qos<<1) | retain; + packet->command = CMD_PUBLISH | ((dup&0x1)<<3) | (qos<<1) | retain; packet->remaining_length = packetlen; rc = packet__alloc(packet); if(rc){ diff --git a/lib/send_subscribe.c b/lib/send_subscribe.c index c950b12a1c..498919ff77 100644 --- a/lib/send_subscribe.c +++ b/lib/send_subscribe.c @@ -59,7 +59,7 @@ int send__subscribe(struct mosquitto *mosq, int *mid, int topic_count, const cha packetlen += 2+strlen(topic[i]) + 1; } - packet->command = SUBSCRIBE | (1<<1); + packet->command = CMD_SUBSCRIBE | (1<<1); packet->remaining_length = packetlen; rc = packet__alloc(packet); if(rc){ diff --git a/lib/send_unsubscribe.c b/lib/send_unsubscribe.c index db59fc9874..105a7d793d 100644 --- a/lib/send_unsubscribe.c +++ b/lib/send_unsubscribe.c @@ -55,7 +55,7 @@ int send__unsubscribe(struct mosquitto *mosq, int *mid, const char *topic) packetlen += proplen + varbytes; } - packet->command = UNSUBSCRIBE | (1<<1); + packet->command = CMD_UNSUBSCRIBE | (1<<1); packet->remaining_length = packetlen; rc = packet__alloc(packet); if(rc){ diff --git a/src/handle_auth.c b/src/handle_auth.c index 083e6406f4..529f4e65c2 100644 --- a/src/handle_auth.c +++ b/src/handle_auth.c @@ -40,7 +40,7 @@ int handle__auth(struct mosquitto_db *db, struct mosquitto *context) if(packet__read_byte(&context->in_packet, &reason_code)) return 1; - rc = property__read_all(AUTH, &context->in_packet, &properties); + rc = property__read_all(CMD_AUTH, &context->in_packet, &properties); if(rc) return rc; mosquitto_property_free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ diff --git a/src/handle_connack.c b/src/handle_connack.c index 4fb76c4cbe..ca3321697a 100644 --- a/src/handle_connack.c +++ b/src/handle_connack.c @@ -45,7 +45,7 @@ int handle__connack(struct mosquitto_db *db, struct mosquitto *context) if(packet__read_byte(&context->in_packet, &reason_code)) return 1; if(context->protocol == mosq_p_mqtt5){ - rc = property__read_all(CONNACK, &context->in_packet, &properties); + rc = property__read_all(CMD_CONNACK, &context->in_packet, &properties); if(rc) return rc; mosquitto_property_free_all(&properties); } diff --git a/src/handle_connect.c b/src/handle_connect.c index a60e1f9ba2..b617211fa0 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -242,7 +242,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) } if(protocol_version == PROTOCOL_VERSION_v5){ - rc = property__read_all(CONNECT, &context->in_packet, &properties); + rc = property__read_all(CMD_CONNECT, &context->in_packet, &properties); if(rc) return rc; mosquitto_property_free_all(&properties); } @@ -729,7 +729,7 @@ int handle__disconnect(struct mosquitto_db *db, struct mosquitto *context) } if(context->protocol == mosq_p_mqtt5){ - rc = property__read_all(DISCONNECT, &context->in_packet, &properties); + rc = property__read_all(CMD_DISCONNECT, &context->in_packet, &properties); if(rc) return rc; mosquitto_property_free_all(&properties); } diff --git a/src/handle_publish.c b/src/handle_publish.c index a071481d81..e190f928e5 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -141,7 +141,7 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) /* Handle properties */ if(context->protocol == mosq_p_mqtt5){ - rc = property__read_all(PUBLISH, &context->in_packet, &properties); + rc = property__read_all(CMD_PUBLISH, &context->in_packet, &properties); if(rc) return rc; p = properties; @@ -150,10 +150,10 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) msg_properties_last = NULL; while(p){ switch(p->identifier){ - case PROP_PAYLOAD_FORMAT_INDICATOR: - case PROP_CORRELATION_DATA: - case PROP_USER_PROPERTY: - case PROP_CONTENT_TYPE: + case MQTT_PROP_PAYLOAD_FORMAT_INDICATOR: + case MQTT_PROP_CORRELATION_DATA: + case MQTT_PROP_USER_PROPERTY: + case MQTT_PROP_CONTENT_TYPE: if(msg_properties){ msg_properties_last->next = p; msg_properties_last = p; @@ -172,19 +172,19 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) } break; - case PROP_TOPIC_ALIAS: + case MQTT_PROP_TOPIC_ALIAS: p = p->next; break; - case PROP_RESPONSE_TOPIC: + case MQTT_PROP_RESPONSE_TOPIC: p = p->next; break; - case PROP_MESSAGE_EXPIRY_INTERVAL: + case MQTT_PROP_MESSAGE_EXPIRY_INTERVAL: p = p->next; break; - case PROP_SUBSCRIPTION_IDENTIFIER: + case MQTT_PROP_SUBSCRIPTION_IDENTIFIER: p = p->next; break; diff --git a/src/handle_subscribe.c b/src/handle_subscribe.c index 0bd7b70205..b96ad255bd 100644 --- a/src/handle_subscribe.c +++ b/src/handle_subscribe.c @@ -53,7 +53,7 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) if(mid == 0) return MOSQ_ERR_PROTOCOL; if(context->protocol == mosq_p_mqtt5){ - rc = property__read_all(SUBSCRIBE, &context->in_packet, &properties); + rc = property__read_all(CMD_SUBSCRIBE, &context->in_packet, &properties); if(rc) return rc; mosquitto_property_free_all(&properties); } diff --git a/src/handle_unsubscribe.c b/src/handle_unsubscribe.c index c64ae66c6f..296fef1194 100644 --- a/src/handle_unsubscribe.c +++ b/src/handle_unsubscribe.c @@ -45,7 +45,7 @@ int handle__unsubscribe(struct mosquitto_db *db, struct mosquitto *context) if(mid == 0) return MOSQ_ERR_PROTOCOL; if(context->protocol == mosq_p_mqtt5){ - rc = property__read_all(UNSUBSCRIBE, &context->in_packet, &properties); + rc = property__read_all(CMD_UNSUBSCRIBE, &context->in_packet, &properties); if(rc) return rc; /* Immediately free, we don't do anything with User Property at the moment */ mosquitto_property_free_all(&properties); @@ -92,6 +92,6 @@ int handle__unsubscribe(struct mosquitto_db *db, struct mosquitto *context) log__printf(NULL, MOSQ_LOG_DEBUG, "Sending UNSUBACK to %s", context->id); /* We don't use Reason String or User Property yet. */ - return send__command_with_mid(context, UNSUBACK, mid, false, NULL); + return send__command_with_mid(context, CMD_UNSUBACK, mid, false, NULL); } diff --git a/src/read_handle.c b/src/read_handle.c index a283ca0e21..72144ce8cb 100644 --- a/src/read_handle.c +++ b/src/read_handle.c @@ -35,37 +35,37 @@ int handle__packet(struct mosquitto_db *db, struct mosquitto *context) if(!context) return MOSQ_ERR_INVAL; switch((context->in_packet.command)&0xF0){ - case PINGREQ: + case CMD_PINGREQ: return handle__pingreq(context); - case PINGRESP: + case CMD_PINGRESP: return handle__pingresp(context); - case PUBACK: + case CMD_PUBACK: return handle__pubackcomp(db, context, "PUBACK"); - case PUBCOMP: + case CMD_PUBCOMP: return handle__pubackcomp(db, context, "PUBCOMP"); - case PUBLISH: + case CMD_PUBLISH: return handle__publish(db, context); - case PUBREC: + case CMD_PUBREC: return handle__pubrec(context); - case PUBREL: + case CMD_PUBREL: return handle__pubrel(db, context); - case CONNECT: + case CMD_CONNECT: return handle__connect(db, context); - case DISCONNECT: + case CMD_DISCONNECT: return handle__disconnect(db, context); - case SUBSCRIBE: + case CMD_SUBSCRIBE: return handle__subscribe(db, context); - case UNSUBSCRIBE: + case CMD_UNSUBSCRIBE: return handle__unsubscribe(db, context); #ifdef WITH_BRIDGE - case CONNACK: + case CMD_CONNACK: return handle__connack(db, context); - case SUBACK: + case CMD_SUBACK: return handle__suback(context); - case UNSUBACK: + case CMD_UNSUBACK: return handle__unsuback(context); #endif - case AUTH: + case CMD_AUTH: return handle__auth(db, context); default: /* If we don't recognise the command, return an error straight away. */ diff --git a/src/send_connack.c b/src/send_connack.c index ba19b30511..7414298aac 100644 --- a/src/send_connack.c +++ b/src/send_connack.c @@ -41,7 +41,7 @@ int send__connack(struct mosquitto *context, int ack, int result) packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet)); if(!packet) return MOSQ_ERR_NOMEM; - packet->command = CONNACK; + packet->command = CMD_CONNACK; packet->remaining_length = 2; if(context->protocol == mosq_p_mqtt5){ proplen = property__get_length_all(properties); diff --git a/src/send_suback.c b/src/send_suback.c index a276f81ccf..20eeb270af 100644 --- a/src/send_suback.c +++ b/src/send_suback.c @@ -36,7 +36,7 @@ int send__suback(struct mosquitto *context, uint16_t mid, uint32_t payloadlen, c packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet)); if(!packet) return MOSQ_ERR_NOMEM; - packet->command = SUBACK; + packet->command = CMD_SUBACK; packet->remaining_length = 2+payloadlen; if(context->protocol == mosq_p_mqtt5){ proplen = property__get_length_all(properties); diff --git a/test/unit/property_read.c b/test/unit/property_read.c index 2b34773529..f124ae216b 100644 --- a/test/unit/property_read.c +++ b/test/unit/property_read.c @@ -201,7 +201,7 @@ static void duplicate_string_helper(int identifier) payload[7] = 1; payload[8] = 'h'; - string_prop_read_helper(PUBLISH, payload, 9, MOSQ_ERR_PROTOCOL, identifier, ""); + string_prop_read_helper(CMD_PUBLISH, payload, 9, MOSQ_ERR_PROTOCOL, identifier, ""); } static void bad_string_helper(int identifier) @@ -217,7 +217,7 @@ static void bad_string_helper(int identifier) payload[5] = 0; /* 0 in string not allowed */ payload[6] = 'h'; - string_prop_read_helper(PUBLISH, payload, 7, MOSQ_ERR_MALFORMED_UTF8, identifier, ""); + string_prop_read_helper(CMD_PUBLISH, payload, 7, MOSQ_ERR_MALFORMED_UTF8, identifier, ""); } static void binary_prop_read_helper( @@ -285,7 +285,7 @@ static void string_pair_prop_read_helper( memset(&packet, 0, sizeof(struct mosquitto__packet)); packet.payload = payload; packet.remaining_length = remaining_length; - rc = property__read_all(CONNECT, &packet, &properties); + rc = property__read_all(CMD_CONNECT, &packet, &properties); CU_ASSERT_EQUAL(rc, rc_expected); CU_ASSERT_EQUAL(packet.pos, remaining_length); @@ -320,7 +320,7 @@ static void varint_prop_read_helper( memset(&packet, 0, sizeof(struct mosquitto__packet)); packet.payload = payload; packet.remaining_length = remaining_length; - rc = property__read_all(PUBLISH, &packet, &properties); + rc = property__read_all(CMD_PUBLISH, &packet, &properties); CU_ASSERT_EQUAL(rc, rc_expected); if(properties){ @@ -336,8 +336,8 @@ static void varint_prop_read_helper( static void packet_helper_reason_string_user_property(int command) { uint8_t payload[24] = {23, - PROP_REASON_STRING, 0, 6, 'r', 'e', 'a', 's', 'o', 'n', - PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e'}; + MQTT_PROP_REASON_STRING, 0, 6, 'r', 'e', 'a', 's', 'o', 'n', + MQTT_PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e'}; struct mosquitto__packet packet; struct mqtt5__property *properties, *p; @@ -354,14 +354,14 @@ static void packet_helper_reason_string_user_property(int command) CU_ASSERT_PTR_NOT_NULL(properties->next); p = properties; - CU_ASSERT_EQUAL(p->identifier, PROP_REASON_STRING); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_REASON_STRING); CU_ASSERT_STRING_EQUAL(p->value.s.v, "reason"); CU_ASSERT_EQUAL(p->value.s.len, strlen("reason")); p = p->next; CU_ASSERT_PTR_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_USER_PROPERTY); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_USER_PROPERTY); CU_ASSERT_STRING_EQUAL(p->value.s.v, "value"); CU_ASSERT_EQUAL(p->value.s.len, strlen("value")); CU_ASSERT_STRING_EQUAL(p->name.v, "name"); @@ -386,7 +386,7 @@ static void TEST_no_properties(void) memset(payload, 0, sizeof(payload)); packet.payload = payload; packet.remaining_length = 1; - rc = property__read_all(CONNECT, &packet, &properties); + rc = property__read_all(CMD_CONNECT, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); CU_ASSERT_PTR_EQUAL(properties, NULL); CU_ASSERT_EQUAL(packet.pos, 1); @@ -404,7 +404,7 @@ static void TEST_truncated(void) memset(payload, 0, sizeof(payload)); packet.payload = payload; packet.remaining_length = 0; - rc = property__read_all(CONNECT, &packet, &properties); + rc = property__read_all(CMD_CONNECT, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_PROTOCOL); CU_ASSERT_PTR_EQUAL(properties, NULL); CU_ASSERT_EQUAL(packet.pos, 0); @@ -415,7 +415,7 @@ static void TEST_truncated(void) payload[0] = 2; packet.payload = payload; packet.remaining_length = 1; - rc = property__read_all(CONNECT, &packet, &properties); + rc = property__read_all(CMD_CONNECT, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_PROTOCOL); CU_ASSERT_PTR_EQUAL(properties, NULL); CU_ASSERT_EQUAL(packet.pos, 1); @@ -424,10 +424,10 @@ static void TEST_truncated(void) memset(&packet, 0, sizeof(struct mosquitto__packet)); memset(payload, 0, sizeof(payload)); payload[0] = 4; - payload[1] = PROP_PAYLOAD_FORMAT_INDICATOR; + payload[1] = MQTT_PROP_PAYLOAD_FORMAT_INDICATOR; packet.payload = payload; packet.remaining_length = 2; - rc = property__read_all(CONNECT, &packet, &properties); + rc = property__read_all(CMD_CONNECT, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_PROTOCOL); CU_ASSERT_PTR_EQUAL(properties, NULL); CU_ASSERT_EQUAL(packet.pos, 2); @@ -450,7 +450,7 @@ static void TEST_invalid_property_id(void) payload[0] = 4; packet.payload = payload; packet.remaining_length = 2; - rc = property__read_all(CONNECT, &packet, &properties); + rc = property__read_all(CMD_CONNECT, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_MALFORMED_PACKET); CU_ASSERT_PTR_EQUAL(properties, NULL); CU_ASSERT_EQUAL(packet.pos, 2); @@ -462,7 +462,7 @@ static void TEST_invalid_property_id(void) payload[1] = 4; packet.payload = payload; packet.remaining_length = 2; - rc = property__read_all(CONNECT, &packet, &properties); + rc = property__read_all(CMD_CONNECT, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_MALFORMED_PACKET); CU_ASSERT_PTR_EQUAL(properties, NULL); CU_ASSERT_EQUAL(packet.pos, 2); @@ -478,10 +478,10 @@ static void TEST_single_payload_format_indicator(void) memset(&payload, 0, sizeof(payload)); payload[0] = 2; /* Proplen = Identifier + byte */ - payload[1] = PROP_PAYLOAD_FORMAT_INDICATOR; + payload[1] = MQTT_PROP_PAYLOAD_FORMAT_INDICATOR; payload[2] = 1; - byte_prop_read_helper(PUBLISH, payload, 3, MOSQ_ERR_SUCCESS, PROP_PAYLOAD_FORMAT_INDICATOR, 1); + byte_prop_read_helper(CMD_PUBLISH, payload, 3, MOSQ_ERR_SUCCESS, MQTT_PROP_PAYLOAD_FORMAT_INDICATOR, 1); } static void TEST_single_request_problem_information(void) @@ -490,10 +490,10 @@ static void TEST_single_request_problem_information(void) memset(&payload, 0, sizeof(payload)); payload[0] = 2; /* Proplen = Identifier + byte */ - payload[1] = PROP_REQUEST_PROBLEM_INFO; + payload[1] = MQTT_PROP_REQUEST_PROBLEM_INFORMATION; payload[2] = 1; - byte_prop_read_helper(CONNECT, payload, 3, MOSQ_ERR_SUCCESS, PROP_REQUEST_PROBLEM_INFO, 1); + byte_prop_read_helper(CMD_CONNECT, payload, 3, MOSQ_ERR_SUCCESS, MQTT_PROP_REQUEST_PROBLEM_INFORMATION, 1); } static void TEST_single_request_response_information(void) @@ -502,10 +502,10 @@ static void TEST_single_request_response_information(void) memset(&payload, 0, sizeof(payload)); payload[0] = 2; /* Proplen = Identifier + byte */ - payload[1] = PROP_REQUEST_RESPONSE_INFO; + payload[1] = MQTT_PROP_REQUEST_RESPONSE_INFORMATION; payload[2] = 1; - byte_prop_read_helper(CONNECT, payload, 3, MOSQ_ERR_SUCCESS, PROP_REQUEST_RESPONSE_INFO, 1); + byte_prop_read_helper(CMD_CONNECT, payload, 3, MOSQ_ERR_SUCCESS, MQTT_PROP_REQUEST_RESPONSE_INFORMATION, 1); } static void TEST_single_maximum_qos(void) @@ -514,10 +514,10 @@ static void TEST_single_maximum_qos(void) memset(&payload, 0, sizeof(payload)); payload[0] = 2; /* Proplen = Identifier + byte */ - payload[1] = PROP_MAXIMUM_QOS; + payload[1] = MQTT_PROP_MAXIMUM_QOS; payload[2] = 1; - byte_prop_read_helper(CONNACK, payload, 3, MOSQ_ERR_SUCCESS, PROP_MAXIMUM_QOS, 1); + byte_prop_read_helper(CMD_CONNACK, payload, 3, MOSQ_ERR_SUCCESS, MQTT_PROP_MAXIMUM_QOS, 1); } static void TEST_single_retain_available(void) @@ -526,10 +526,10 @@ static void TEST_single_retain_available(void) memset(&payload, 0, sizeof(payload)); payload[0] = 2; /* Proplen = Identifier + byte */ - payload[1] = PROP_RETAIN_AVAILABLE; + payload[1] = MQTT_PROP_RETAIN_AVAILABLE; payload[2] = 1; - byte_prop_read_helper(CONNACK, payload, 3, MOSQ_ERR_SUCCESS, PROP_RETAIN_AVAILABLE, 1); + byte_prop_read_helper(CMD_CONNACK, payload, 3, MOSQ_ERR_SUCCESS, MQTT_PROP_RETAIN_AVAILABLE, 1); } static void TEST_single_wildcard_subscription_available(void) @@ -538,10 +538,10 @@ static void TEST_single_wildcard_subscription_available(void) memset(&payload, 0, sizeof(payload)); payload[0] = 2; /* Proplen = Identifier + byte */ - payload[1] = PROP_WILDCARD_SUB_AVAILABLE; + payload[1] = MQTT_PROP_WILDCARD_SUB_AVAILABLE; payload[2] = 0; - byte_prop_read_helper(CONNACK, payload, 3, MOSQ_ERR_SUCCESS, PROP_WILDCARD_SUB_AVAILABLE, 0); + byte_prop_read_helper(CMD_CONNACK, payload, 3, MOSQ_ERR_SUCCESS, MQTT_PROP_WILDCARD_SUB_AVAILABLE, 0); } static void TEST_single_subscription_identifier_available(void) @@ -550,10 +550,10 @@ static void TEST_single_subscription_identifier_available(void) memset(&payload, 0, sizeof(payload)); payload[0] = 2; /* Proplen = Identifier + byte */ - payload[1] = PROP_SUBSCRIPTION_ID_AVAILABLE; + payload[1] = MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE; payload[2] = 0; - byte_prop_read_helper(CONNACK, payload, 3, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_ID_AVAILABLE, 0); + byte_prop_read_helper(CMD_CONNACK, payload, 3, MOSQ_ERR_SUCCESS, MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE, 0); } static void TEST_single_shared_subscription_available(void) @@ -562,10 +562,10 @@ static void TEST_single_shared_subscription_available(void) memset(&payload, 0, sizeof(payload)); payload[0] = 2; /* Proplen = Identifier + byte */ - payload[1] = PROP_SHARED_SUB_AVAILABLE; + payload[1] = MQTT_PROP_SHARED_SUB_AVAILABLE; payload[2] = 1; - byte_prop_read_helper(CONNACK, payload, 3, MOSQ_ERR_SUCCESS, PROP_SHARED_SUB_AVAILABLE, 1); + byte_prop_read_helper(CMD_CONNACK, payload, 3, MOSQ_ERR_SUCCESS, MQTT_PROP_SHARED_SUB_AVAILABLE, 1); } static void TEST_single_message_expiry_interval(void) @@ -574,13 +574,13 @@ static void TEST_single_message_expiry_interval(void) memset(&payload, 0, sizeof(payload)); payload[0] = 5; /* Proplen = Identifier + int32 */ - payload[1] = PROP_MESSAGE_EXPIRY_INTERVAL; + payload[1] = MQTT_PROP_MESSAGE_EXPIRY_INTERVAL; payload[2] = 0x12; payload[3] = 0x23; payload[4] = 0x34; payload[5] = 0x45; - int32_prop_read_helper(CMD_WILL, payload, 6, MOSQ_ERR_SUCCESS, PROP_MESSAGE_EXPIRY_INTERVAL, 0x12233445); + int32_prop_read_helper(CMD_WILL, payload, 6, MOSQ_ERR_SUCCESS, MQTT_PROP_MESSAGE_EXPIRY_INTERVAL, 0x12233445); } static void TEST_single_session_expiry_interval(void) @@ -589,13 +589,13 @@ static void TEST_single_session_expiry_interval(void) memset(&payload, 0, sizeof(payload)); payload[0] = 5; /* Proplen = Identifier + int32 */ - payload[1] = PROP_SESSION_EXPIRY_INTERVAL; + payload[1] = MQTT_PROP_SESSION_EXPIRY_INTERVAL; payload[2] = 0x45; payload[3] = 0x34; payload[4] = 0x23; payload[5] = 0x12; - int32_prop_read_helper(CONNACK, payload, 6, MOSQ_ERR_SUCCESS, PROP_SESSION_EXPIRY_INTERVAL, 0x45342312); + int32_prop_read_helper(CMD_CONNACK, payload, 6, MOSQ_ERR_SUCCESS, MQTT_PROP_SESSION_EXPIRY_INTERVAL, 0x45342312); } static void TEST_single_will_delay_interval(void) @@ -604,13 +604,13 @@ static void TEST_single_will_delay_interval(void) memset(&payload, 0, sizeof(payload)); payload[0] = 5; /* Proplen = Identifier + int32 */ - payload[1] = PROP_WILL_DELAY_INTERVAL; + payload[1] = MQTT_PROP_WILL_DELAY_INTERVAL; payload[2] = 0x45; payload[3] = 0x34; payload[4] = 0x23; payload[5] = 0x12; - int32_prop_read_helper(CMD_WILL, payload, 6, MOSQ_ERR_SUCCESS, PROP_WILL_DELAY_INTERVAL, 0x45342312); + int32_prop_read_helper(CMD_WILL, payload, 6, MOSQ_ERR_SUCCESS, MQTT_PROP_WILL_DELAY_INTERVAL, 0x45342312); } static void TEST_single_maximum_packet_size(void) @@ -619,13 +619,13 @@ static void TEST_single_maximum_packet_size(void) memset(&payload, 0, sizeof(payload)); payload[0] = 5; /* Proplen = Identifier + int32 */ - payload[1] = PROP_MAXIMUM_PACKET_SIZE; + payload[1] = MQTT_PROP_MAXIMUM_PACKET_SIZE; payload[2] = 0x45; payload[3] = 0x34; payload[4] = 0x23; payload[5] = 0x12; - int32_prop_read_helper(CONNECT, payload, 6, MOSQ_ERR_SUCCESS, PROP_MAXIMUM_PACKET_SIZE, 0x45342312); + int32_prop_read_helper(CMD_CONNECT, payload, 6, MOSQ_ERR_SUCCESS, MQTT_PROP_MAXIMUM_PACKET_SIZE, 0x45342312); } static void TEST_single_server_keep_alive(void) @@ -634,11 +634,11 @@ static void TEST_single_server_keep_alive(void) memset(&payload, 0, sizeof(payload)); payload[0] = 3; /* Proplen = Identifier + int16 */ - payload[1] = PROP_SERVER_KEEP_ALIVE; + payload[1] = MQTT_PROP_SERVER_KEEP_ALIVE; payload[2] = 0x45; payload[3] = 0x34; - int16_prop_read_helper(CONNACK, payload, 4, MOSQ_ERR_SUCCESS, PROP_SERVER_KEEP_ALIVE, 0x4534); + int16_prop_read_helper(CMD_CONNACK, payload, 4, MOSQ_ERR_SUCCESS, MQTT_PROP_SERVER_KEEP_ALIVE, 0x4534); } static void TEST_single_receive_maximum(void) @@ -647,11 +647,11 @@ static void TEST_single_receive_maximum(void) memset(&payload, 0, sizeof(payload)); payload[0] = 3; /* Proplen = Identifier + int16 */ - payload[1] = PROP_RECEIVE_MAXIMUM; + payload[1] = MQTT_PROP_RECEIVE_MAXIMUM; payload[2] = 0x68; payload[3] = 0x42; - int16_prop_read_helper(CONNACK, payload, 4, MOSQ_ERR_SUCCESS, PROP_RECEIVE_MAXIMUM, 0x6842); + int16_prop_read_helper(CMD_CONNACK, payload, 4, MOSQ_ERR_SUCCESS, MQTT_PROP_RECEIVE_MAXIMUM, 0x6842); } static void TEST_single_topic_alias_maximum(void) @@ -660,11 +660,11 @@ static void TEST_single_topic_alias_maximum(void) memset(&payload, 0, sizeof(payload)); payload[0] = 3; /* Proplen = Identifier + int16 */ - payload[1] = PROP_TOPIC_ALIAS_MAXIMUM; + payload[1] = MQTT_PROP_TOPIC_ALIAS_MAXIMUM; payload[2] = 0x68; payload[3] = 0x42; - int16_prop_read_helper(CONNECT, payload, 4, MOSQ_ERR_SUCCESS, PROP_TOPIC_ALIAS_MAXIMUM, 0x6842); + int16_prop_read_helper(CMD_CONNECT, payload, 4, MOSQ_ERR_SUCCESS, MQTT_PROP_TOPIC_ALIAS_MAXIMUM, 0x6842); } static void TEST_single_topic_alias(void) @@ -673,11 +673,11 @@ static void TEST_single_topic_alias(void) memset(&payload, 0, sizeof(payload)); payload[0] = 3; /* Proplen = Identifier + int16 */ - payload[1] = PROP_TOPIC_ALIAS; + payload[1] = MQTT_PROP_TOPIC_ALIAS; payload[2] = 0x68; payload[3] = 0x42; - int16_prop_read_helper(PUBLISH, payload, 4, MOSQ_ERR_SUCCESS, PROP_TOPIC_ALIAS, 0x6842); + int16_prop_read_helper(CMD_PUBLISH, payload, 4, MOSQ_ERR_SUCCESS, MQTT_PROP_TOPIC_ALIAS, 0x6842); } static void TEST_single_content_type(void) @@ -686,7 +686,7 @@ static void TEST_single_content_type(void) memset(&payload, 0, sizeof(payload)); payload[0] = 8; - payload[1] = PROP_CONTENT_TYPE; + payload[1] = MQTT_PROP_CONTENT_TYPE; payload[2] = 0x00; payload[3] = 0x05; payload[4] = 'h'; @@ -695,7 +695,7 @@ static void TEST_single_content_type(void) payload[7] = 'l'; payload[8] = 'o'; - string_prop_read_helper(PUBLISH, payload, 9, MOSQ_ERR_SUCCESS, PROP_CONTENT_TYPE, "hello"); + string_prop_read_helper(CMD_PUBLISH, payload, 9, MOSQ_ERR_SUCCESS, MQTT_PROP_CONTENT_TYPE, "hello"); } static void TEST_single_response_topic(void) @@ -704,7 +704,7 @@ static void TEST_single_response_topic(void) memset(&payload, 0, sizeof(payload)); payload[0] = 8; - payload[1] = PROP_RESPONSE_TOPIC; + payload[1] = MQTT_PROP_RESPONSE_TOPIC; payload[2] = 0x00; payload[3] = 0x05; payload[4] = 'h'; @@ -713,7 +713,7 @@ static void TEST_single_response_topic(void) payload[7] = 'l'; payload[8] = 'o'; - string_prop_read_helper(CMD_WILL, payload, 9, MOSQ_ERR_SUCCESS, PROP_RESPONSE_TOPIC, "hello"); + string_prop_read_helper(CMD_WILL, payload, 9, MOSQ_ERR_SUCCESS, MQTT_PROP_RESPONSE_TOPIC, "hello"); } static void TEST_single_assigned_client_identifier(void) @@ -722,7 +722,7 @@ static void TEST_single_assigned_client_identifier(void) memset(&payload, 0, sizeof(payload)); payload[0] = 8; - payload[1] = PROP_ASSIGNED_CLIENT_IDENTIFIER; + payload[1] = MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER; payload[2] = 0x00; payload[3] = 0x05; payload[4] = 'h'; @@ -731,7 +731,7 @@ static void TEST_single_assigned_client_identifier(void) payload[7] = 'l'; payload[8] = 'o'; - string_prop_read_helper(CONNACK, payload, 9, MOSQ_ERR_SUCCESS, PROP_ASSIGNED_CLIENT_IDENTIFIER, "hello"); + string_prop_read_helper(CMD_CONNACK, payload, 9, MOSQ_ERR_SUCCESS, MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER, "hello"); } static void TEST_single_authentication_method(void) @@ -740,7 +740,7 @@ static void TEST_single_authentication_method(void) memset(&payload, 0, sizeof(payload)); payload[0] = 8; - payload[1] = PROP_AUTHENTICATION_METHOD; + payload[1] = MQTT_PROP_AUTHENTICATION_METHOD; payload[2] = 0x00; payload[3] = 0x05; payload[4] = 'h'; @@ -749,7 +749,7 @@ static void TEST_single_authentication_method(void) payload[7] = 'l'; payload[8] = 'o'; - string_prop_read_helper(AUTH, payload, 9, MOSQ_ERR_SUCCESS, PROP_AUTHENTICATION_METHOD, "hello"); + string_prop_read_helper(CMD_AUTH, payload, 9, MOSQ_ERR_SUCCESS, MQTT_PROP_AUTHENTICATION_METHOD, "hello"); } static void TEST_single_response_information(void) @@ -758,7 +758,7 @@ static void TEST_single_response_information(void) memset(&payload, 0, sizeof(payload)); payload[0] = 8; - payload[1] = PROP_RESPONSE_INFO; + payload[1] = MQTT_PROP_RESPONSE_INFORMATION; payload[2] = 0x00; payload[3] = 0x05; payload[4] = 'h'; @@ -767,7 +767,7 @@ static void TEST_single_response_information(void) payload[7] = 'l'; payload[8] = 'o'; - string_prop_read_helper(CONNACK, payload, 9, MOSQ_ERR_SUCCESS, PROP_RESPONSE_INFO, "hello"); + string_prop_read_helper(CMD_CONNACK, payload, 9, MOSQ_ERR_SUCCESS, MQTT_PROP_RESPONSE_INFORMATION, "hello"); } static void TEST_single_server_reference(void) @@ -776,7 +776,7 @@ static void TEST_single_server_reference(void) memset(&payload, 0, sizeof(payload)); payload[0] = 8; - payload[1] = PROP_SERVER_REFERENCE; + payload[1] = MQTT_PROP_SERVER_REFERENCE; payload[2] = 0x00; payload[3] = 0x05; payload[4] = 'h'; @@ -785,7 +785,7 @@ static void TEST_single_server_reference(void) payload[7] = 'l'; payload[8] = 'o'; - string_prop_read_helper(CONNACK, payload, 9, MOSQ_ERR_SUCCESS, PROP_SERVER_REFERENCE, "hello"); + string_prop_read_helper(CMD_CONNACK, payload, 9, MOSQ_ERR_SUCCESS, MQTT_PROP_SERVER_REFERENCE, "hello"); } static void TEST_single_reason_string(void) @@ -794,7 +794,7 @@ static void TEST_single_reason_string(void) memset(&payload, 0, sizeof(payload)); payload[0] = 8; - payload[1] = PROP_REASON_STRING; + payload[1] = MQTT_PROP_REASON_STRING; payload[2] = 0x00; payload[3] = 0x05; payload[4] = 'h'; @@ -803,7 +803,7 @@ static void TEST_single_reason_string(void) payload[7] = 'l'; payload[8] = 'o'; - string_prop_read_helper(PUBCOMP, payload, 9, MOSQ_ERR_SUCCESS, PROP_REASON_STRING, "hello"); + string_prop_read_helper(CMD_PUBCOMP, payload, 9, MOSQ_ERR_SUCCESS, MQTT_PROP_REASON_STRING, "hello"); } static void TEST_single_correlation_data(void) @@ -812,7 +812,7 @@ static void TEST_single_correlation_data(void) memset(&payload, 0, sizeof(payload)); payload[0] = 8; - payload[1] = PROP_CORRELATION_DATA; + payload[1] = MQTT_PROP_CORRELATION_DATA; payload[2] = 0x00; payload[3] = 0x05; payload[4] = 1; @@ -821,7 +821,7 @@ static void TEST_single_correlation_data(void) payload[7] = 'l'; payload[8] = 9; - binary_prop_read_helper(PUBLISH, payload, 9, MOSQ_ERR_SUCCESS, PROP_CORRELATION_DATA, &payload[4], 5); + binary_prop_read_helper(CMD_PUBLISH, payload, 9, MOSQ_ERR_SUCCESS, MQTT_PROP_CORRELATION_DATA, &payload[4], 5); } static void TEST_single_authentication_data(void) @@ -830,7 +830,7 @@ static void TEST_single_authentication_data(void) memset(&payload, 0, sizeof(payload)); payload[0] = 8; - payload[1] = PROP_AUTHENTICATION_DATA; + payload[1] = MQTT_PROP_AUTHENTICATION_DATA; payload[2] = 0x00; payload[3] = 0x05; payload[4] = 1; @@ -839,7 +839,7 @@ static void TEST_single_authentication_data(void) payload[7] = 'l'; payload[8] = 9; - binary_prop_read_helper(CONNECT, payload, 9, MOSQ_ERR_SUCCESS, PROP_AUTHENTICATION_DATA, &payload[4], 5); + binary_prop_read_helper(CMD_CONNECT, payload, 9, MOSQ_ERR_SUCCESS, MQTT_PROP_AUTHENTICATION_DATA, &payload[4], 5); } static void TEST_single_user_property(void) @@ -847,7 +847,7 @@ static void TEST_single_user_property(void) uint8_t payload[20]; payload[0] = 9; - payload[1] = PROP_USER_PROPERTY; + payload[1] = MQTT_PROP_USER_PROPERTY; payload[2] = 0; payload[3] = 2; payload[4] = 'z'; @@ -857,7 +857,7 @@ static void TEST_single_user_property(void) payload[8] = 'b'; payload[9] = 'c'; - string_pair_prop_read_helper(payload, 10, MOSQ_ERR_SUCCESS, PROP_USER_PROPERTY, "za", "bc", false); + string_pair_prop_read_helper(payload, 10, MOSQ_ERR_SUCCESS, MQTT_PROP_USER_PROPERTY, "za", "bc", false); } static void TEST_single_subscription_identifier(void) @@ -865,57 +865,57 @@ static void TEST_single_subscription_identifier(void) uint8_t payload[20]; payload[0] = 2; - payload[1] = PROP_SUBSCRIPTION_IDENTIFIER; + payload[1] = MQTT_PROP_SUBSCRIPTION_IDENTIFIER; payload[2] = 0; - varint_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 0); + varint_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 0); payload[0] = 2; - payload[1] = PROP_SUBSCRIPTION_IDENTIFIER; + payload[1] = MQTT_PROP_SUBSCRIPTION_IDENTIFIER; payload[2] = 0x7F; - varint_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 127); + varint_prop_read_helper(payload, 3, MOSQ_ERR_SUCCESS, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 127); payload[0] = 3; - payload[1] = PROP_SUBSCRIPTION_IDENTIFIER; + payload[1] = MQTT_PROP_SUBSCRIPTION_IDENTIFIER; payload[2] = 0x80; payload[3] = 0x01; - varint_prop_read_helper(payload, 4, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 128); + varint_prop_read_helper(payload, 4, MOSQ_ERR_SUCCESS, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 128); payload[0] = 3; - payload[1] = PROP_SUBSCRIPTION_IDENTIFIER; + payload[1] = MQTT_PROP_SUBSCRIPTION_IDENTIFIER; payload[2] = 0xFF; payload[3] = 0x7F; - varint_prop_read_helper(payload, 4, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 16383); + varint_prop_read_helper(payload, 4, MOSQ_ERR_SUCCESS, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 16383); payload[0] = 4; - payload[1] = PROP_SUBSCRIPTION_IDENTIFIER; + payload[1] = MQTT_PROP_SUBSCRIPTION_IDENTIFIER; payload[2] = 0x80; payload[3] = 0x80; payload[4] = 0x01; - varint_prop_read_helper(payload, 5, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 16384); + varint_prop_read_helper(payload, 5, MOSQ_ERR_SUCCESS, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 16384); payload[0] = 4; - payload[1] = PROP_SUBSCRIPTION_IDENTIFIER; + payload[1] = MQTT_PROP_SUBSCRIPTION_IDENTIFIER; payload[2] = 0xFF; payload[3] = 0xFF; payload[4] = 0x7F; - varint_prop_read_helper(payload, 5, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 2097151); + varint_prop_read_helper(payload, 5, MOSQ_ERR_SUCCESS, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 2097151); payload[0] = 5; - payload[1] = PROP_SUBSCRIPTION_IDENTIFIER; + payload[1] = MQTT_PROP_SUBSCRIPTION_IDENTIFIER; payload[2] = 0x80; payload[3] = 0x80; payload[4] = 0x80; payload[5] = 0x01; - varint_prop_read_helper(payload, 6, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 2097152); + varint_prop_read_helper(payload, 6, MOSQ_ERR_SUCCESS, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 2097152); payload[0] = 5; - payload[1] = PROP_SUBSCRIPTION_IDENTIFIER; + payload[1] = MQTT_PROP_SUBSCRIPTION_IDENTIFIER; payload[2] = 0xFF; payload[3] = 0xFF; payload[4] = 0xFF; payload[5] = 0x7F; - varint_prop_read_helper(payload, 6, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 268435455); + varint_prop_read_helper(payload, 6, MOSQ_ERR_SUCCESS, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 268435455); } /* ======================================================================== @@ -924,127 +924,127 @@ static void TEST_single_subscription_identifier(void) static void TEST_duplicate_payload_format_indicator(void) { - duplicate_byte_helper(PUBLISH, PROP_PAYLOAD_FORMAT_INDICATOR); + duplicate_byte_helper(CMD_PUBLISH, MQTT_PROP_PAYLOAD_FORMAT_INDICATOR); } static void TEST_duplicate_request_problem_information(void) { - duplicate_byte_helper(CONNECT, PROP_REQUEST_PROBLEM_INFO); + duplicate_byte_helper(CMD_CONNECT, MQTT_PROP_REQUEST_PROBLEM_INFORMATION); } static void TEST_duplicate_request_response_information(void) { - duplicate_byte_helper(CONNECT, PROP_REQUEST_RESPONSE_INFO); + duplicate_byte_helper(CMD_CONNECT, MQTT_PROP_REQUEST_RESPONSE_INFORMATION); } static void TEST_duplicate_maximum_qos(void) { - duplicate_byte_helper(CONNACK, PROP_MAXIMUM_QOS); + duplicate_byte_helper(CMD_CONNACK, MQTT_PROP_MAXIMUM_QOS); } static void TEST_duplicate_retain_available(void) { - duplicate_byte_helper(CONNACK, PROP_RETAIN_AVAILABLE); + duplicate_byte_helper(CMD_CONNACK, MQTT_PROP_RETAIN_AVAILABLE); } static void TEST_duplicate_wildcard_subscription_available(void) { - duplicate_byte_helper(CONNACK, PROP_WILDCARD_SUB_AVAILABLE); + duplicate_byte_helper(CMD_CONNACK, MQTT_PROP_WILDCARD_SUB_AVAILABLE); } static void TEST_duplicate_subscription_identifier_available(void) { - duplicate_byte_helper(CONNACK, PROP_SUBSCRIPTION_ID_AVAILABLE); + duplicate_byte_helper(CMD_CONNACK, MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE); } static void TEST_duplicate_shared_subscription_available(void) { - duplicate_byte_helper(CONNACK, PROP_SHARED_SUB_AVAILABLE); + duplicate_byte_helper(CMD_CONNACK, MQTT_PROP_SHARED_SUB_AVAILABLE); } static void TEST_duplicate_message_expiry_interval(void) { - duplicate_int32_helper(PUBLISH, PROP_MESSAGE_EXPIRY_INTERVAL); + duplicate_int32_helper(CMD_PUBLISH, MQTT_PROP_MESSAGE_EXPIRY_INTERVAL); } static void TEST_duplicate_session_expiry_interval(void) { - duplicate_int32_helper(DISCONNECT, PROP_SESSION_EXPIRY_INTERVAL); + duplicate_int32_helper(CMD_DISCONNECT, MQTT_PROP_SESSION_EXPIRY_INTERVAL); } static void TEST_duplicate_will_delay_interval(void) { - duplicate_int32_helper(CMD_WILL, PROP_WILL_DELAY_INTERVAL); + duplicate_int32_helper(CMD_WILL, MQTT_PROP_WILL_DELAY_INTERVAL); } static void TEST_duplicate_maximum_packet_size(void) { - duplicate_int32_helper(CONNECT, PROP_MAXIMUM_PACKET_SIZE); + duplicate_int32_helper(CMD_CONNECT, MQTT_PROP_MAXIMUM_PACKET_SIZE); } static void TEST_duplicate_server_keep_alive(void) { - duplicate_int16_helper(CONNACK, PROP_SERVER_KEEP_ALIVE); + duplicate_int16_helper(CMD_CONNACK, MQTT_PROP_SERVER_KEEP_ALIVE); } static void TEST_duplicate_receive_maximum(void) { - duplicate_int16_helper(CONNACK, PROP_RECEIVE_MAXIMUM); + duplicate_int16_helper(CMD_CONNACK, MQTT_PROP_RECEIVE_MAXIMUM); } static void TEST_duplicate_topic_alias_maximum(void) { - duplicate_int16_helper(CONNECT, PROP_TOPIC_ALIAS_MAXIMUM); + duplicate_int16_helper(CMD_CONNECT, MQTT_PROP_TOPIC_ALIAS_MAXIMUM); } static void TEST_duplicate_topic_alias(void) { - duplicate_int16_helper(PUBLISH, PROP_TOPIC_ALIAS); + duplicate_int16_helper(CMD_PUBLISH, MQTT_PROP_TOPIC_ALIAS); } static void TEST_duplicate_content_type(void) { - duplicate_string_helper(PROP_CONTENT_TYPE); + duplicate_string_helper(MQTT_PROP_CONTENT_TYPE); } static void TEST_duplicate_response_topic(void) { - duplicate_string_helper(PROP_RESPONSE_TOPIC); + duplicate_string_helper(MQTT_PROP_RESPONSE_TOPIC); } static void TEST_duplicate_assigned_client_identifier(void) { - duplicate_string_helper(PROP_ASSIGNED_CLIENT_IDENTIFIER); + duplicate_string_helper(MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER); } static void TEST_duplicate_authentication_method(void) { - duplicate_string_helper(PROP_AUTHENTICATION_METHOD); + duplicate_string_helper(MQTT_PROP_AUTHENTICATION_METHOD); } static void TEST_duplicate_response_information(void) { - duplicate_string_helper(PROP_RESPONSE_INFO); + duplicate_string_helper(MQTT_PROP_RESPONSE_INFORMATION); } static void TEST_duplicate_server_reference(void) { - duplicate_string_helper(PROP_SERVER_REFERENCE); + duplicate_string_helper(MQTT_PROP_SERVER_REFERENCE); } static void TEST_duplicate_reason_string(void) { - duplicate_string_helper(PROP_REASON_STRING); + duplicate_string_helper(MQTT_PROP_REASON_STRING); } static void TEST_duplicate_correlation_data(void) { - duplicate_binary_helper(PUBLISH, PROP_CORRELATION_DATA); + duplicate_binary_helper(CMD_PUBLISH, MQTT_PROP_CORRELATION_DATA); } static void TEST_duplicate_authentication_data(void) { - duplicate_binary_helper(CONNACK, PROP_AUTHENTICATION_DATA); + duplicate_binary_helper(CMD_CONNACK, MQTT_PROP_AUTHENTICATION_DATA); } static void TEST_duplicate_user_property(void) @@ -1053,7 +1053,7 @@ static void TEST_duplicate_user_property(void) memset(&payload, 0, sizeof(payload)); payload[0] = 18; /* Proplen = (Identifier + byte)*2 */ - payload[1] = PROP_USER_PROPERTY; + payload[1] = MQTT_PROP_USER_PROPERTY; payload[2] = 0; payload[3] = 2; payload[4] = 'a'; @@ -1062,7 +1062,7 @@ static void TEST_duplicate_user_property(void) payload[7] = 2; payload[8] = 'g'; payload[9] = 'h'; - payload[10] = PROP_USER_PROPERTY; + payload[10] = MQTT_PROP_USER_PROPERTY; payload[11] = 0; payload[12] = 2; payload[13] = 'c'; @@ -1072,7 +1072,7 @@ static void TEST_duplicate_user_property(void) payload[17] = 'e'; payload[18] = 'f'; - string_pair_prop_read_helper(payload, 19, MOSQ_ERR_SUCCESS, PROP_USER_PROPERTY, "ab", "gh", true); + string_pair_prop_read_helper(payload, 19, MOSQ_ERR_SUCCESS, MQTT_PROP_USER_PROPERTY, "ab", "gh", true); } static void TEST_duplicate_subscription_identifier(void) @@ -1081,13 +1081,13 @@ static void TEST_duplicate_subscription_identifier(void) memset(&payload, 0, sizeof(payload)); payload[0] = 4; /* Proplen = (Identifier + byte)*2 */ - payload[1] = PROP_SUBSCRIPTION_IDENTIFIER; + payload[1] = MQTT_PROP_SUBSCRIPTION_IDENTIFIER; payload[2] = 0x80; payload[3] = 0x02; - payload[4] = PROP_SUBSCRIPTION_IDENTIFIER; + payload[4] = MQTT_PROP_SUBSCRIPTION_IDENTIFIER; payload[5] = 0x04; - varint_prop_read_helper(payload, 5, MOSQ_ERR_PROTOCOL, PROP_SUBSCRIPTION_IDENTIFIER, 0); + varint_prop_read_helper(payload, 5, MOSQ_ERR_PROTOCOL, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 0); } /* ======================================================================== @@ -1096,37 +1096,37 @@ static void TEST_duplicate_subscription_identifier(void) static void TEST_bad_request_problem_information(void) { - bad_byte_helper(CONNECT, PROP_REQUEST_PROBLEM_INFO); + bad_byte_helper(CMD_CONNECT, MQTT_PROP_REQUEST_PROBLEM_INFORMATION); } static void TEST_bad_request_response_information(void) { - bad_byte_helper(CONNECT, PROP_REQUEST_RESPONSE_INFO); + bad_byte_helper(CMD_CONNECT, MQTT_PROP_REQUEST_RESPONSE_INFORMATION); } static void TEST_bad_maximum_qos(void) { - bad_byte_helper(CONNACK, PROP_MAXIMUM_QOS); + bad_byte_helper(CMD_CONNACK, MQTT_PROP_MAXIMUM_QOS); } static void TEST_bad_retain_available(void) { - bad_byte_helper(CONNACK, PROP_RETAIN_AVAILABLE); + bad_byte_helper(CMD_CONNACK, MQTT_PROP_RETAIN_AVAILABLE); } static void TEST_bad_wildcard_sub_available(void) { - bad_byte_helper(CONNACK, PROP_WILDCARD_SUB_AVAILABLE); + bad_byte_helper(CMD_CONNACK, MQTT_PROP_WILDCARD_SUB_AVAILABLE); } static void TEST_bad_subscription_id_available(void) { - bad_byte_helper(CONNACK, PROP_SUBSCRIPTION_ID_AVAILABLE); + bad_byte_helper(CMD_CONNACK, MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE); } static void TEST_bad_shared_sub_available(void) { - bad_byte_helper(CONNACK, PROP_SHARED_SUB_AVAILABLE); + bad_byte_helper(CMD_CONNACK, MQTT_PROP_SHARED_SUB_AVAILABLE); } static void TEST_bad_maximum_packet_size(void) @@ -1135,13 +1135,13 @@ static void TEST_bad_maximum_packet_size(void) memset(&payload, 0, sizeof(payload)); payload[0] = 5; /* Proplen = Identifier + int32 */ - payload[1] = PROP_MAXIMUM_PACKET_SIZE; + payload[1] = MQTT_PROP_MAXIMUM_PACKET_SIZE; payload[2] = 0; payload[3] = 0; payload[4] = 0; payload[5] = 0; /* 0 is invalid */ - int32_prop_read_helper(CONNACK, payload, 6, MOSQ_ERR_PROTOCOL, PROP_MAXIMUM_PACKET_SIZE, 0); + int32_prop_read_helper(CMD_CONNACK, payload, 6, MOSQ_ERR_PROTOCOL, MQTT_PROP_MAXIMUM_PACKET_SIZE, 0); } static void TEST_bad_receive_maximum(void) @@ -1150,11 +1150,11 @@ static void TEST_bad_receive_maximum(void) memset(&payload, 0, sizeof(payload)); payload[0] = 3; /* Proplen = Identifier + int16 */ - payload[1] = PROP_RECEIVE_MAXIMUM; + payload[1] = MQTT_PROP_RECEIVE_MAXIMUM; payload[2] = 0; payload[3] = 0; /* 0 is invalid */ - int32_prop_read_helper(CONNECT, payload, 4, MOSQ_ERR_PROTOCOL, PROP_RECEIVE_MAXIMUM, 0); + int32_prop_read_helper(CMD_CONNECT, payload, 4, MOSQ_ERR_PROTOCOL, MQTT_PROP_RECEIVE_MAXIMUM, 0); } static void TEST_bad_topic_alias(void) @@ -1163,16 +1163,16 @@ static void TEST_bad_topic_alias(void) memset(&payload, 0, sizeof(payload)); payload[0] = 3; /* Proplen = Identifier + int16 */ - payload[1] = PROP_TOPIC_ALIAS; + payload[1] = MQTT_PROP_TOPIC_ALIAS; payload[2] = 0; payload[3] = 0; /* 0 is invalid */ - int32_prop_read_helper(PUBLISH, payload, 4, MOSQ_ERR_PROTOCOL, PROP_TOPIC_ALIAS, 0); + int32_prop_read_helper(CMD_PUBLISH, payload, 4, MOSQ_ERR_PROTOCOL, MQTT_PROP_TOPIC_ALIAS, 0); } static void TEST_bad_content_type(void) { - bad_string_helper(PROP_CONTENT_TYPE); + bad_string_helper(MQTT_PROP_CONTENT_TYPE); } static void TEST_bad_subscription_identifier(void) @@ -1181,14 +1181,14 @@ static void TEST_bad_subscription_identifier(void) memset(&payload, 0, sizeof(payload)); payload[0] = 6; - payload[1] = PROP_SUBSCRIPTION_IDENTIFIER; + payload[1] = MQTT_PROP_SUBSCRIPTION_IDENTIFIER; payload[2] = 0xFF; payload[3] = 0xFF; payload[4] = 0xFF; payload[5] = 0xFF; payload[6] = 0x01; - varint_prop_read_helper(payload, 7, MOSQ_ERR_PROTOCOL, PROP_SUBSCRIPTION_IDENTIFIER, 0); + varint_prop_read_helper(payload, 7, MOSQ_ERR_PROTOCOL, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 0); } /* ======================================================================== @@ -1198,15 +1198,15 @@ static void TEST_bad_subscription_identifier(void) static void TEST_packet_connect(void) { uint8_t payload[] = {0, - PROP_SESSION_EXPIRY_INTERVAL, 0x12, 0x45, 0x00, 0x00, - PROP_RECEIVE_MAXIMUM, 0x00, 0x05, - PROP_MAXIMUM_PACKET_SIZE, 0x12, 0x45, 0x00, 0x00, - PROP_TOPIC_ALIAS_MAXIMUM, 0x00, 0x02, - PROP_REQUEST_PROBLEM_INFO, 1, - PROP_REQUEST_RESPONSE_INFO, 1, - PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e', - PROP_AUTHENTICATION_METHOD, 0x00, 0x04, 'n', 'o', 'n', 'e', - PROP_AUTHENTICATION_DATA, 0x00, 0x02, 1, 2}; + MQTT_PROP_SESSION_EXPIRY_INTERVAL, 0x12, 0x45, 0x00, 0x00, + MQTT_PROP_RECEIVE_MAXIMUM, 0x00, 0x05, + MQTT_PROP_MAXIMUM_PACKET_SIZE, 0x12, 0x45, 0x00, 0x00, + MQTT_PROP_TOPIC_ALIAS_MAXIMUM, 0x00, 0x02, + MQTT_PROP_REQUEST_PROBLEM_INFORMATION, 1, + MQTT_PROP_REQUEST_RESPONSE_INFORMATION, 1, + MQTT_PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e', + MQTT_PROP_AUTHENTICATION_METHOD, 0x00, 0x04, 'n', 'o', 'n', 'e', + MQTT_PROP_AUTHENTICATION_DATA, 0x00, 0x02, 1, 2}; struct mosquitto__packet packet; struct mqtt5__property *properties, *p; @@ -1217,44 +1217,44 @@ static void TEST_packet_connect(void) memset(&packet, 0, sizeof(struct mosquitto__packet)); packet.payload = payload; packet.remaining_length = sizeof(payload);; - rc = property__read_all(CONNECT, &packet, &properties); + rc = property__read_all(CMD_CONNECT, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); CU_ASSERT_PTR_NOT_NULL(properties->next); p = properties; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_SESSION_EXPIRY_INTERVAL); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_SESSION_EXPIRY_INTERVAL); CU_ASSERT_EQUAL(p->value.i32, 0x12450000); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_RECEIVE_MAXIMUM); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_RECEIVE_MAXIMUM); CU_ASSERT_EQUAL(p->value.i16, 0x0005); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_MAXIMUM_PACKET_SIZE); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_MAXIMUM_PACKET_SIZE); CU_ASSERT_EQUAL(p->value.i32, 0x12450000); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_TOPIC_ALIAS_MAXIMUM); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_TOPIC_ALIAS_MAXIMUM); CU_ASSERT_EQUAL(p->value.i16, 0x0002); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_REQUEST_PROBLEM_INFO); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_REQUEST_PROBLEM_INFORMATION); CU_ASSERT_EQUAL(p->value.i8, 1); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_REQUEST_RESPONSE_INFO); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_REQUEST_RESPONSE_INFORMATION); CU_ASSERT_EQUAL(p->value.i8, 1); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_USER_PROPERTY); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_USER_PROPERTY); CU_ASSERT_STRING_EQUAL(p->value.s.v, "value"); CU_ASSERT_EQUAL(p->value.s.len, strlen("value")); CU_ASSERT_STRING_EQUAL(p->name.v, "name"); @@ -1262,13 +1262,13 @@ static void TEST_packet_connect(void) p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_AUTHENTICATION_METHOD); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_AUTHENTICATION_METHOD); CU_ASSERT_STRING_EQUAL(p->value.s.v, "none"); CU_ASSERT_EQUAL(p->value.s.len, strlen("none")); p = p->next; CU_ASSERT_PTR_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_AUTHENTICATION_DATA); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_AUTHENTICATION_DATA); CU_ASSERT_EQUAL(p->value.bin.v[0], 1); CU_ASSERT_EQUAL(p->value.bin.v[1], 2); CU_ASSERT_EQUAL(p->value.s.len, 2); @@ -1279,23 +1279,23 @@ static void TEST_packet_connect(void) static void TEST_packet_connack(void) { uint8_t payload[] = {0, - PROP_SESSION_EXPIRY_INTERVAL, 0x12, 0x45, 0x00, 0x00, - PROP_RECEIVE_MAXIMUM, 0x00, 0x05, - PROP_MAXIMUM_QOS, 1, - PROP_RETAIN_AVAILABLE, 0, - PROP_MAXIMUM_PACKET_SIZE, 0x12, 0x45, 0x00, 0x00, - PROP_ASSIGNED_CLIENT_IDENTIFIER, 0x00, 0x02, 'a', 'b', - PROP_TOPIC_ALIAS_MAXIMUM, 0x00, 0x02, - PROP_REASON_STRING, 0, 6, 'r', 'e', 'a', 's', 'o', 'n', - PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e', - PROP_WILDCARD_SUB_AVAILABLE, 0, - PROP_SUBSCRIPTION_ID_AVAILABLE, 0, - PROP_SHARED_SUB_AVAILABLE, 0, - PROP_SERVER_KEEP_ALIVE, 0x00, 0xFF, - PROP_RESPONSE_INFO, 0x00, 0x03, 'r', 's', 'p', - PROP_SERVER_REFERENCE, 0x00, 0x04, 's', 'e', 'r', 'v', - PROP_AUTHENTICATION_METHOD, 0x00, 0x04, 'n', 'o', 'n', 'e', - PROP_AUTHENTICATION_DATA, 0x00, 0x02, 1, 2}; + MQTT_PROP_SESSION_EXPIRY_INTERVAL, 0x12, 0x45, 0x00, 0x00, + MQTT_PROP_RECEIVE_MAXIMUM, 0x00, 0x05, + MQTT_PROP_MAXIMUM_QOS, 1, + MQTT_PROP_RETAIN_AVAILABLE, 0, + MQTT_PROP_MAXIMUM_PACKET_SIZE, 0x12, 0x45, 0x00, 0x00, + MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER, 0x00, 0x02, 'a', 'b', + MQTT_PROP_TOPIC_ALIAS_MAXIMUM, 0x00, 0x02, + MQTT_PROP_REASON_STRING, 0, 6, 'r', 'e', 'a', 's', 'o', 'n', + MQTT_PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e', + MQTT_PROP_WILDCARD_SUB_AVAILABLE, 0, + MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE, 0, + MQTT_PROP_SHARED_SUB_AVAILABLE, 0, + MQTT_PROP_SERVER_KEEP_ALIVE, 0x00, 0xFF, + MQTT_PROP_RESPONSE_INFORMATION, 0x00, 0x03, 'r', 's', 'p', + MQTT_PROP_SERVER_REFERENCE, 0x00, 0x04, 's', 'e', 'r', 'v', + MQTT_PROP_AUTHENTICATION_METHOD, 0x00, 0x04, 'n', 'o', 'n', 'e', + MQTT_PROP_AUTHENTICATION_DATA, 0x00, 0x02, 1, 2}; struct mosquitto__packet packet; struct mqtt5__property *properties, *p; @@ -1306,56 +1306,56 @@ static void TEST_packet_connack(void) memset(&packet, 0, sizeof(struct mosquitto__packet)); packet.payload = payload; packet.remaining_length = sizeof(payload);; - rc = property__read_all(CONNACK, &packet, &properties); + rc = property__read_all(CMD_CONNACK, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); CU_ASSERT_PTR_NOT_NULL(properties->next); p = properties; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_SESSION_EXPIRY_INTERVAL); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_SESSION_EXPIRY_INTERVAL); CU_ASSERT_EQUAL(p->value.i32, 0x12450000); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_RECEIVE_MAXIMUM); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_RECEIVE_MAXIMUM); CU_ASSERT_EQUAL(p->value.i16, 0x0005); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_MAXIMUM_QOS); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_MAXIMUM_QOS); CU_ASSERT_EQUAL(p->value.i8, 1); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_RETAIN_AVAILABLE); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_RETAIN_AVAILABLE); CU_ASSERT_EQUAL(p->value.i8, 0); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_MAXIMUM_PACKET_SIZE); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_MAXIMUM_PACKET_SIZE); CU_ASSERT_EQUAL(p->value.i32, 0x12450000); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_ASSIGNED_CLIENT_IDENTIFIER); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER); CU_ASSERT_STRING_EQUAL(p->value.s.v, "ab"); CU_ASSERT_EQUAL(p->value.s.len, strlen("ab")); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_TOPIC_ALIAS_MAXIMUM); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_TOPIC_ALIAS_MAXIMUM); CU_ASSERT_EQUAL(p->value.i16, 0x0002); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_REASON_STRING); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_REASON_STRING); CU_ASSERT_STRING_EQUAL(p->value.s.v, "reason"); CU_ASSERT_EQUAL(p->value.s.len, strlen("reason")); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_USER_PROPERTY); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_USER_PROPERTY); CU_ASSERT_STRING_EQUAL(p->value.s.v, "value"); CU_ASSERT_EQUAL(p->value.s.len, strlen("value")); CU_ASSERT_STRING_EQUAL(p->name.v, "name"); @@ -1363,45 +1363,45 @@ static void TEST_packet_connack(void) p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_WILDCARD_SUB_AVAILABLE); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_WILDCARD_SUB_AVAILABLE); CU_ASSERT_EQUAL(p->value.i8, 0); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_SUBSCRIPTION_ID_AVAILABLE); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE); CU_ASSERT_EQUAL(p->value.i8, 0); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_SHARED_SUB_AVAILABLE); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_SHARED_SUB_AVAILABLE); CU_ASSERT_EQUAL(p->value.i8, 0); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_SERVER_KEEP_ALIVE); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_SERVER_KEEP_ALIVE); CU_ASSERT_EQUAL(p->value.i16, 0x00FF); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_RESPONSE_INFO); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_RESPONSE_INFORMATION); CU_ASSERT_STRING_EQUAL(p->value.s.v, "rsp"); CU_ASSERT_EQUAL(p->value.s.len, strlen("rsp")); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_SERVER_REFERENCE); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_SERVER_REFERENCE); CU_ASSERT_STRING_EQUAL(p->value.s.v, "serv"); CU_ASSERT_EQUAL(p->value.s.len, strlen("serv")); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_AUTHENTICATION_METHOD); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_AUTHENTICATION_METHOD); CU_ASSERT_STRING_EQUAL(p->value.s.v, "none"); CU_ASSERT_EQUAL(p->value.s.len, strlen("none")); p = p->next; CU_ASSERT_PTR_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_AUTHENTICATION_DATA); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_AUTHENTICATION_DATA); CU_ASSERT_EQUAL(p->value.bin.v[0], 1); CU_ASSERT_EQUAL(p->value.bin.v[1], 2); CU_ASSERT_EQUAL(p->value.s.len, 2); @@ -1412,14 +1412,14 @@ static void TEST_packet_connack(void) static void TEST_packet_publish(void) { uint8_t payload[] = {0, - PROP_PAYLOAD_FORMAT_INDICATOR, 1, - PROP_MESSAGE_EXPIRY_INTERVAL, 0x12, 0x45, 0x00, 0x00, - PROP_TOPIC_ALIAS, 0x00, 0x02, - PROP_RESPONSE_TOPIC, 0, 6, 'r', 'e', 's', 'p', 'o', 'n', - PROP_CORRELATION_DATA, 0x00, 0x02, 1, 2, - PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e', - PROP_SUBSCRIPTION_IDENTIFIER, 0x04, - PROP_CONTENT_TYPE, 0, 5, 'e', 'm', 'p', 't', 'y'}; + MQTT_PROP_PAYLOAD_FORMAT_INDICATOR, 1, + MQTT_PROP_MESSAGE_EXPIRY_INTERVAL, 0x12, 0x45, 0x00, 0x00, + MQTT_PROP_TOPIC_ALIAS, 0x00, 0x02, + MQTT_PROP_RESPONSE_TOPIC, 0, 6, 'r', 'e', 's', 'p', 'o', 'n', + MQTT_PROP_CORRELATION_DATA, 0x00, 0x02, 1, 2, + MQTT_PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e', + MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 0x04, + MQTT_PROP_CONTENT_TYPE, 0, 5, 'e', 'm', 'p', 't', 'y'}; struct mosquitto__packet packet; struct mqtt5__property *properties, *p; @@ -1430,42 +1430,42 @@ static void TEST_packet_publish(void) memset(&packet, 0, sizeof(struct mosquitto__packet)); packet.payload = payload; packet.remaining_length = sizeof(payload);; - rc = property__read_all(PUBLISH, &packet, &properties); + rc = property__read_all(CMD_PUBLISH, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); CU_ASSERT_PTR_NOT_NULL(properties->next); p = properties; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_PAYLOAD_FORMAT_INDICATOR); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_PAYLOAD_FORMAT_INDICATOR); CU_ASSERT_EQUAL(p->value.i8, 1); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_MESSAGE_EXPIRY_INTERVAL); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_MESSAGE_EXPIRY_INTERVAL); CU_ASSERT_EQUAL(p->value.i32, 0x12450000); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_TOPIC_ALIAS); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_TOPIC_ALIAS); CU_ASSERT_EQUAL(p->value.i16, 0x0002); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_RESPONSE_TOPIC); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_RESPONSE_TOPIC); CU_ASSERT_STRING_EQUAL(p->value.s.v, "respon"); CU_ASSERT_EQUAL(p->value.s.len, strlen("respon")); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_CORRELATION_DATA); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_CORRELATION_DATA); CU_ASSERT_EQUAL(p->value.bin.v[0], 1); CU_ASSERT_EQUAL(p->value.bin.v[1], 2); CU_ASSERT_EQUAL(p->value.bin.len, 2); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_USER_PROPERTY); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_USER_PROPERTY); CU_ASSERT_STRING_EQUAL(p->value.s.v, "value"); CU_ASSERT_EQUAL(p->value.s.len, strlen("value")); CU_ASSERT_STRING_EQUAL(p->name.v, "name"); @@ -1473,12 +1473,12 @@ static void TEST_packet_publish(void) p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_SUBSCRIPTION_IDENTIFIER); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_SUBSCRIPTION_IDENTIFIER); CU_ASSERT_EQUAL(p->value.varint, 0x00000004); p = p->next; CU_ASSERT_PTR_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_CONTENT_TYPE); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_CONTENT_TYPE); CU_ASSERT_STRING_EQUAL(p->value.s.v, "empty"); CU_ASSERT_EQUAL(p->value.s.len, strlen("empty")); @@ -1487,29 +1487,29 @@ static void TEST_packet_publish(void) static void TEST_packet_puback(void) { - packet_helper_reason_string_user_property(PUBACK); + packet_helper_reason_string_user_property(CMD_PUBACK); } static void TEST_packet_pubrec(void) { - packet_helper_reason_string_user_property(PUBREC); + packet_helper_reason_string_user_property(CMD_PUBREC); } static void TEST_packet_pubrel(void) { - packet_helper_reason_string_user_property(PUBREL); + packet_helper_reason_string_user_property(CMD_PUBREL); } static void TEST_packet_pubcomp(void) { - packet_helper_reason_string_user_property(PUBCOMP); + packet_helper_reason_string_user_property(CMD_PUBCOMP); } static void TEST_packet_subscribe(void) { uint8_t payload[] = {0, - PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e', - PROP_SUBSCRIPTION_IDENTIFIER, 0x04}; + MQTT_PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e', + MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 0x04}; struct mosquitto__packet packet; struct mqtt5__property *properties, *p; @@ -1520,14 +1520,14 @@ static void TEST_packet_subscribe(void) memset(&packet, 0, sizeof(struct mosquitto__packet)); packet.payload = payload; packet.remaining_length = sizeof(payload);; - rc = property__read_all(SUBSCRIBE, &packet, &properties); + rc = property__read_all(CMD_SUBSCRIBE, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); CU_ASSERT_PTR_NOT_NULL(properties->next); p = properties; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_USER_PROPERTY); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_USER_PROPERTY); CU_ASSERT_STRING_EQUAL(p->value.s.v, "value"); CU_ASSERT_EQUAL(p->value.s.len, strlen("value")); CU_ASSERT_STRING_EQUAL(p->name.v, "name"); @@ -1535,7 +1535,7 @@ static void TEST_packet_subscribe(void) p = p->next; CU_ASSERT_PTR_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_SUBSCRIPTION_IDENTIFIER); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_SUBSCRIPTION_IDENTIFIER); CU_ASSERT_EQUAL(p->value.varint, 0x00000004); mosquitto_property_free_all(&properties); @@ -1543,13 +1543,13 @@ static void TEST_packet_subscribe(void) static void TEST_packet_suback(void) { - packet_helper_reason_string_user_property(SUBACK); + packet_helper_reason_string_user_property(CMD_SUBACK); } static void TEST_packet_unsubscribe(void) { uint8_t payload[] = {0, - PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e'}; + MQTT_PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e'}; struct mosquitto__packet packet; struct mqtt5__property *properties, *p; @@ -1560,13 +1560,13 @@ static void TEST_packet_unsubscribe(void) memset(&packet, 0, sizeof(struct mosquitto__packet)); packet.payload = payload; packet.remaining_length = sizeof(payload);; - rc = property__read_all(UNSUBSCRIBE, &packet, &properties); + rc = property__read_all(CMD_UNSUBSCRIBE, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); p = properties; CU_ASSERT_PTR_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_USER_PROPERTY); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_USER_PROPERTY); CU_ASSERT_STRING_EQUAL(p->value.s.v, "value"); CU_ASSERT_EQUAL(p->value.s.len, strlen("value")); CU_ASSERT_STRING_EQUAL(p->name.v, "name"); @@ -1577,15 +1577,15 @@ static void TEST_packet_unsubscribe(void) static void TEST_packet_unsuback(void) { - packet_helper_reason_string_user_property(UNSUBACK); + packet_helper_reason_string_user_property(CMD_UNSUBACK); } static void TEST_packet_disconnect(void) { uint8_t payload[] = {0, - PROP_SESSION_EXPIRY_INTERVAL, 0x12, 0x45, 0x00, 0x00, - PROP_REASON_STRING, 0, 6, 'r', 'e', 'a', 's', 'o', 'n', - PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e'}; + MQTT_PROP_SESSION_EXPIRY_INTERVAL, 0x12, 0x45, 0x00, 0x00, + MQTT_PROP_REASON_STRING, 0, 6, 'r', 'e', 'a', 's', 'o', 'n', + MQTT_PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e'}; struct mosquitto__packet packet; struct mqtt5__property *properties, *p; @@ -1596,25 +1596,25 @@ static void TEST_packet_disconnect(void) memset(&packet, 0, sizeof(struct mosquitto__packet)); packet.payload = payload; packet.remaining_length = sizeof(payload);; - rc = property__read_all(DISCONNECT, &packet, &properties); + rc = property__read_all(CMD_DISCONNECT, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); CU_ASSERT_PTR_NOT_NULL(properties->next); p = properties; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_SESSION_EXPIRY_INTERVAL); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_SESSION_EXPIRY_INTERVAL); CU_ASSERT_EQUAL(p->value.i32, 0x12450000); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_REASON_STRING); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_REASON_STRING); CU_ASSERT_STRING_EQUAL(p->value.s.v, "reason"); CU_ASSERT_EQUAL(p->value.s.len, strlen("reason")); p = p->next; CU_ASSERT_PTR_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_USER_PROPERTY); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_USER_PROPERTY); CU_ASSERT_STRING_EQUAL(p->value.s.v, "value"); CU_ASSERT_EQUAL(p->value.s.len, strlen("value")); CU_ASSERT_STRING_EQUAL(p->name.v, "name"); @@ -1626,10 +1626,10 @@ static void TEST_packet_disconnect(void) static void TEST_packet_auth(void) { uint8_t payload[] = {0, - PROP_AUTHENTICATION_METHOD, 0x00, 0x04, 'n', 'o', 'n', 'e', - PROP_AUTHENTICATION_DATA, 0x00, 0x02, 1, 2, - PROP_REASON_STRING, 0, 6, 'r', 'e', 'a', 's', 'o', 'n', - PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e'}; + MQTT_PROP_AUTHENTICATION_METHOD, 0x00, 0x04, 'n', 'o', 'n', 'e', + MQTT_PROP_AUTHENTICATION_DATA, 0x00, 0x02, 1, 2, + MQTT_PROP_REASON_STRING, 0, 6, 'r', 'e', 'a', 's', 'o', 'n', + MQTT_PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e'}; struct mosquitto__packet packet; struct mqtt5__property *properties, *p; @@ -1640,33 +1640,33 @@ static void TEST_packet_auth(void) memset(&packet, 0, sizeof(struct mosquitto__packet)); packet.payload = payload; packet.remaining_length = sizeof(payload);; - rc = property__read_all(AUTH, &packet, &properties); + rc = property__read_all(CMD_AUTH, &packet, &properties); CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); CU_ASSERT_PTR_NOT_NULL(properties->next); p = properties; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_AUTHENTICATION_METHOD); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_AUTHENTICATION_METHOD); CU_ASSERT_STRING_EQUAL(p->value.s.v, "none"); CU_ASSERT_EQUAL(p->value.s.len, strlen("none")); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_AUTHENTICATION_DATA); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_AUTHENTICATION_DATA); CU_ASSERT_EQUAL(p->value.bin.v[0], 1); CU_ASSERT_EQUAL(p->value.bin.v[1], 2); CU_ASSERT_EQUAL(p->value.s.len, 2); p = p->next; CU_ASSERT_PTR_NOT_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_REASON_STRING); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_REASON_STRING); CU_ASSERT_STRING_EQUAL(p->value.s.v, "reason"); CU_ASSERT_EQUAL(p->value.s.len, strlen("reason")); p = p->next; CU_ASSERT_PTR_NULL(p->next); - CU_ASSERT_EQUAL(p->identifier, PROP_USER_PROPERTY); + CU_ASSERT_EQUAL(p->identifier, MQTT_PROP_USER_PROPERTY); CU_ASSERT_STRING_EQUAL(p->value.s.v, "value"); CU_ASSERT_EQUAL(p->value.s.len, strlen("value")); CU_ASSERT_STRING_EQUAL(p->name.v, "name"); diff --git a/test/unit/property_write.c b/test/unit/property_write.c index 950034122f..00533539e6 100644 --- a/test/unit/property_write.c +++ b/test/unit/property_write.c @@ -240,7 +240,7 @@ static void string_pair_prop_write_helper( property__write_all(&packet, &property); packet.pos = 0; - rc = property__read_all(CONNECT, &packet, &properties); + rc = property__read_all(CMD_CONNECT, &packet, &properties); CU_ASSERT_EQUAL(rc, rc_expected); CU_ASSERT_EQUAL(packet.pos, remaining_length); @@ -287,7 +287,7 @@ static void varint_prop_write_helper( property__write_all(&packet, &property); packet.pos = 0; - rc = property__read_all(PUBLISH, &packet, &properties); + rc = property__read_all(CMD_PUBLISH, &packet, &properties); CU_ASSERT_EQUAL(rc, rc_expected); if(properties){ @@ -338,148 +338,148 @@ static void TEST_bad_identifier(void) static void TEST_single_payload_format_indicator(void) { - byte_prop_write_helper(PUBLISH, 3, MOSQ_ERR_SUCCESS, PROP_PAYLOAD_FORMAT_INDICATOR, 1); + byte_prop_write_helper(CMD_PUBLISH, 3, MOSQ_ERR_SUCCESS, MQTT_PROP_PAYLOAD_FORMAT_INDICATOR, 1); } static void TEST_single_request_problem_information(void) { - byte_prop_write_helper(CONNECT, 3, MOSQ_ERR_SUCCESS, PROP_REQUEST_PROBLEM_INFO, 1); + byte_prop_write_helper(CMD_CONNECT, 3, MOSQ_ERR_SUCCESS, MQTT_PROP_REQUEST_PROBLEM_INFORMATION, 1); } static void TEST_single_request_response_information(void) { - byte_prop_write_helper(CONNECT, 3, MOSQ_ERR_SUCCESS, PROP_REQUEST_RESPONSE_INFO, 1); + byte_prop_write_helper(CMD_CONNECT, 3, MOSQ_ERR_SUCCESS, MQTT_PROP_REQUEST_RESPONSE_INFORMATION, 1); } static void TEST_single_maximum_qos(void) { - byte_prop_write_helper(CONNACK, 3, MOSQ_ERR_SUCCESS, PROP_MAXIMUM_QOS, 1); + byte_prop_write_helper(CMD_CONNACK, 3, MOSQ_ERR_SUCCESS, MQTT_PROP_MAXIMUM_QOS, 1); } static void TEST_single_retain_available(void) { - byte_prop_write_helper(CONNACK, 3, MOSQ_ERR_SUCCESS, PROP_RETAIN_AVAILABLE, 1); + byte_prop_write_helper(CMD_CONNACK, 3, MOSQ_ERR_SUCCESS, MQTT_PROP_RETAIN_AVAILABLE, 1); } static void TEST_single_wildcard_subscription_available(void) { - byte_prop_write_helper(CONNACK, 3, MOSQ_ERR_SUCCESS, PROP_WILDCARD_SUB_AVAILABLE, 0); + byte_prop_write_helper(CMD_CONNACK, 3, MOSQ_ERR_SUCCESS, MQTT_PROP_WILDCARD_SUB_AVAILABLE, 0); } static void TEST_single_subscription_identifier_available(void) { - byte_prop_write_helper(CONNACK, 3, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_ID_AVAILABLE, 0); + byte_prop_write_helper(CMD_CONNACK, 3, MOSQ_ERR_SUCCESS, MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE, 0); } static void TEST_single_shared_subscription_available(void) { - byte_prop_write_helper(CONNACK, 3, MOSQ_ERR_SUCCESS, PROP_SHARED_SUB_AVAILABLE, 1); + byte_prop_write_helper(CMD_CONNACK, 3, MOSQ_ERR_SUCCESS, MQTT_PROP_SHARED_SUB_AVAILABLE, 1); } static void TEST_single_message_expiry_interval(void) { - int32_prop_write_helper(PUBLISH, 6, MOSQ_ERR_SUCCESS, PROP_MESSAGE_EXPIRY_INTERVAL, 0x12233445); + int32_prop_write_helper(CMD_PUBLISH, 6, MOSQ_ERR_SUCCESS, MQTT_PROP_MESSAGE_EXPIRY_INTERVAL, 0x12233445); } static void TEST_single_session_expiry_interval(void) { - int32_prop_write_helper(CONNACK, 6, MOSQ_ERR_SUCCESS, PROP_SESSION_EXPIRY_INTERVAL, 0x45342312); + int32_prop_write_helper(CMD_CONNACK, 6, MOSQ_ERR_SUCCESS, MQTT_PROP_SESSION_EXPIRY_INTERVAL, 0x45342312); } static void TEST_single_will_delay_interval(void) { - int32_prop_write_helper(CMD_WILL, 6, MOSQ_ERR_SUCCESS, PROP_WILL_DELAY_INTERVAL, 0x45342312); + int32_prop_write_helper(CMD_WILL, 6, MOSQ_ERR_SUCCESS, MQTT_PROP_WILL_DELAY_INTERVAL, 0x45342312); } static void TEST_single_maximum_packet_size(void) { - int32_prop_write_helper(CONNECT, 6, MOSQ_ERR_SUCCESS, PROP_MAXIMUM_PACKET_SIZE, 0x45342312); + int32_prop_write_helper(CMD_CONNECT, 6, MOSQ_ERR_SUCCESS, MQTT_PROP_MAXIMUM_PACKET_SIZE, 0x45342312); } static void TEST_single_server_keep_alive(void) { - int16_prop_write_helper(CONNACK, 4, MOSQ_ERR_SUCCESS, PROP_SERVER_KEEP_ALIVE, 0x4534); + int16_prop_write_helper(CMD_CONNACK, 4, MOSQ_ERR_SUCCESS, MQTT_PROP_SERVER_KEEP_ALIVE, 0x4534); } static void TEST_single_receive_maximum(void) { - int16_prop_write_helper(CONNACK, 4, MOSQ_ERR_SUCCESS, PROP_RECEIVE_MAXIMUM, 0x6842); + int16_prop_write_helper(CMD_CONNACK, 4, MOSQ_ERR_SUCCESS, MQTT_PROP_RECEIVE_MAXIMUM, 0x6842); } static void TEST_single_topic_alias_maximum(void) { - int16_prop_write_helper(CONNECT, 4, MOSQ_ERR_SUCCESS, PROP_TOPIC_ALIAS_MAXIMUM, 0x6842); + int16_prop_write_helper(CMD_CONNECT, 4, MOSQ_ERR_SUCCESS, MQTT_PROP_TOPIC_ALIAS_MAXIMUM, 0x6842); } static void TEST_single_topic_alias(void) { - int16_prop_write_helper(PUBLISH, 4, MOSQ_ERR_SUCCESS, PROP_TOPIC_ALIAS, 0x6842); + int16_prop_write_helper(CMD_PUBLISH, 4, MOSQ_ERR_SUCCESS, MQTT_PROP_TOPIC_ALIAS, 0x6842); } static void TEST_single_content_type(void) { - string_prop_write_helper(PUBLISH, 9, MOSQ_ERR_SUCCESS, PROP_CONTENT_TYPE, "hello"); + string_prop_write_helper(CMD_PUBLISH, 9, MOSQ_ERR_SUCCESS, MQTT_PROP_CONTENT_TYPE, "hello"); } static void TEST_single_response_topic(void) { - string_prop_write_helper(CMD_WILL, 9, MOSQ_ERR_SUCCESS, PROP_RESPONSE_TOPIC, "hello"); + string_prop_write_helper(CMD_WILL, 9, MOSQ_ERR_SUCCESS, MQTT_PROP_RESPONSE_TOPIC, "hello"); } static void TEST_single_assigned_client_identifier(void) { - string_prop_write_helper(CONNACK, 9, MOSQ_ERR_SUCCESS, PROP_ASSIGNED_CLIENT_IDENTIFIER, "hello"); + string_prop_write_helper(CMD_CONNACK, 9, MOSQ_ERR_SUCCESS, MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER, "hello"); } static void TEST_single_authentication_method(void) { - string_prop_write_helper(CONNECT, 9, MOSQ_ERR_SUCCESS, PROP_AUTHENTICATION_METHOD, "hello"); + string_prop_write_helper(CMD_CONNECT, 9, MOSQ_ERR_SUCCESS, MQTT_PROP_AUTHENTICATION_METHOD, "hello"); } static void TEST_single_response_information(void) { - string_prop_write_helper(CONNACK, 9, MOSQ_ERR_SUCCESS, PROP_RESPONSE_INFO, "hello"); + string_prop_write_helper(CMD_CONNACK, 9, MOSQ_ERR_SUCCESS, MQTT_PROP_RESPONSE_INFORMATION, "hello"); } static void TEST_single_server_reference(void) { - string_prop_write_helper(CONNACK, 9, MOSQ_ERR_SUCCESS, PROP_SERVER_REFERENCE, "hello"); + string_prop_write_helper(CMD_CONNACK, 9, MOSQ_ERR_SUCCESS, MQTT_PROP_SERVER_REFERENCE, "hello"); } static void TEST_single_reason_string(void) { - string_prop_write_helper(PUBREC, 9, MOSQ_ERR_SUCCESS, PROP_REASON_STRING, "hello"); + string_prop_write_helper(CMD_PUBREC, 9, MOSQ_ERR_SUCCESS, MQTT_PROP_REASON_STRING, "hello"); } static void TEST_single_correlation_data(void) { uint8_t payload[5] = {1, 'e', 0, 'l', 9}; - binary_prop_write_helper(PUBLISH, 9, MOSQ_ERR_SUCCESS, PROP_CORRELATION_DATA, payload, 5); + binary_prop_write_helper(CMD_PUBLISH, 9, MOSQ_ERR_SUCCESS, MQTT_PROP_CORRELATION_DATA, payload, 5); } static void TEST_single_authentication_data(void) { uint8_t payload[5] = {1, 'e', 0, 'l', 9}; - binary_prop_write_helper(CONNECT, 9, MOSQ_ERR_SUCCESS, PROP_AUTHENTICATION_DATA, payload, 5); + binary_prop_write_helper(CMD_CONNECT, 9, MOSQ_ERR_SUCCESS, MQTT_PROP_AUTHENTICATION_DATA, payload, 5); } static void TEST_single_user_property(void) { - string_pair_prop_write_helper(10, MOSQ_ERR_SUCCESS, PROP_USER_PROPERTY, "za", "bc", false); + string_pair_prop_write_helper(10, MOSQ_ERR_SUCCESS, MQTT_PROP_USER_PROPERTY, "za", "bc", false); } static void TEST_single_subscription_identifier(void) { - varint_prop_write_helper(3, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 0); - varint_prop_write_helper(3, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 127); - varint_prop_write_helper(4, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 128); - varint_prop_write_helper(4, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 16383); - varint_prop_write_helper(5, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 16384); - varint_prop_write_helper(5, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 2097151); - varint_prop_write_helper(6, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 2097152); - varint_prop_write_helper(6, MOSQ_ERR_SUCCESS, PROP_SUBSCRIPTION_IDENTIFIER, 268435455); + varint_prop_write_helper(3, MOSQ_ERR_SUCCESS, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 0); + varint_prop_write_helper(3, MOSQ_ERR_SUCCESS, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 127); + varint_prop_write_helper(4, MOSQ_ERR_SUCCESS, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 128); + varint_prop_write_helper(4, MOSQ_ERR_SUCCESS, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 16383); + varint_prop_write_helper(5, MOSQ_ERR_SUCCESS, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 16384); + varint_prop_write_helper(5, MOSQ_ERR_SUCCESS, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 2097151); + varint_prop_write_helper(6, MOSQ_ERR_SUCCESS, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 2097152); + varint_prop_write_helper(6, MOSQ_ERR_SUCCESS, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 268435455); } From 63a479564bfb6f4bb0e75c5ca4224804239bca4a Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 30 Oct 2018 11:32:37 +0000 Subject: [PATCH 070/254] Add mosquitto_property_command_check() --- lib/linker.version | 1 + lib/mosquitto.h | 14 ++++ lib/property_mosq.c | 184 +++++++++++++++++++++++--------------------- 3 files changed, 111 insertions(+), 88 deletions(-) diff --git a/lib/linker.version b/lib/linker.version index 727f85b0bf..c047e87c0e 100644 --- a/lib/linker.version +++ b/lib/linker.version @@ -96,4 +96,5 @@ MOSQ_1.6 { global: mosquitto_subscribe_multiple; mosquitto_property_free_all; + mosquitto_property_command_check; } MOSQ_1.5; diff --git a/lib/mosquitto.h b/lib/mosquitto.h index 668de8147f..129560c0e9 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -1897,6 +1897,20 @@ libmosq_EXPORT int mosquitto_validate_utf8(const char *str, int len); */ libmosq_EXPORT void mosquitto_property_free_all(mosquitto_property **properties); +/* + * Function: mosquitto_property_command_check + * + * Check whether a property identifier is valid for the given command. + * + * Parameters: + * command - MQTT command (e.g. CMD_CONNECT) + * identifier - MQTT property (e.g. MQTT_PROP_USER_PROPERTY) + * + * Returns: + * MOSQ_ERR_SUCCESS - if the identifier is valid for command + * MOSQ_ERR_PROTOCOL - if the identifier is not valid for use with command. + */ +int mosquitto_property_command_check(int command, int identifier); #ifdef __cplusplus } diff --git a/lib/property_mosq.c b/lib/property_mosq.c index a970ef9f7f..a3c5d20985 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -451,100 +451,108 @@ int property__write_all(struct mosquitto__packet *packet, struct mqtt5__property } +int mosquitto_property_command_check(int command, int identifier) +{ + switch(identifier){ + case MQTT_PROP_PAYLOAD_FORMAT_INDICATOR: + case MQTT_PROP_MESSAGE_EXPIRY_INTERVAL: + case MQTT_PROP_CONTENT_TYPE: + case MQTT_PROP_RESPONSE_TOPIC: + case MQTT_PROP_CORRELATION_DATA: + if(command != CMD_PUBLISH && command != CMD_WILL){ + return MOSQ_ERR_PROTOCOL; + } + break; + + case MQTT_PROP_SUBSCRIPTION_IDENTIFIER: + if(command != CMD_PUBLISH && command != CMD_SUBSCRIBE){ + return MOSQ_ERR_PROTOCOL; + } + break; + + case MQTT_PROP_SESSION_EXPIRY_INTERVAL: + if(command != CMD_CONNECT && command != CMD_CONNACK && command != CMD_DISCONNECT){ + return MOSQ_ERR_PROTOCOL; + } + break; + + case MQTT_PROP_AUTHENTICATION_METHOD: + case MQTT_PROP_AUTHENTICATION_DATA: + if(command != CMD_CONNECT && command != CMD_CONNACK && command != CMD_AUTH){ + return MOSQ_ERR_PROTOCOL; + } + break; + + case MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER: + case MQTT_PROP_SERVER_KEEP_ALIVE: + case MQTT_PROP_RESPONSE_INFORMATION: + case MQTT_PROP_MAXIMUM_QOS: + case MQTT_PROP_RETAIN_AVAILABLE: + case MQTT_PROP_WILDCARD_SUB_AVAILABLE: + case MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE: + case MQTT_PROP_SHARED_SUB_AVAILABLE: + if(command != CMD_CONNACK){ + return MOSQ_ERR_PROTOCOL; + } + break; + + case MQTT_PROP_WILL_DELAY_INTERVAL: + if(command != CMD_WILL){ + return MOSQ_ERR_PROTOCOL; + } + break; + + case MQTT_PROP_REQUEST_PROBLEM_INFORMATION: + case MQTT_PROP_REQUEST_RESPONSE_INFORMATION: + if(command != CMD_CONNECT){ + return MOSQ_ERR_PROTOCOL; + } + break; + + case MQTT_PROP_SERVER_REFERENCE: + if(command != CMD_CONNACK && command != CMD_DISCONNECT){ + return MOSQ_ERR_PROTOCOL; + } + break; + + case MQTT_PROP_REASON_STRING: + if(command == CMD_CONNECT || command == CMD_PUBLISH || command == CMD_SUBSCRIBE || command == CMD_UNSUBSCRIBE){ + return MOSQ_ERR_PROTOCOL; + } + break; + + case MQTT_PROP_RECEIVE_MAXIMUM: + case MQTT_PROP_TOPIC_ALIAS_MAXIMUM: + case MQTT_PROP_MAXIMUM_PACKET_SIZE: + if(command != CMD_CONNECT && command != CMD_CONNACK){ + return MOSQ_ERR_PROTOCOL; + } + break; + + case MQTT_PROP_TOPIC_ALIAS: + if(command != CMD_PUBLISH){ + return MOSQ_ERR_PROTOCOL; + } + break; + + case MQTT_PROP_USER_PROPERTY: + break; + + default: + return MOSQ_ERR_PROTOCOL; + } + return MOSQ_ERR_SUCCESS; +} + static int property__command_check(int command, struct mqtt5__property *properties) { struct mqtt5__property *p; + int rc; p = properties; while(p){ - switch(p->identifier){ - case MQTT_PROP_PAYLOAD_FORMAT_INDICATOR: - case MQTT_PROP_MESSAGE_EXPIRY_INTERVAL: - case MQTT_PROP_CONTENT_TYPE: - case MQTT_PROP_RESPONSE_TOPIC: - case MQTT_PROP_CORRELATION_DATA: - if(command != CMD_PUBLISH && command != CMD_WILL){ - return MOSQ_ERR_PROTOCOL; - } - break; - - case MQTT_PROP_SUBSCRIPTION_IDENTIFIER: - if(command != CMD_PUBLISH && command != CMD_SUBSCRIBE){ - return MOSQ_ERR_PROTOCOL; - } - break; - - case MQTT_PROP_SESSION_EXPIRY_INTERVAL: - if(command != CMD_CONNECT && command != CMD_CONNACK && command != CMD_DISCONNECT){ - return MOSQ_ERR_PROTOCOL; - } - break; - - case MQTT_PROP_AUTHENTICATION_METHOD: - case MQTT_PROP_AUTHENTICATION_DATA: - if(command != CMD_CONNECT && command != CMD_CONNACK && command != CMD_AUTH){ - return MOSQ_ERR_PROTOCOL; - } - break; - - case MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER: - case MQTT_PROP_SERVER_KEEP_ALIVE: - case MQTT_PROP_RESPONSE_INFORMATION: - case MQTT_PROP_MAXIMUM_QOS: - case MQTT_PROP_RETAIN_AVAILABLE: - case MQTT_PROP_WILDCARD_SUB_AVAILABLE: - case MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE: - case MQTT_PROP_SHARED_SUB_AVAILABLE: - if(command != CMD_CONNACK){ - return MOSQ_ERR_PROTOCOL; - } - break; - - case MQTT_PROP_WILL_DELAY_INTERVAL: - if(command != CMD_WILL){ - return MOSQ_ERR_PROTOCOL; - } - break; - - case MQTT_PROP_REQUEST_PROBLEM_INFORMATION: - case MQTT_PROP_REQUEST_RESPONSE_INFORMATION: - if(command != CMD_CONNECT){ - return MOSQ_ERR_PROTOCOL; - } - break; - - case MQTT_PROP_SERVER_REFERENCE: - if(command != CMD_CONNACK && command != CMD_DISCONNECT){ - return MOSQ_ERR_PROTOCOL; - } - break; - - case MQTT_PROP_REASON_STRING: - if(command == CMD_CONNECT || command == CMD_PUBLISH || command == CMD_SUBSCRIBE || command == CMD_UNSUBSCRIBE){ - return MOSQ_ERR_PROTOCOL; - } - break; - - case MQTT_PROP_RECEIVE_MAXIMUM: - case MQTT_PROP_TOPIC_ALIAS_MAXIMUM: - case MQTT_PROP_MAXIMUM_PACKET_SIZE: - if(command != CMD_CONNECT && command != CMD_CONNACK){ - return MOSQ_ERR_PROTOCOL; - } - break; - - case MQTT_PROP_TOPIC_ALIAS: - if(command != CMD_PUBLISH){ - return MOSQ_ERR_PROTOCOL; - } - break; - - case MQTT_PROP_USER_PROPERTY: - break; - - default: - return MOSQ_ERR_PROTOCOL; - } + rc = mosquitto_property_command_check(command, p->identifier); + if(rc) return rc; p = p->next; } From c19b3598c077718cfedda1e5084914708b15ec65 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 30 Oct 2018 11:40:06 +0000 Subject: [PATCH 071/254] Add mosquitto_string_to_command. --- lib/linker.version | 3 ++- lib/mosquitto.c | 34 ++++++++++++++++++++++++++++++++++ lib/mosquitto.h | 19 +++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/lib/linker.version b/lib/linker.version index c047e87c0e..9502cc1577 100644 --- a/lib/linker.version +++ b/lib/linker.version @@ -94,7 +94,8 @@ MOSQ_1.5 { MOSQ_1.6 { global: - mosquitto_subscribe_multiple; mosquitto_property_free_all; mosquitto_property_command_check; + mosquitto_string_to_command; + mosquitto_subscribe_multiple; } MOSQ_1.5; diff --git a/lib/mosquitto.c b/lib/mosquitto.c index e5bd32927c..ebecbdc939 100644 --- a/lib/mosquitto.c +++ b/lib/mosquitto.c @@ -493,6 +493,40 @@ const char *mosquitto_reason_string(int reason_code) } } + +int mosquitto_string_to_command(const char *str, int *cmd) +{ + if(!strcasecmp(str, "connect")){ + *cmd = CMD_CONNECT; + }else if(!strcasecmp(str, "connack")){ + *cmd = CMD_CONNACK; + }else if(!strcasecmp(str, "publish")){ + *cmd = CMD_PUBLISH; + }else if(!strcasecmp(str, "puback")){ + *cmd = CMD_PUBACK; + }else if(!strcasecmp(str, "pubrec")){ + *cmd = CMD_PUBREC; + }else if(!strcasecmp(str, "pubrel")){ + *cmd = CMD_PUBREL; + }else if(!strcasecmp(str, "pubcomp")){ + *cmd = CMD_PUBCOMP; + }else if(!strcasecmp(str, "subscribe")){ + *cmd = CMD_SUBSCRIBE; + }else if(!strcasecmp(str, "unsubscribe")){ + *cmd = CMD_UNSUBSCRIBE; + }else if(!strcasecmp(str, "disconnect")){ + *cmd = CMD_DISCONNECT; + }else if(!strcasecmp(str, "auth")){ + *cmd = CMD_AUTH; + }else if(!strcasecmp(str, "will")){ + *cmd = CMD_WILL; + }else{ + return MOSQ_ERR_INVAL; + } + return MOSQ_ERR_SUCCESS; +} + + int mosquitto_sub_topic_tokenise(const char *subtopic, char ***topics, int *count) { int len; diff --git a/lib/mosquitto.h b/lib/mosquitto.h index 129560c0e9..9ff9f7874e 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -1568,6 +1568,25 @@ libmosq_EXPORT const char *mosquitto_strerror(int mosq_errno); */ libmosq_EXPORT const char *mosquitto_connack_string(int connack_code); +/* Function: mosquitto_string_to_command + * + * Take a string input representing an MQTT command and convert it to the + * libmosquitto integer representation. + * + * Parameters: + * str - the string to parse. + * cmd - pointer to an int, for the result. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - on an invalid input. + * + * Example: + * mosquitto_string_to_command("CONNECT", &cmd); + * // cmd == CMD_CONNECT + */ +libmosq_EXPORT int mosquitto_string_to_command(const char *str, int *cmd); + /* * Function: mosquitto_sub_topic_tokenise * From 446ad6290a3cc056d6f519071893d78062f726dc Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 30 Oct 2018 11:54:36 +0000 Subject: [PATCH 072/254] Add mosquitto_string_to_property_info. --- lib/linker.version | 1 + lib/mosquitto.h | 23 ++++++++++++ lib/mqtt_protocol.h | 10 +++++ lib/property_mosq.c | 89 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 123 insertions(+) diff --git a/lib/linker.version b/lib/linker.version index 9502cc1577..347beeccbe 100644 --- a/lib/linker.version +++ b/lib/linker.version @@ -97,5 +97,6 @@ MOSQ_1.6 { mosquitto_property_free_all; mosquitto_property_command_check; mosquitto_string_to_command; + mosquitto_string_to_property_info; mosquitto_subscribe_multiple; } MOSQ_1.5; diff --git a/lib/mosquitto.h b/lib/mosquitto.h index 9ff9f7874e..338baa8876 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -1931,6 +1931,29 @@ libmosq_EXPORT void mosquitto_property_free_all(mosquitto_property **properties) */ int mosquitto_property_command_check(int command, int identifier); +/* Function: mosquitto_string_to_property_info + * + * Parse a property name string and convert to a property identifier and data type. + * The property name is as defined in the MQTT specification, with - as a + * separator, for example: payload-format-indicator. + * + * Parameters: + * propname - the string to parse + * identifier - pointer to an int to receive the property identifier + * type - pointer to an int to receive the property type + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if the string does not match a property + * + * Example: + * mosquitto_string_to_property_info("response-topic", &id, &type); + * // id == MQTT_PROP_RESPONSE_TOPIC + * // type == MQTT_PROP_TYPE_STRING + */ +int mosquitto_string_to_property_info(const char *propname, int *identifier, int *type); + + #ifdef __cplusplus } #endif diff --git a/lib/mqtt_protocol.h b/lib/mqtt_protocol.h index 4b132018a9..2d53f6f880 100644 --- a/lib/mqtt_protocol.h +++ b/lib/mqtt_protocol.h @@ -135,6 +135,16 @@ enum mqtt5_property { MQTT_PROP_SHARED_SUB_AVAILABLE = 42, /* Byte : CONNACK */ }; +enum mqtt5_property_type { + MQTT_PROP_TYPE_BYTE = 1, + MQTT_PROP_TYPE_INT16 = 2, + MQTT_PROP_TYPE_INT32 = 3, + MQTT_PROP_TYPE_VARINT = 4, + MQTT_PROP_TYPE_BINARY = 5, + MQTT_PROP_TYPE_STRING = 6, + MQTT_PROP_TYPE_STRING_PAIR = 7 +}; + #define MQTT_MAX_PAYLOAD 268435455 #endif diff --git a/lib/property_mosq.c b/lib/property_mosq.c index a3c5d20985..b5556d7dbb 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -559,3 +559,92 @@ static int property__command_check(int command, struct mqtt5__property *properti return MOSQ_ERR_SUCCESS; } + +int mosquitto_string_to_property_info(const char *propname, int *identifier, int *type) +{ + if(!strcasecmp(propname, "payload-format-indicator")){ + *identifier = MQTT_PROP_PAYLOAD_FORMAT_INDICATOR; + *type = MQTT_PROP_TYPE_BYTE; + }else if(!strcasecmp(propname, "message-expiry-interval")){ + *identifier = MQTT_PROP_MESSAGE_EXPIRY_INTERVAL; + *type = MQTT_PROP_TYPE_INT32; + }else if(!strcasecmp(propname, "content-type")){ + *identifier = MQTT_PROP_CONTENT_TYPE; + *type = MQTT_PROP_TYPE_STRING; + }else if(!strcasecmp(propname, "response-topic")){ + *identifier = MQTT_PROP_RESPONSE_TOPIC; + *type = MQTT_PROP_TYPE_STRING; + }else if(!strcasecmp(propname, "correlation-data")){ + *identifier = MQTT_PROP_CORRELATION_DATA; + *type = MQTT_PROP_TYPE_BINARY; + }else if(!strcasecmp(propname, "subscription-identifier")){ + *identifier = MQTT_PROP_SUBSCRIPTION_IDENTIFIER; + *type = MQTT_PROP_TYPE_VARINT; + }else if(!strcasecmp(propname, "session-expiry-interval")){ + *identifier = MQTT_PROP_SESSION_EXPIRY_INTERVAL; + *type = MQTT_PROP_TYPE_INT32; + }else if(!strcasecmp(propname, "assigned-client-identifier")){ + *identifier = MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER; + *type = MQTT_PROP_TYPE_STRING; + }else if(!strcasecmp(propname, "server-keep-alive")){ + *identifier = MQTT_PROP_SERVER_KEEP_ALIVE; + *type = MQTT_PROP_TYPE_INT16; + }else if(!strcasecmp(propname, "authentication-method")){ + *identifier = MQTT_PROP_AUTHENTICATION_METHOD; + *type = MQTT_PROP_TYPE_STRING; + }else if(!strcasecmp(propname, "authentication-data")){ + *identifier = MQTT_PROP_AUTHENTICATION_DATA; + *type = MQTT_PROP_TYPE_BINARY; + }else if(!strcasecmp(propname, "request-problem-information")){ + *identifier = MQTT_PROP_REQUEST_PROBLEM_INFORMATION; + *type = MQTT_PROP_TYPE_BYTE; + }else if(!strcasecmp(propname, "will-delay-interval")){ + *identifier = MQTT_PROP_WILL_DELAY_INTERVAL; + *type = MQTT_PROP_TYPE_INT32; + }else if(!strcasecmp(propname, "request-response-information")){ + *identifier = MQTT_PROP_REQUEST_RESPONSE_INFORMATION; + *type = MQTT_PROP_TYPE_BYTE; + }else if(!strcasecmp(propname, "response-information")){ + *identifier = MQTT_PROP_RESPONSE_INFORMATION; + *type = MQTT_PROP_TYPE_STRING; + }else if(!strcasecmp(propname, "server-reference")){ + *identifier = MQTT_PROP_SERVER_REFERENCE; + *type = MQTT_PROP_TYPE_STRING; + }else if(!strcasecmp(propname, "reason-string")){ + *identifier = MQTT_PROP_REASON_STRING; + *type = MQTT_PROP_TYPE_STRING; + }else if(!strcasecmp(propname, "receive-maximum")){ + *identifier = MQTT_PROP_RECEIVE_MAXIMUM; + *type = MQTT_PROP_TYPE_INT16; + }else if(!strcasecmp(propname, "topic-alias-maximum")){ + *identifier = MQTT_PROP_TOPIC_ALIAS_MAXIMUM; + *type = MQTT_PROP_TYPE_INT16; + }else if(!strcasecmp(propname, "topic-alias")){ + *identifier = MQTT_PROP_TOPIC_ALIAS; + *type = MQTT_PROP_TYPE_INT16; + }else if(!strcasecmp(propname, "maximum-qos")){ + *identifier = MQTT_PROP_MAXIMUM_QOS; + *type = MQTT_PROP_TYPE_BYTE; + }else if(!strcasecmp(propname, "retain-available")){ + *identifier = MQTT_PROP_RETAIN_AVAILABLE; + *type = MQTT_PROP_TYPE_BYTE; + }else if(!strcasecmp(propname, "user-property")){ + *identifier = MQTT_PROP_USER_PROPERTY; + *type = MQTT_PROP_TYPE_STRING_PAIR; + }else if(!strcasecmp(propname, "maximum-packet-size")){ + *identifier = MQTT_PROP_MAXIMUM_PACKET_SIZE; + *type = MQTT_PROP_TYPE_INT32; + }else if(!strcasecmp(propname, "wildcard-subscription-available")){ + *identifier = MQTT_PROP_WILDCARD_SUB_AVAILABLE; + *type = MQTT_PROP_TYPE_BYTE; + }else if(!strcasecmp(propname, "subscription-identifier-available")){ + *identifier = MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE; + *type = MQTT_PROP_TYPE_BYTE; + }else if(!strcasecmp(propname, "shared-subscription-available")){ + *identifier = MQTT_PROP_SHARED_SUB_AVAILABLE; + *type = MQTT_PROP_TYPE_BYTE; + }else{ + return MOSQ_ERR_INVAL; + } + return MOSQ_ERR_SUCCESS; +} From b462115fa6d07dfa9848e5d6268176aaa9d8f5b1 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 31 Oct 2018 08:24:28 +0000 Subject: [PATCH 073/254] Add reason code to PUBACK/REC/REL/COMP. --- lib/send_mosq.c | 14 ++++++++------ lib/send_mosq.h | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/send_mosq.c b/lib/send_mosq.c index a29d091934..9bf441a1e4 100644 --- a/lib/send_mosq.c +++ b/lib/send_mosq.c @@ -73,7 +73,7 @@ int send__puback(struct mosquitto *mosq, uint16_t mid) if(mosq) log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBACK (Mid: %d)", mosq->id, mid); #endif /* We don't use Reason String or User Property yet. */ - return send__command_with_mid(mosq, CMD_PUBACK, mid, false, NULL); + return send__command_with_mid(mosq, CMD_PUBACK, mid, false, 0, NULL); } int send__pubcomp(struct mosquitto *mosq, uint16_t mid) @@ -84,7 +84,7 @@ int send__pubcomp(struct mosquitto *mosq, uint16_t mid) if(mosq) log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBCOMP (Mid: %d)", mosq->id, mid); #endif /* We don't use Reason String or User Property yet. */ - return send__command_with_mid(mosq, CMD_PUBCOMP, mid, false, NULL); + return send__command_with_mid(mosq, CMD_PUBCOMP, mid, false, 0, NULL); } @@ -96,7 +96,7 @@ int send__pubrec(struct mosquitto *mosq, uint16_t mid) if(mosq) log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBREC (Mid: %d)", mosq->id, mid); #endif /* We don't use Reason String or User Property yet. */ - return send__command_with_mid(mosq, CMD_PUBREC, mid, false, NULL); + return send__command_with_mid(mosq, CMD_PUBREC, mid, false, 0, NULL); } int send__pubrel(struct mosquitto *mosq, uint16_t mid) @@ -107,11 +107,11 @@ int send__pubrel(struct mosquitto *mosq, uint16_t mid) if(mosq) log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBREL (Mid: %d)", mosq->id, mid); #endif /* We don't use Reason String or User Property yet. */ - return send__command_with_mid(mosq, CMD_PUBREL|2, mid, false, NULL); + return send__command_with_mid(mosq, CMD_PUBREL|2, mid, false, 0, NULL); } /* For PUBACK, PUBCOMP, PUBREC, and PUBREL */ -int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup, struct mqtt5__property *properties) +int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup, uint8_t reason_code, struct mqtt5__property *properties) { struct mosquitto__packet *packet = NULL; int rc; @@ -130,7 +130,8 @@ int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid if(mosq->protocol == mosq_p_mqtt5){ proplen = property__get_length_all(properties); varbytes = packet__varint_bytes(proplen); - packet->remaining_length += varbytes + proplen; + /* 1 here is sizeof(reason_code) */ + packet->remaining_length += 1 + varbytes + proplen; } rc = packet__alloc(packet); @@ -142,6 +143,7 @@ int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid packet__write_uint16(packet, mid); if(mosq->protocol == mosq_p_mqtt5){ + packet__write_byte(packet, reason_code); property__write_all(packet, properties); } diff --git a/lib/send_mosq.h b/lib/send_mosq.h index 7ea0b12bb3..34b1b8788b 100644 --- a/lib/send_mosq.h +++ b/lib/send_mosq.h @@ -20,7 +20,7 @@ and the Eclipse Distribution License is available at #include "property_mosq.h" int send__simple_command(struct mosquitto *mosq, uint8_t command); -int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup, struct mqtt5__property *properties); +int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup, uint8_t reason_code, struct mqtt5__property *properties); int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, struct mqtt5__property *properties); int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session); From 12cba75c734d948ba21a7f68d724741f6b3502ed Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 31 Oct 2018 12:38:39 +0000 Subject: [PATCH 074/254] Client support for adding properties. --- client/CMakeLists.txt | 2 +- client/Makefile | 7 +- client/client_props.c | 185 +++++++++++++++++++ client/client_shared.c | 16 +- client/client_shared.h | 8 + client/pub_client.c | 13 +- client/sub_client.c | 5 +- lib/actions.c | 20 +- lib/connect.c | 26 ++- lib/linker.version | 9 + lib/mosquitto.h | 316 +++++++++++++++++++++++++++++++- lib/property_mosq.c | 244 +++++++++++++++++++++++- lib/property_mosq.h | 6 +- lib/send_connect.c | 3 +- lib/send_disconnect.c | 3 +- lib/send_mosq.c | 2 +- lib/send_mosq.h | 12 +- lib/send_publish.c | 4 +- lib/send_subscribe.c | 3 +- lib/socks_mosq.c | 2 +- man/mosquitto_pub.1.xml | 91 +++++++++ man/mosquitto_sub.1.xml | 92 ++++++++++ src/CMakeLists.txt | 1 + src/Makefile | 4 + src/bridge.c | 4 +- src/handle_connack.c | 2 +- src/handle_unsubscribe.c | 2 +- src/mosquitto_broker_internal.h | 1 + src/send_unsuback.c | 60 ++++++ test/mosq_test.py | 33 ++-- 30 files changed, 1101 insertions(+), 75 deletions(-) create mode 100644 client/client_props.c create mode 100644 src/send_unsuback.c diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index a6b2c01891..39a12d1d3a 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -2,7 +2,7 @@ include_directories(${mosquitto_SOURCE_DIR} ${mosquitto_SOURCE_DIR}/lib ${STDBOOL_H_PATH} ${STDINT_H_PATH}) link_directories(${mosquitto_BINARY_DIR}/lib) -set(shared_src client_shared.c client_shared.h) +set(shared_src client_shared.c client_shared.h client_props.c) if (${WITH_SRV} STREQUAL ON) add_definitions("-DWITH_SRV") diff --git a/client/Makefile b/client/Makefile index 02ac608726..4ffc46b153 100644 --- a/client/Makefile +++ b/client/Makefile @@ -14,10 +14,10 @@ static_pub : pub_client.o client_shared.o ../lib/libmosquitto.a static_sub : sub_client.o sub_client_output.o client_shared.o ../lib/libmosquitto.a ${CROSS_COMPILE}${CC} $^ -o mosquitto_sub ${CLIENT_LDFLAGS} -lssl -lcrypto -lpthread -mosquitto_pub : pub_client.o client_shared.o +mosquitto_pub : pub_client.o client_shared.o client_props.o ${CROSS_COMPILE}${CC} $^ -o $@ ${CLIENT_LDFLAGS} -mosquitto_sub : sub_client.o sub_client_output.o client_shared.o +mosquitto_sub : sub_client.o sub_client_output.o client_shared.o client_props.o ${CROSS_COMPILE}${CC} $^ -o $@ ${CLIENT_LDFLAGS} pub_client.o : pub_client.c ../lib/libmosquitto.so.${SOVERSION} @@ -32,6 +32,9 @@ sub_client_output.o : sub_client_output.c ../lib/libmosquitto.so.${SOVERSION} client_shared.o : client_shared.c client_shared.h ${CROSS_COMPILE}${CC} -c $< -o $@ ${CLIENT_CFLAGS} +client_props.o : client_props.c client_shared.h + ${CROSS_COMPILE}${CC} -c $< -o $@ ${CLIENT_CFLAGS} + ../lib/libmosquitto.so.${SOVERSION} : $(MAKE) -C ../lib diff --git a/client/client_props.c b/client/client_props.c new file mode 100644 index 0000000000..908fbb0f73 --- /dev/null +++ b/client/client_props.c @@ -0,0 +1,185 @@ +/* +Copyright (c) 2018 Roger Light + +All rights reserved. This program and the accompanying materials +are made available under the terms of the Eclipse Public License v1.0 +and Eclipse Distribution License v1.0 which accompany this distribution. + +The Eclipse Public License is available at + http://www.eclipse.org/legal/epl-v10.html +and the Eclipse Distribution License is available at + http://www.eclipse.org/org/documents/edl-v10.php. + +Contributors: + Roger Light - initial implementation and documentation. +*/ + +#include "config.h" + +#include +#include +#include +#include +#include +#ifndef WIN32 +#include +#include +#else +#include +#include +#define snprintf sprintf_s +#define strncasecmp _strnicmp +#endif + +#include "mosquitto.h" +#include "mqtt_protocol.h" +#include "client_shared.h" + +enum prop_type +{ + PROP_TYPE_BYTE, + PROP_TYPE_INT16, + PROP_TYPE_INT32, + PROP_TYPE_BINARY, + PROP_TYPE_STRING, + PROP_TYPE_STRING_PAIR +}; + +/* This parses property inputs. It should work for any command type, but is limited at the moment. + * + * Format: + * + * command property value + * command property key value + * + * Example: + * + * publish message-expiry-interval 32 + * connect user-property key value + */ + +int cfg_parse_property(struct mosq_config *cfg, int argc, char *argv[], int *idx) +{ + char *cmdname = NULL, *propname = NULL; + char *key = NULL, *value = NULL; + int cmd, identifier, type; + mosquitto_property **proplist; + int rc; + + /* idx now points to "command" */ + if((*idx)+2 > argc-1){ + /* Not enough args */ + fprintf(stderr, "Error: --property argument given but not enough arguments specified.\n\n"); + return MOSQ_ERR_INVAL; + } + + cmdname = argv[*idx]; + if(mosquitto_string_to_command(cmdname, &cmd)){ + fprintf(stderr, "Error: Invalid command given in --property argument.\n\n"); + return MOSQ_ERR_INVAL; + } + + propname = argv[(*idx)+1]; + if(mosquitto_string_to_property_info(propname, &identifier, &type)){ + fprintf(stderr, "Error: Invalid property name given in --property argument.\n\n"); + return MOSQ_ERR_INVAL; + } + + if(identifier == MQTT_PROP_USER_PROPERTY){ + if((*idx)+3 > argc-1){ + /* Not enough args */ + fprintf(stderr, "Error: --property argument given but not enough arguments specified.\n\n"); + return MOSQ_ERR_INVAL; + } + + key = argv[(*idx)+2]; + value = argv[(*idx)+3]; + (*idx) += 3; + }else{ + value = argv[(*idx)+2]; + (*idx) += 2; + } + + + switch(cmd){ + case CMD_CONNECT: + proplist = &cfg->connect_props; + break; + + case CMD_PUBLISH: + if(identifier == MQTT_PROP_SUBSCRIPTION_IDENTIFIER){ + fprintf(stderr, "Error: %s property not supported for %s in --property argument.\n\n", propname, cmdname); + return MOSQ_ERR_INVAL; + } + proplist = &cfg->publish_props; + break; + + case CMD_SUBSCRIBE: + if(identifier != MQTT_PROP_USER_PROPERTY){ + fprintf(stderr, "Error: %s property not supported for %s in --property argument.\n\n", propname, cmdname); + return MOSQ_ERR_NOT_SUPPORTED; + } + proplist = &cfg->subscribe_props; + break; + + case CMD_UNSUBSCRIBE: + proplist = &cfg->subscribe_props; + break; + + case CMD_DISCONNECT: + proplist = &cfg->disconnect_props; + break; + + case CMD_AUTH: + fprintf(stderr, "Error: %s property not supported for %s in --property argument.\n\n", propname, cmdname); + return MOSQ_ERR_NOT_SUPPORTED; + + case CMD_WILL: + proplist = &cfg->will_props; + break; + + case CMD_PUBACK: + case CMD_PUBREC: + case CMD_PUBREL: + case CMD_PUBCOMP: + case CMD_SUBACK: + case CMD_UNSUBACK: + fprintf(stderr, "Error: %s property not supported for %s in --property argument.\n\n", propname, cmdname); + return MOSQ_ERR_NOT_SUPPORTED; + + default: + return MOSQ_ERR_INVAL; + } + + switch(type){ + case MQTT_PROP_TYPE_BYTE: + rc = mosquitto_property_add_byte(proplist, identifier, atoi(value)); + break; + case MQTT_PROP_TYPE_INT16: + rc = mosquitto_property_add_int16(proplist, identifier, atoi(value)); + break; + case MQTT_PROP_TYPE_INT32: + rc = mosquitto_property_add_int32(proplist, identifier, atoi(value)); + break; + case MQTT_PROP_TYPE_VARINT: + rc = mosquitto_property_add_varint(proplist, identifier, atoi(value)); + break; + case MQTT_PROP_TYPE_BINARY: + rc = mosquitto_property_add_binary(proplist, identifier, value, strlen(value)); + break; + case MQTT_PROP_TYPE_STRING: + rc = mosquitto_property_add_string(proplist, identifier, value); + break; + case MQTT_PROP_TYPE_STRING_PAIR: + rc = mosquitto_property_add_string_pair(proplist, identifier, key, value); + break; + default: + return MOSQ_ERR_INVAL; + } + if(rc){ + fprintf(stderr, "Error adding property %s %d\n", propname, type); + return rc; + } + return MOSQ_ERR_SUCCESS; +} + diff --git a/client/client_shared.c b/client/client_shared.c index 253ef1619f..aa2529aa51 100644 --- a/client/client_shared.c +++ b/client/client_shared.c @@ -179,6 +179,12 @@ void client_config_cleanup(struct mosq_config *cfg) free(cfg->socks5_username); free(cfg->socks5_password); #endif + mosquitto_property_free_all(&cfg->connect_props); + mosquitto_property_free_all(&cfg->publish_props); + mosquitto_property_free_all(&cfg->subscribe_props); + mosquitto_property_free_all(&cfg->unsubscribe_props); + mosquitto_property_free_all(&cfg->disconnect_props); + mosquitto_property_free_all(&cfg->will_props); } int client_config_load(struct mosq_config *cfg, int pub_or_sub, int argc, char *argv[]) @@ -877,6 +883,12 @@ int client_config_line_proc(struct mosq_config *cfg, int pub_or_sub, int argc, c goto unknown_option; } cfg->verbose = 1; + }else if(!strcmp(argv[i], "-y") || !strcmp(argv[i], "--property")){ + i++; + if(cfg_parse_property(cfg, argc, argv, &i)){ + return 1; + } + cfg->protocol_version = MQTT_PROTOCOL_V5; }else{ goto unknown_option; } @@ -1006,10 +1018,10 @@ int client_connect(struct mosquitto *mosq, struct mosq_config *cfg) if(cfg->use_srv){ rc = mosquitto_connect_srv(mosq, cfg->host, cfg->keepalive, cfg->bind_address); }else{ - rc = mosquitto_connect_bind(mosq, cfg->host, port, cfg->keepalive, cfg->bind_address); + rc = mosquitto_connect_bind_with_properties(mosq, cfg->host, port, cfg->keepalive, cfg->bind_address, cfg->connect_props); } #else - rc = mosquitto_connect_bind(mosq, cfg->host, port, cfg->keepalive, cfg->bind_address); + rc = mosquitto_connect_bind_with_properties(mosq, cfg->host, port, cfg->keepalive, cfg->bind_address, cfg->connect_props); #endif if(rc>0){ if(!cfg->quiet){ diff --git a/client/client_shared.h b/client/client_shared.h index 0676229325..18adcf3f26 100644 --- a/client/client_shared.h +++ b/client/client_shared.h @@ -92,6 +92,12 @@ struct mosq_config { char *socks5_username; char *socks5_password; #endif + mosquitto_property *connect_props; + mosquitto_property *publish_props; + mosquitto_property *subscribe_props; + mosquitto_property *unsubscribe_props; + mosquitto_property *disconnect_props; + mosquitto_property *will_props; }; int client_config_load(struct mosq_config *config, int pub_or_sub, int argc, char *argv[]); @@ -100,4 +106,6 @@ int client_opts_set(struct mosquitto *mosq, struct mosq_config *cfg); int client_id_generate(struct mosq_config *cfg, const char *id_base); int client_connect(struct mosquitto *mosq, struct mosq_config *cfg); +int cfg_parse_property(struct mosq_config *cfg, int argc, char *argv[], int *idx); + #endif diff --git a/client/pub_client.c b/client/pub_client.c index 9fb38889c0..ffeb2ec185 100644 --- a/client/pub_client.c +++ b/client/pub_client.c @@ -54,6 +54,7 @@ static char *username = NULL; static char *password = NULL; static bool disconnect_sent = false; static bool quiet = false; +static struct mosq_config cfg; void my_connect_callback(struct mosquitto *mosq, void *obj, int result) { @@ -64,10 +65,10 @@ void my_connect_callback(struct mosquitto *mosq, void *obj, int result) case MSGMODE_CMD: case MSGMODE_FILE: case MSGMODE_STDIN_FILE: - rc = mosquitto_publish(mosq, &mid_sent, topic, msglen, message, qos, retain); + rc = mosquitto_publish_with_properties(mosq, &mid_sent, topic, msglen, message, qos, retain, cfg.publish_props); break; case MSGMODE_NULL: - rc = mosquitto_publish(mosq, &mid_sent, topic, 0, NULL, qos, retain); + rc = mosquitto_publish_with_properties(mosq, &mid_sent, topic, 0, NULL, qos, retain, cfg.publish_props); break; case MSGMODE_STDIN_LINE: status = STATUS_CONNACK_RECVD; @@ -230,6 +231,8 @@ void print_usage(void) #ifdef WITH_SOCKS printf(" [--proxy socks-url]\n"); #endif + printf(" [--property command identifier value]\n"); + printf(" [-y command identifier value]\n"); printf(" mosquitto_pub --help\n\n"); printf(" -A : bind the outgoing socket to this host/ip address. Use to control which interface\n"); printf(" the client communicates over.\n"); @@ -258,6 +261,7 @@ void print_usage(void) printf(" -u : provide a username\n"); printf(" -V : specify the version of the MQTT protocol to use when connecting.\n"); printf(" Can be mqttv5, mqttv311 or mqttv31. Defaults to mqttv311.\n"); + printf(" -y,--property : Add MQTT v5 properties. See the documentation for more details.\n"); printf(" --help : display this message.\n"); printf(" --quiet : don't print error messages.\n"); printf(" --will-payload : payload for the client Will, which is sent by the broker in case of\n"); @@ -290,12 +294,11 @@ void print_usage(void) printf(" socks5h://[username[:password]@]hostname[:port]\n"); printf(" Only \"none\" and \"username\" authentication is supported.\n"); #endif - printf("\nSee http://mosquitto.org/ for more information.\n\n"); + printf("\nSee https://mosquitto.org/ for more information.\n\n"); } int main(int argc, char *argv[]) { - struct mosq_config cfg; struct mosquitto *mosq = NULL; int rc; int rc2; @@ -413,7 +416,7 @@ int main(int argc, char *argv[]) buf_len_actual = strlen(buf); if(buf[buf_len_actual-1] == '\n'){ buf[buf_len_actual-1] = '\0'; - rc2 = mosquitto_publish(mosq, &mid_sent, topic, buf_len_actual-1, buf, qos, retain); + rc2 = mosquitto_publish_with_properties(mosq, &mid_sent, topic, buf_len_actual-1, buf, qos, retain, cfg.publish_props); if(rc2){ if(!quiet) fprintf(stderr, "Error: Publish returned %d, disconnecting.\n", rc2); mosquitto_disconnect(mosq); diff --git a/client/sub_client.c b/client/sub_client.c index 4495849dcb..5e9a972db3 100644 --- a/client/sub_client.c +++ b/client/sub_client.c @@ -96,7 +96,7 @@ void my_connect_callback(struct mosquitto *mosq, void *obj, int result, int flag cfg = (struct mosq_config *)obj; if(!result){ - mosquitto_subscribe_multiple(mosq, NULL, cfg->topic_count, cfg->topics, cfg->qos); + mosquitto_subscribe_multiple(mosq, NULL, cfg->topic_count, cfg->topics, cfg->qos, cfg->subscribe_props); for(i=0; iunsub_topic_count; i++){ mosquitto_unsubscribe(mosq, NULL, cfg->unsub_topics[i]); @@ -165,6 +165,8 @@ void print_usage(void) #ifdef WITH_SOCKS printf(" [--proxy socks-url]\n"); #endif + printf(" [-y command identifier value]\n"); + printf(" [--property command identifier value]\n"); printf(" mosquitto_sub --help\n\n"); printf(" -A : bind the outgoing socket to this host/ip address. Use to control which interface\n"); printf(" the client communicates over.\n"); @@ -198,6 +200,7 @@ void print_usage(void) #ifndef WIN32 printf(" -W : Specifies a timeout in seconds how long to process incoming MQTT messages.\n"); #endif + printf(" -y, --property : Add MQTT v5 properties. See the documentation for more details.\n"); printf(" --help : display this message.\n"); printf(" --quiet : don't print error messages.\n"); printf(" --retained-only : only handle messages with the retained flag set, and exit when the\n"); diff --git a/lib/actions.c b/lib/actions.c index 7a48f3cc26..c6bdef5c44 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -29,6 +29,11 @@ and the Eclipse Distribution License is available at int mosquitto_publish(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, const void *payload, int qos, bool retain) +{ + return mosquitto_publish_with_properties(mosq, mid, topic, payloadlen, payload, qos, retain, NULL); +} + +int mosquitto_publish_with_properties(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, const void *payload, int qos, bool retain, const mosquitto_property *properties) { struct mosquitto_message_all *message; uint16_t local_mid; @@ -49,7 +54,7 @@ int mosquitto_publish(struct mosquitto *mosq, int *mid, const char *topic, int p } if(qos == 0){ - return send__publish(mosq, local_mid, topic, payloadlen, payload, qos, retain, false, NULL); + return send__publish(mosq, local_mid, topic, payloadlen, payload, qos, retain, false, properties); }else{ message = mosquitto__calloc(1, sizeof(struct mosquitto_message_all)); if(!message) return MOSQ_ERR_NOMEM; @@ -87,7 +92,7 @@ int mosquitto_publish(struct mosquitto *mosq, int *mid, const char *topic, int p message->state = mosq_ms_wait_for_pubrec; } pthread_mutex_unlock(&mosq->out_message_mutex); - return send__publish(mosq, message->msg.mid, message->msg.topic, message->msg.payloadlen, message->msg.payload, message->msg.qos, message->msg.retain, message->dup, NULL); + return send__publish(mosq, message->msg.mid, message->msg.topic, message->msg.payloadlen, message->msg.payload, message->msg.qos, message->msg.retain, message->dup, properties); }else{ message->state = mosq_ms_invalid; pthread_mutex_unlock(&mosq->out_message_mutex); @@ -98,6 +103,11 @@ int mosquitto_publish(struct mosquitto *mosq, int *mid, const char *topic, int p int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const char *sub, int qos) +{ + return mosquitto_subscribe_with_properties(mosq, mid, sub, qos, NULL); +} + +int mosquitto_subscribe_with_properties(struct mosquitto *mosq, int *mid, const char *sub, int qos, const mosquitto_property *properties) { if(!mosq) return MOSQ_ERR_INVAL; if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; @@ -105,11 +115,11 @@ int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const char *sub, int q if(mosquitto_sub_topic_check(sub)) return MOSQ_ERR_INVAL; if(mosquitto_validate_utf8(sub, strlen(sub))) return MOSQ_ERR_MALFORMED_UTF8; - return send__subscribe(mosq, mid, 1, (char *const *const)&sub, qos); + return send__subscribe(mosq, mid, 1, (char *const *const)&sub, qos, properties); } -int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, int qos) +int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, int qos, const mosquitto_property *properties) { int i; @@ -122,7 +132,7 @@ int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count if(mosquitto_validate_utf8(sub[i], strlen(sub[i]))) return MOSQ_ERR_MALFORMED_UTF8; } - return send__subscribe(mosq, mid, sub_count, sub, qos); + return send__subscribe(mosq, mid, sub_count, sub, qos, properties); } diff --git a/lib/connect.c b/lib/connect.c index fe084e31e0..88eecca344 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -26,7 +26,7 @@ and the Eclipse Distribution License is available at #include "send_mosq.h" #include "socks_mosq.h" -static int mosquitto__reconnect(struct mosquitto *mosq, bool blocking); +static int mosquitto__reconnect(struct mosquitto *mosq, bool blocking, const struct mqtt5__property *properties); static int mosquitto__connect_init(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address); @@ -73,6 +73,11 @@ int mosquitto_connect(struct mosquitto *mosq, const char *host, int port, int ke int mosquitto_connect_bind(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address) +{ + return mosquitto_connect_bind_with_properties(mosq, host, port, keepalive, bind_address, NULL); +} + +int mosquitto_connect_bind_with_properties(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address, const mosquitto_property *properties) { int rc; rc = mosquitto__connect_init(mosq, host, port, keepalive, bind_address); @@ -82,7 +87,7 @@ int mosquitto_connect_bind(struct mosquitto *mosq, const char *host, int port, i mosq->state = mosq_cs_new; pthread_mutex_unlock(&mosq->state_mutex); - return mosquitto__reconnect(mosq, true); + return mosquitto__reconnect(mosq, true, properties); } @@ -101,23 +106,23 @@ int mosquitto_connect_bind_async(struct mosquitto *mosq, const char *host, int p mosq->state = mosq_cs_connect_async; pthread_mutex_unlock(&mosq->state_mutex); - return mosquitto__reconnect(mosq, false); + return mosquitto__reconnect(mosq, false, NULL); } int mosquitto_reconnect_async(struct mosquitto *mosq) { - return mosquitto__reconnect(mosq, false); + return mosquitto__reconnect(mosq, false, NULL); } int mosquitto_reconnect(struct mosquitto *mosq) { - return mosquitto__reconnect(mosq, true); + return mosquitto__reconnect(mosq, true, NULL); } -static int mosquitto__reconnect(struct mosquitto *mosq, bool blocking) +static int mosquitto__reconnect(struct mosquitto *mosq, bool blocking, const mosquitto_property *properties) { int rc; struct mosquitto__packet *packet; @@ -193,12 +198,17 @@ static int mosquitto__reconnect(struct mosquitto *mosq, bool blocking) }else #endif { - return send__connect(mosq, mosq->keepalive, mosq->clean_session); + return send__connect(mosq, mosq->keepalive, mosq->clean_session, properties); } } int mosquitto_disconnect(struct mosquitto *mosq) +{ + return mosquitto_disconnect_with_properties(mosq, NULL); +} + +int mosquitto_disconnect_with_properties(struct mosquitto *mosq, const mosquitto_property *properties) { if(!mosq) return MOSQ_ERR_INVAL; @@ -207,6 +217,6 @@ int mosquitto_disconnect(struct mosquitto *mosq) pthread_mutex_unlock(&mosq->state_mutex); if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; - return send__disconnect(mosq); + return send__disconnect(mosq, properties); } diff --git a/lib/linker.version b/lib/linker.version index 347beeccbe..9ec233cca9 100644 --- a/lib/linker.version +++ b/lib/linker.version @@ -94,8 +94,17 @@ MOSQ_1.5 { MOSQ_1.6 { global: + mosquitto_connect_bind_with_properties; + mosquitto_property_add_binary; + mosquitto_property_add_byte; + mosquitto_property_add_int16; + mosquitto_property_add_int32; + mosquitto_property_add_string; + mosquitto_property_add_string_pair; + mosquitto_property_add_varint; mosquitto_property_free_all; mosquitto_property_command_check; + mosquitto_publish_with_properties; mosquitto_string_to_command; mosquitto_string_to_property_info; mosquitto_subscribe_multiple; diff --git a/lib/mosquitto.h b/lib/mosquitto.h index 338baa8876..c7ba275d86 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -44,6 +44,7 @@ extern "C" { #endif #include +#include #define LIBMOSQUITTO_MAJOR 1 #define LIBMOSQUITTO_MINOR 5 @@ -423,6 +424,37 @@ libmosq_EXPORT int mosquitto_connect(struct mosquitto *mosq, const char *host, i */ libmosq_EXPORT int mosquitto_connect_bind(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address); +/* + * Function: mosquitto_connect_bind_with_properties + * + * Connect to an MQTT broker. This extends the functionality of + * by adding the bind_address parameter. Use this function + * if you need to restrict network communication over a particular interface. + * + * Parameters: + * mosq - a valid mosquitto instance. + * host - the hostname or ip address of the broker to connect to. + * port - the network port to connect to. Usually 1883. + * 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. + * bind_address - the hostname or ip address of the local network interface to + * bind to. + * properties - the MQTT 5 properties for the connect (not for the Will). + * + * 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 + * Windows. + * + * See Also: + * , , + */ +libmosq_EXPORT int mosquitto_connect_bind_with_properties(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address, const mosquitto_property *properties); + /* * Function: mosquitto_connect_async * @@ -604,6 +636,26 @@ libmosq_EXPORT int mosquitto_reconnect_async(struct mosquitto *mosq); */ libmosq_EXPORT int mosquitto_disconnect(struct mosquitto *mosq); +/* + * Function: mosquitto_disconnect_with_properties + * + * Disconnect from the broker, with attached MQTT properties. + * + * Use to create a list of properties, then attach + * them to this publish. Properties need freeing with + * . + * + * Parameters: + * mosq - a valid mosquitto instance. + * properties - a valid mosquitto_property list, or NULL. + * + * Returns: + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. + */ +libmosq_EXPORT int mosquitto_disconnect_with_properties(struct mosquitto *mosq, const mosquitto_property *properties); + /* ====================================================================== * @@ -648,6 +700,58 @@ libmosq_EXPORT int mosquitto_disconnect(struct mosquitto *mosq); */ libmosq_EXPORT int mosquitto_publish(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, const void *payload, int qos, bool retain); + +/* + * Function: mosquitto_publish_with_properties + * + * Publish a message on a given topic, with attached MQTT properties. + * + * Use to create a list of properties, then attach + * them to this publish. Properties need freeing with + * . + * + * Requires the mosquitto instance to be connected with MQTT 5. + * + * Parameters: + * mosq - a valid mosquitto instance. + * mid - pointer to an int. If not NULL, the function will set this + * to the message id of this particular message. This can be then + * used with the publish callback to determine when the message + * has been sent. + * Note that although the MQTT protocol doesn't use message ids + * for messages with QoS=0, libmosquitto assigns them message ids + * so they can be tracked with this parameter. + * topic - null terminated string of the topic to publish to. + * payloadlen - the size of the payload (bytes). Valid values are between 0 and + * 268,435,455. + * payload - pointer to the data to send. If payloadlen > 0 this must be a + * valid memory location. + * qos - integer value 0, 1 or 2 indicating the Quality of Service to be + * used for the message. + * retain - set to true to make the message retained. + * properties - a valid mosquitto_property list, or NULL. + * + * 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_PROTOCOL - if there is a protocol error communicating with the + * broker. + * MOSQ_ERR_PAYLOAD_SIZE - if payloadlen is too large. + * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8 + */ +libmosq_EXPORT int mosquitto_publish_with_properties( + struct mosquitto *mosq, + int *mid, + const char *topic, + int payloadlen, + const void *payload, + int qos, + bool retain, + const mosquitto_property *properties); + + /* * Function: mosquitto_subscribe * @@ -671,6 +775,37 @@ libmosq_EXPORT int mosquitto_publish(struct mosquitto *mosq, int *mid, const cha */ libmosq_EXPORT int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const char *sub, int qos); +/* + * Function: mosquitto_subscribe_with_properties + * + * Subscribe to a topic, with attached MQTT properties. + * + * Use to create a list of properties, then attach + * them to this subscribe. Properties need freeing with + * . + * + * Requires the mosquitto instance to be connected with MQTT 5. + * + * + * Parameters: + * mosq - a valid mosquitto instance. + * mid - a pointer to an int. If not NULL, the function will set this to + * the message id of this particular message. This can be then used + * with the subscribe callback to determine when the message has been + * sent. + * sub - the subscription pattern. + * qos - the requested Quality of Service for this subscription. + * properties - a valid mosquitto_property list, or NULL. + * + * 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_MALFORMED_UTF8 - if the topic is not valid UTF-8 + */ +libmosq_EXPORT int mosquitto_subscribe_with_properties(struct mosquitto *mosq, int *mid, const char *sub, int qos, const mosquitto_property *properties); + /* * Function: mosquitto_subscribe_multiple * @@ -689,6 +824,8 @@ libmosq_EXPORT int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const c * familiar with this, just think of it as a safer "char **", * equivalent to "const char *" for a simple string pointer. * qos - the requested Quality of Service for each subscription. + * properties - a valid mosquitto_property list, or NULL. Only used with MQTT + * v5 clients. * * Returns: * MOSQ_ERR_SUCCESS - on success. @@ -697,7 +834,7 @@ libmosq_EXPORT int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const c * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. * MOSQ_ERR_MALFORMED_UTF8 - if a topic is not valid UTF-8 */ -int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, int qos); +int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, int qos, const mosquitto_property *properties); /* * Function: mosquitto_unsubscribe @@ -1901,6 +2038,179 @@ libmosq_EXPORT int mosquitto_validate_utf8(const char *str, int len); * ============================================================================= */ + +/* + * Function: mosquitto_property_add_byte + * + * Add a new byte property to a property list. + * + * If *proplist == NULL, a new list will be created, otherwise the new property + * will be appended to the list. + * + * Parameters: + * proplist - pointer to mosquitto_property pointer, the list of properties + * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) + * value - integer value for the new property + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if identifier is invalid, or if proplist is NULL + * MOSQ_ERR_NOMEM - on out of memory + * + * Example: + * mosquitto_property *proplist = NULL; + * mosquitto_property_add_byte(&proplist, MQTT_PROP_PAYLOAD_FORMAT_IDENTIFIER, 1); + */ +libmosq_EXPORT int mosquitto_property_add_byte(mosquitto_property **proplist, int identifier, uint8_t value); + +/* + * Function: mosquitto_property_add_int16 + * + * Add a new int16 property to a property list. + * + * If *proplist == NULL, a new list will be created, otherwise the new property + * will be appended to the list. + * + * Parameters: + * proplist - pointer to mosquitto_property pointer, the list of properties + * identifier - property identifier (e.g. MQTT_PROP_RECEIVE_MAXIMUM) + * value - integer value for the new property + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if identifier is invalid, or if proplist is NULL + * MOSQ_ERR_NOMEM - on out of memory + * + * Example: + * mosquitto_property *proplist = NULL; + * mosquitto_property_add_int16(&proplist, MQTT_PROP_RECEIVE_MAXIMUM, 1000); + */ +libmosq_EXPORT int mosquitto_property_add_int16(mosquitto_property **proplist, int identifier, uint16_t value); + +/* + * Function: mosquitto_property_add_int32 + * + * Add a new int32 property to a property list. + * + * If *proplist == NULL, a new list will be created, otherwise the new property + * will be appended to the list. + * + * Parameters: + * proplist - pointer to mosquitto_property pointer, the list of properties + * identifier - property identifier (e.g. MQTT_PROP_MESSAGE_EXPIRY_INTERVAL) + * value - integer value for the new property + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if identifier is invalid, or if proplist is NULL + * MOSQ_ERR_NOMEM - on out of memory + * + * Example: + * mosquitto_property *proplist = NULL; + * mosquitto_property_add_int32(&proplist, MQTT_PROP_MESSAGE_EXPIRY_INTERVAL, 86400); + */ +libmosq_EXPORT int mosquitto_property_add_int32(mosquitto_property **proplist, int identifier, uint32_t value); + +/* + * Function: mosquitto_property_add_varint + * + * Add a new varint property to a property list. + * + * If *proplist == NULL, a new list will be created, otherwise the new property + * will be appended to the list. + * + * Parameters: + * proplist - pointer to mosquitto_property pointer, the list of properties + * identifier - property identifier (e.g. MQTT_PROP_SUBSCRIPTION_IDENTIFIER) + * value - integer value for the new property + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if identifier is invalid, or if proplist is NULL + * MOSQ_ERR_NOMEM - on out of memory + * + * Example: + * mosquitto_property *proplist = NULL; + * mosquitto_property_add_varint(&proplist, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 1); + */ +libmosq_EXPORT int mosquitto_property_add_varint(mosquitto_property **proplist, int identifier, uint32_t value); + +/* + * Function: mosquitto_property_add_binary + * + * Add a new binary property to a property list. + * + * If *proplist == NULL, a new list will be created, otherwise the new property + * will be appended to the list. + * + * Parameters: + * proplist - pointer to mosquitto_property pointer, the list of properties + * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) + * value - pointer to the property data + * len - length of property data in bytes + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if identifier is invalid, or if proplist is NULL + * MOSQ_ERR_NOMEM - on out of memory + * + * Example: + * mosquitto_property *proplist = NULL; + * mosquitto_property_add_binary(&proplist, MQTT_PROP_AUTHENTICATION_DATA, auth_data, auth_data_len); + */ +libmosq_EXPORT int mosquitto_property_add_binary(mosquitto_property **proplist, int identifier, const void *value, uint16_t len); + +/* + * Function: mosquitto_property_add_string + * + * Add a new string property to a property list. + * + * If *proplist == NULL, a new list will be created, otherwise the new property + * will be appended to the list. + * + * Parameters: + * proplist - pointer to mosquitto_property pointer, the list of properties + * identifier - property identifier (e.g. MQTT_PROP_CONTENT_TYPE) + * value - string value for the new property, must be UTF-8 and zero terminated + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if identifier is invalid, if value is NULL, or if proplist is NULL + * MOSQ_ERR_NOMEM - on out of memory + * MOSQ_ERR_MALFORMED_UTF8 - value is not valid UTF-8. + * + * Example: + * mosquitto_property *proplist = NULL; + * mosquitto_property_add_string(&proplist, MQTT_PROP_CONTENT_TYPE, "application/json"); + */ +libmosq_EXPORT int mosquitto_property_add_string(mosquitto_property **proplist, int identifier, const char *value); + +/* + * Function: mosquitto_property_add_string_pair + * + * Add a new string pair property to a property list. + * + * If *proplist == NULL, a new list will be created, otherwise the new property + * will be appended to the list. + * + * Parameters: + * proplist - pointer to mosquitto_property pointer, the list of properties + * identifier - property identifier (e.g. MQTT_PROP_USER_PROPERTY) + * name - string name for the new property, must be UTF-8 and zero terminated + * value - string value for the new property, must be UTF-8 and zero terminated + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if identifier is invalid, if name or value is NULL, or if proplist is NULL + * MOSQ_ERR_NOMEM - on out of memory + * MOSQ_ERR_MALFORMED_UTF8 - if name or value are not valid UTF-8. + * + * Example: + * mosquitto_property *proplist = NULL; + * mosquitto_property_add_string_pair(&proplist, MQTT_PROP_USER_PROPERTY, "client", "mosquitto_pub"); + */ +libmosq_EXPORT int mosquitto_property_add_string_pair(mosquitto_property **proplist, int identifier, const char *name, const char *value); + /* * Function: mosquitto_property_free_all * @@ -1929,7 +2239,7 @@ libmosq_EXPORT void mosquitto_property_free_all(mosquitto_property **properties) * MOSQ_ERR_SUCCESS - if the identifier is valid for command * MOSQ_ERR_PROTOCOL - if the identifier is not valid for use with command. */ -int mosquitto_property_command_check(int command, int identifier); +libmosq_EXPORT int mosquitto_property_command_check(int command, int identifier); /* Function: mosquitto_string_to_property_info * @@ -1951,7 +2261,7 @@ int mosquitto_property_command_check(int command, int identifier); * // id == MQTT_PROP_RESPONSE_TOPIC * // type == MQTT_PROP_TYPE_STRING */ -int mosquitto_string_to_property_info(const char *propname, int *identifier, int *type); +libmosq_EXPORT int mosquitto_string_to_property_info(const char *propname, int *identifier, int *type); #ifdef __cplusplus diff --git a/lib/property_mosq.c b/lib/property_mosq.c index b5556d7dbb..be8ef05e03 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -290,11 +290,12 @@ void mosquitto_property_free_all(struct mqtt5__property **property) } -int property__get_length(struct mqtt5__property *property) +int property__get_length(const struct mqtt5__property *property) { if(!property) return 0; switch(property->identifier){ + /* Byte */ case MQTT_PROP_PAYLOAD_FORMAT_INDICATOR: case MQTT_PROP_REQUEST_PROBLEM_INFORMATION: case MQTT_PROP_REQUEST_RESPONSE_INFORMATION: @@ -305,18 +306,21 @@ int property__get_length(struct mqtt5__property *property) case MQTT_PROP_SHARED_SUB_AVAILABLE: return 2; /* 1 (identifier) + 1 byte */ + /* uint16 */ case MQTT_PROP_SERVER_KEEP_ALIVE: case MQTT_PROP_RECEIVE_MAXIMUM: case MQTT_PROP_TOPIC_ALIAS_MAXIMUM: case MQTT_PROP_TOPIC_ALIAS: return 3; /* 1 (identifier) + 2 bytes */ + /* uint32 */ case MQTT_PROP_MESSAGE_EXPIRY_INTERVAL: case MQTT_PROP_WILL_DELAY_INTERVAL: case MQTT_PROP_MAXIMUM_PACKET_SIZE: case MQTT_PROP_SESSION_EXPIRY_INTERVAL: - return 5; /* 1 (identifier) + 5 bytes */ + return 5; /* 1 (identifier) + 4 bytes */ + /* varint */ case MQTT_PROP_SUBSCRIPTION_IDENTIFIER: if(property->value.varint < 128){ return 2; @@ -330,10 +334,12 @@ int property__get_length(struct mqtt5__property *property) return 0; } + /* binary */ case MQTT_PROP_CORRELATION_DATA: case MQTT_PROP_AUTHENTICATION_DATA: return 3 + property->value.bin.len; /* 1 + 2 bytes (len) + X bytes (payload) */ + /* string */ case MQTT_PROP_CONTENT_TYPE: case MQTT_PROP_RESPONSE_TOPIC: case MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER: @@ -343,6 +349,7 @@ int property__get_length(struct mqtt5__property *property) case MQTT_PROP_REASON_STRING: return 3 + property->value.s.len; /* 1 + 2 bytes (len) + X bytes (string) */ + /* string pair */ case MQTT_PROP_USER_PROPERTY: return 5 + property->value.s.len + property->name.len; /* 1 + 2*(2 bytes (len) + X bytes (string))*/ @@ -353,9 +360,9 @@ int property__get_length(struct mqtt5__property *property) } -int property__get_length_all(struct mqtt5__property *property) +int property__get_length_all(const struct mqtt5__property *property) { - struct mqtt5__property *p; + const struct mqtt5__property *p; int len = 0; p = property; @@ -367,7 +374,7 @@ int property__get_length_all(struct mqtt5__property *property) } -int property__write(struct mosquitto__packet *packet, struct mqtt5__property *property) +int property__write(struct mosquitto__packet *packet, const struct mqtt5__property *property) { int rc; @@ -417,6 +424,7 @@ int property__write(struct mosquitto__packet *packet, struct mqtt5__property *pr case MQTT_PROP_CORRELATION_DATA: packet__write_uint16(packet, property->value.bin.len); packet__write_bytes(packet, property->value.bin.v, property->value.bin.len); + break; case MQTT_PROP_USER_PROPERTY: packet__write_string(packet, property->name.v, property->name.len); @@ -432,10 +440,10 @@ int property__write(struct mosquitto__packet *packet, struct mqtt5__property *pr } -int property__write_all(struct mosquitto__packet *packet, struct mqtt5__property *properties) +int property__write_all(struct mosquitto__packet *packet, const struct mqtt5__property *properties) { int rc; - struct mqtt5__property *p; + const struct mqtt5__property *p; rc = packet__write_varint(packet, property__get_length_all(properties)); if(rc) return rc; @@ -648,3 +656,225 @@ int mosquitto_string_to_property_info(const char *propname, int *identifier, int } return MOSQ_ERR_SUCCESS; } + + +static void property__add(struct mqtt5__property **proplist, struct mqtt5__property *prop) +{ + struct mqtt5__property *p; + + if(!(*proplist)){ + *proplist = prop; + } + + p = *proplist; + while(p->next){ + p = p->next; + } + p->next = prop; + prop->next = NULL; +} + + +int mosquitto_property_add_byte(mosquitto_property **proplist, int identifier, uint8_t value) +{ + struct mqtt5__property *prop; + + if(!proplist) return MOSQ_ERR_INVAL; + if(identifier != MQTT_PROP_PAYLOAD_FORMAT_INDICATOR + && identifier != MQTT_PROP_REQUEST_PROBLEM_INFORMATION + && identifier != MQTT_PROP_REQUEST_RESPONSE_INFORMATION + && identifier != MQTT_PROP_MAXIMUM_QOS + && identifier != MQTT_PROP_RETAIN_AVAILABLE + && identifier != MQTT_PROP_WILDCARD_SUB_AVAILABLE + && identifier != MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE + && identifier != MQTT_PROP_SHARED_SUB_AVAILABLE){ + return MOSQ_ERR_INVAL; + } + + prop = mosquitto__calloc(1, sizeof(struct mqtt5__property)); + if(!prop) return MOSQ_ERR_NOMEM; + + prop->identifier = identifier; + prop->value.i8 = value; + + property__add(proplist, prop); + return MOSQ_ERR_SUCCESS; +} + + +int mosquitto_property_add_int16(mosquitto_property **proplist, int identifier, uint16_t value) +{ + struct mqtt5__property *prop; + + if(!proplist) return MOSQ_ERR_INVAL; + if(identifier != MQTT_PROP_SERVER_KEEP_ALIVE + && identifier != MQTT_PROP_RECEIVE_MAXIMUM + && identifier != MQTT_PROP_TOPIC_ALIAS_MAXIMUM + && identifier != MQTT_PROP_TOPIC_ALIAS){ + return MOSQ_ERR_INVAL; + } + + prop = mosquitto__calloc(1, sizeof(struct mqtt5__property)); + if(!prop) return MOSQ_ERR_NOMEM; + + prop->identifier = identifier; + prop->value.i16 = value; + + property__add(proplist, prop); + return MOSQ_ERR_SUCCESS; +} + + +int mosquitto_property_add_int32(mosquitto_property **proplist, int identifier, uint32_t value) +{ + struct mqtt5__property *prop; + + if(!proplist) return MOSQ_ERR_INVAL; + if(identifier != MQTT_PROP_MESSAGE_EXPIRY_INTERVAL + && identifier != MQTT_PROP_SESSION_EXPIRY_INTERVAL + && identifier != MQTT_PROP_WILL_DELAY_INTERVAL + && identifier != MQTT_PROP_MAXIMUM_PACKET_SIZE){ + + return MOSQ_ERR_INVAL; + } + + prop = mosquitto__calloc(1, sizeof(struct mqtt5__property)); + if(!prop) return MOSQ_ERR_NOMEM; + + prop->identifier = identifier; + prop->value.i32 = value; + + property__add(proplist, prop); + return MOSQ_ERR_SUCCESS; +} + + +int mosquitto_property_add_varint(mosquitto_property **proplist, int identifier, uint32_t value) +{ + struct mqtt5__property *prop; + + if(!proplist || value > 268435455) return MOSQ_ERR_INVAL; + if(identifier != MQTT_PROP_SUBSCRIPTION_IDENTIFIER) return MOSQ_ERR_INVAL; + + prop = mosquitto__calloc(1, sizeof(struct mqtt5__property)); + if(!prop) return MOSQ_ERR_NOMEM; + + prop->identifier = identifier; + prop->value.varint = value; + + property__add(proplist, prop); + return MOSQ_ERR_SUCCESS; +} + + +int mosquitto_property_add_binary(mosquitto_property **proplist, int identifier, const void *value, uint16_t len) +{ + struct mqtt5__property *prop; + + if(!proplist) return MOSQ_ERR_INVAL; + if(identifier != MQTT_PROP_CORRELATION_DATA + && identifier != MQTT_PROP_AUTHENTICATION_DATA){ + + return MOSQ_ERR_INVAL; + } + + prop = mosquitto__calloc(1, sizeof(struct mqtt5__property)); + if(!prop) return MOSQ_ERR_NOMEM; + + prop->identifier = identifier; + + if(len){ + prop->value.bin.v = mosquitto__malloc(len); + if(!prop->value.bin.v){ + mosquitto__free(prop); + return MOSQ_ERR_NOMEM; + } + + memcpy(prop->value.bin.v, value, len); + prop->value.bin.len = len; + } + + property__add(proplist, prop); + return MOSQ_ERR_SUCCESS; +} + + +int mosquitto_property_add_string(mosquitto_property **proplist, int identifier, const char *value) +{ + struct mqtt5__property *prop; + + if(!proplist) return MOSQ_ERR_INVAL; + if(value){ + if(mosquitto_validate_utf8(value, strlen(value))) return MOSQ_ERR_MALFORMED_UTF8; + } + + if(identifier != MQTT_PROP_CONTENT_TYPE + && identifier != MQTT_PROP_RESPONSE_TOPIC + && identifier != MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER + && identifier != MQTT_PROP_AUTHENTICATION_METHOD + && identifier != MQTT_PROP_RESPONSE_INFORMATION + && identifier != MQTT_PROP_SERVER_REFERENCE + && identifier != MQTT_PROP_REASON_STRING){ + + return MOSQ_ERR_INVAL; + } + + prop = mosquitto__calloc(1, sizeof(struct mqtt5__property)); + if(!prop) return MOSQ_ERR_NOMEM; + + prop->identifier = identifier; + if(value && strlen(value)){ + prop->value.s.v = mosquitto__strdup(value); + if(!prop->value.s.v){ + mosquitto__free(prop->name.v); + mosquitto__free(prop); + return MOSQ_ERR_NOMEM; + } + prop->value.s.len = strlen(value); + } + + property__add(proplist, prop); + return MOSQ_ERR_SUCCESS; +} + + +int mosquitto_property_add_string_pair(mosquitto_property **proplist, int identifier, const char *name, const char *value) +{ + struct mqtt5__property *prop; + + if(!proplist) return MOSQ_ERR_INVAL; + if(identifier != MQTT_PROP_USER_PROPERTY) return MOSQ_ERR_INVAL; + if(name){ + if(mosquitto_validate_utf8(name, strlen(name))) return MOSQ_ERR_MALFORMED_UTF8; + } + if(value){ + if(mosquitto_validate_utf8(value, strlen(value))) return MOSQ_ERR_MALFORMED_UTF8; + } + + prop = mosquitto__calloc(1, sizeof(struct mqtt5__property)); + if(!prop) return MOSQ_ERR_NOMEM; + + prop->identifier = identifier; + + if(name && strlen(name)){ + prop->name.v = mosquitto__strdup(name); + if(!prop->name.v){ + mosquitto__free(prop); + return MOSQ_ERR_NOMEM; + } + prop->name.len = strlen(name); + } + + if(value && strlen(value)){ + prop->value.s.v = mosquitto__strdup(value); + if(!prop->value.s.v){ + mosquitto__free(prop->name.v); + mosquitto__free(prop); + return MOSQ_ERR_NOMEM; + } + prop->value.s.len = strlen(value); + } + + property__add(proplist, prop); + return MOSQ_ERR_SUCCESS; +} diff --git a/lib/property_mosq.h b/lib/property_mosq.h index 5fbd311f2f..dd2ecf9578 100644 --- a/lib/property_mosq.h +++ b/lib/property_mosq.h @@ -40,10 +40,10 @@ struct mqtt5__property { int property__read_all(int command, struct mosquitto__packet *packet, struct mqtt5__property **property); -int property__write_all(struct mosquitto__packet *packet, struct mqtt5__property *property); +int property__write_all(struct mosquitto__packet *packet, const struct mqtt5__property *property); void property__free(struct mqtt5__property **property); -int property__get_length(struct mqtt5__property *property); -int property__get_length_all(struct mqtt5__property *property); +int property__get_length(const struct mqtt5__property *property); +int property__get_length_all(const struct mqtt5__property *property); #endif diff --git a/lib/send_connect.c b/lib/send_connect.c index f8859ef056..1c703fd72b 100644 --- a/lib/send_connect.c +++ b/lib/send_connect.c @@ -31,7 +31,7 @@ and the Eclipse Distribution License is available at #include "packet_mosq.h" #include "property_mosq.h" -int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session) +int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session, const struct mqtt5__property *properties) { struct mosquitto__packet *packet = NULL; int payloadlen; @@ -41,7 +41,6 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session uint8_t version; char *clientid, *username, *password; int headerlen; - struct mqtt5__property *properties = NULL; int proplen, varbytes; assert(mosq); diff --git a/lib/send_disconnect.c b/lib/send_disconnect.c index 1258f5c08c..9593ea2eb8 100644 --- a/lib/send_disconnect.c +++ b/lib/send_disconnect.c @@ -32,11 +32,10 @@ and the Eclipse Distribution License is available at #include "send_mosq.h" -int send__disconnect(struct mosquitto *mosq) +int send__disconnect(struct mosquitto *mosq, const struct mqtt5__property *properties) { struct mosquitto__packet *packet = NULL; int rc; - struct mqtt5__property *properties = NULL; int proplen, varbytes; assert(mosq); diff --git a/lib/send_mosq.c b/lib/send_mosq.c index 9bf441a1e4..eb0d6561b9 100644 --- a/lib/send_mosq.c +++ b/lib/send_mosq.c @@ -111,7 +111,7 @@ int send__pubrel(struct mosquitto *mosq, uint16_t mid) } /* For PUBACK, PUBCOMP, PUBREC, and PUBREL */ -int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup, uint8_t reason_code, struct mqtt5__property *properties) +int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup, uint8_t reason_code, const struct mqtt5__property *properties) { struct mosquitto__packet *packet = NULL; int rc; diff --git a/lib/send_mosq.h b/lib/send_mosq.h index 34b1b8788b..68d118995c 100644 --- a/lib/send_mosq.h +++ b/lib/send_mosq.h @@ -20,19 +20,19 @@ and the Eclipse Distribution License is available at #include "property_mosq.h" int send__simple_command(struct mosquitto *mosq, uint8_t command); -int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup, uint8_t reason_code, struct mqtt5__property *properties); -int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, struct mqtt5__property *properties); +int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup, uint8_t reason_code, const struct mqtt5__property *properties); +int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const struct mqtt5__property *properties); -int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session); -int send__disconnect(struct mosquitto *mosq); +int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session, const struct mqtt5__property *properties); +int send__disconnect(struct mosquitto *mosq, const struct mqtt5__property *properties); int send__pingreq(struct mosquitto *mosq); int send__pingresp(struct mosquitto *mosq); int send__puback(struct mosquitto *mosq, uint16_t mid); int send__pubcomp(struct mosquitto *mosq, uint16_t mid); -int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, struct mqtt5__property *properties); +int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const struct mqtt5__property *properties); int send__pubrec(struct mosquitto *mosq, uint16_t mid); int send__pubrel(struct mosquitto *mosq, uint16_t mid); -int send__subscribe(struct mosquitto *mosq, int *mid, int topic_count, char *const *const topic, int topic_qos); +int send__subscribe(struct mosquitto *mosq, int *mid, int topic_count, char *const *const topic, int topic_qos, const struct mqtt5__property *properties); int send__unsubscribe(struct mosquitto *mosq, int *mid, const char *topic); #endif diff --git a/lib/send_publish.c b/lib/send_publish.c index 9ac9d8d238..ef71ab7199 100644 --- a/lib/send_publish.c +++ b/lib/send_publish.c @@ -37,7 +37,7 @@ and the Eclipse Distribution License is available at #include "send_mosq.h" -int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, struct mqtt5__property *properties) +int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const struct mqtt5__property *properties) { #ifdef WITH_BROKER size_t len; @@ -129,7 +129,7 @@ int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint3 } -int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, struct mqtt5__property *properties) +int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const struct mqtt5__property *properties) { struct mosquitto__packet *packet = NULL; int packetlen; diff --git a/lib/send_subscribe.c b/lib/send_subscribe.c index 498919ff77..7feeb3a9f7 100644 --- a/lib/send_subscribe.c +++ b/lib/send_subscribe.c @@ -33,14 +33,13 @@ and the Eclipse Distribution License is available at #include "util_mosq.h" -int send__subscribe(struct mosquitto *mosq, int *mid, int topic_count, const char **topic, int topic_qos) +int send__subscribe(struct mosquitto *mosq, int *mid, int topic_count, const char **topic, int topic_qos, const struct mqtt5__property *properties) { struct mosquitto__packet *packet = NULL; uint32_t packetlen; uint16_t local_mid; int rc; int i; - struct mqtt5__property *properties = NULL; int proplen, varbytes; assert(mosq); diff --git a/lib/socks_mosq.c b/lib/socks_mosq.c index f8f006a401..a3cfc015d3 100644 --- a/lib/socks_mosq.c +++ b/lib/socks_mosq.c @@ -417,7 +417,7 @@ int socks5__read(struct mosquitto *mosq) /* Auth passed */ packet__cleanup(&mosq->in_packet); mosq->state = mosq_cs_new; - return send__connect(mosq, mosq->keepalive, mosq->clean_session); + return send__connect(mosq, mosq->keepalive, mosq->clean_session, NULL); }else{ i = mosq->in_packet.payload[1]; packet__cleanup(&mosq->in_packet); diff --git a/man/mosquitto_pub.1.xml b/man/mosquitto_pub.1.xml index 0d6fc31482..e3b43df804 100644 --- a/man/mosquitto_pub.1.xml +++ b/man/mosquitto_pub.1.xml @@ -46,6 +46,7 @@ + command identifier value topic payload @@ -73,6 +74,7 @@ socks-url protocol-version + command identifier value @@ -313,6 +315,39 @@ option. + + + + + Use an MQTT v5 property with this publish. If you use + this option, the client will be set to be an MQTT v5 + client. This option has two forms: + + + is the MQTT command/packet + identifier and can be one of CONNECT, PUBLISH, PUBREL, + DISCONNECT, AUTH, or WILL. The properties available for + each command are listed in the Properties + section. + + is the name of the + property to add. This is as described in the + specification, but with '-' as a word separator. For + example: + . More details + are in the Properties section. + + is the value of the property + to add, with a data type that is property + specific. + + is only used for the + property as the first of + the two strings in the string pair. In that case, + is the second of the strings in + the pair. + + @@ -481,6 +516,62 @@ arguments to modify the other will parameters. + + Properties + The option allows adding properties + to different stages of the mosquitto_pub run. The properties + supported for each command are as follows: + + + Connect + + (binary data - note treated as a string in mosquitto_pub) + (UTF-8 string pair) + (32-bit unsigned integer) + (16-bit unsigned integer) + (8-bit unsigned integer) + (8-bit unsigned integer) + (32-bit unsigned integer) + (16-bit unsigned integer) + (UTF-8 string pair) + + + + + Publish + + (UTF-8 string) + (binary data - note treated as a string in mosquitto_pub) + (32-bit unsigned integer) + (8-bit unsigned integer) + (UTF-8 string) + (16-bit unsigned integer) + (UTF-8 string pair) + + + + + Disconnect + + (32-bit unsigned integer) + (UTF-8 string pair) + + + + + Will properties + + (UTF-8 string) + (binary data - note treated as a string in mosquitto_pub) + (32-bit unsigned integer) + (8-bit unsigned integer) + (UTF-8 string) + (UTF-8 string pair) + (32-bit unsigned integer) + + + + Examples Publish temperature information to localhost with QoS 1: diff --git a/man/mosquitto_sub.1.xml b/man/mosquitto_sub.1.xml index 44e93cb1d6..696c6c51d6 100644 --- a/man/mosquitto_sub.1.xml +++ b/man/mosquitto_sub.1.xml @@ -52,6 +52,7 @@ protocol-version message processing timeout + command identifier value socks-url @@ -77,6 +78,7 @@ version + command identifier value mosquitto_sub @@ -343,6 +345,39 @@ option. + + + + + Use an MQTT v5 property with this publish. If you use + this option, the client will be set to be an MQTT v5 + client. This option has two forms: + + + is the MQTT command/packet + identifier and can be one of CONNECT, PUBACK, PUBREC, + PUBCOMP, SUBSCRIBE, UNSUBSCRIBE, DISCONNECT, AUTH, or + WILL. The properties available for each command are + listed in the Properties section. + + is the name of the + property to add. This is as described in the + specification, but with '-' as a word separator. For + example: + . More details + are in the Properties section. + + is the value of the property + to add, with a data type that is property + specific. + + is only used for the + property as the first of + the two strings in the string pair. In that case, + is the second of the strings in + the pair. + + @@ -703,6 +738,63 @@ modify the other will parameters. + + Properties + The option allows adding properties + to different stages of the mosquitto_sub run. The properties + supported for each command are as follows: + + + Connect + + (binary data - note treated as a string in mosquitto_pub) + (UTF-8 string pair) + (32-bit unsigned integer) + (16-bit unsigned integer) + (8-bit unsigned integer) + (8-bit unsigned integer) + (32-bit unsigned integer) + (16-bit unsigned integer) + (UTF-8 string pair) + + + + + Subscribe + + (UTF-8 string pair) + + + + + Unsubscribe + + (UTF-8 string pair) + + + + + Disconnect + + (32-bit unsigned integer) + (UTF-8 string pair) + + + + + Will properties + + (UTF-8 string) + (binary data - note treated as a string in mosquitto_pub) + (32-bit unsigned integer) + (8-bit unsigned integer) + (UTF-8 string) + (UTF-8 string pair) + (32-bit unsigned integer) + + + + Examples Note that these really are examples - the subscriptions will work diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 97f1d3b4e6..3d93b2c5c6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -44,6 +44,7 @@ set (MOSQ_SRCS send_suback.c signals.c ../lib/send_subscribe.c + send_unsuback.c ../lib/send_unsubscribe.c sys_tree.c sys_tree.h ../lib/time_mosq.c diff --git a/src/Makefile b/src/Makefile index 93b2ea4a8f..dcb92da4f3 100644 --- a/src/Makefile +++ b/src/Makefile @@ -46,6 +46,7 @@ OBJS= mosquitto.o \ send_publish.o \ send_suback.o \ send_subscribe.o \ + send_unsuback.o \ send_unsubscribe.o \ service.o \ signals.o \ @@ -176,6 +177,9 @@ send_suback.o : send_suback.c mosquitto_broker_internal.h send_subscribe.o : ../lib/send_subscribe.c ../lib/send_mosq.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ +send_unsuback.o : send_unsuback.c mosquitto_broker_internal.h + ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ + send_unsubscribe.o : ../lib/send_unsubscribe.c ../lib/send_mosq.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ diff --git a/src/bridge.c b/src/bridge.c index 77ccf34123..cbff3a9a54 100644 --- a/src/bridge.c +++ b/src/bridge.c @@ -256,7 +256,7 @@ int bridge__connect_step3(struct mosquitto_db *db, struct mosquitto *context) context->bridge->primary_retry = mosquitto_time() + 5; } - rc = send__connect(context, context->keepalive, context->clean_session); + rc = send__connect(context, context->keepalive, context->clean_session, NULL); if(rc == MOSQ_ERR_SUCCESS){ return MOSQ_ERR_SUCCESS; }else if(rc == MOSQ_ERR_ERRNO && errno == ENOTCONN){ @@ -375,7 +375,7 @@ int bridge__connect(struct mosquitto_db *db, struct mosquitto *context) HASH_ADD(hh_sock, db->contexts_by_sock, sock, sizeof(context->sock), context); - rc2 = send__connect(context, context->keepalive, context->clean_session); + rc2 = send__connect(context, context->keepalive, context->clean_session, NULL); if(rc2 == MOSQ_ERR_SUCCESS){ return rc; }else if(rc2 == MOSQ_ERR_ERRNO && errno == ENOTCONN){ diff --git a/src/handle_connack.c b/src/handle_connack.c index ca3321697a..c04625ae6d 100644 --- a/src/handle_connack.c +++ b/src/handle_connack.c @@ -86,7 +86,7 @@ int handle__connack(struct mosquitto_db *db, struct mosquitto *context) } for(i=0; ibridge->topic_count; i++){ if(context->bridge->topics[i].direction == bd_in || context->bridge->topics[i].direction == bd_both){ - if(send__subscribe(context, NULL, 1, &context->bridge->topics[i].remote_topic, context->bridge->topics[i].qos)){ + if(send__subscribe(context, NULL, 1, &context->bridge->topics[i].remote_topic, context->bridge->topics[i].qos, NULL)){ return 1; } }else{ diff --git a/src/handle_unsubscribe.c b/src/handle_unsubscribe.c index 296fef1194..d760a5d7c7 100644 --- a/src/handle_unsubscribe.c +++ b/src/handle_unsubscribe.c @@ -92,6 +92,6 @@ int handle__unsubscribe(struct mosquitto_db *db, struct mosquitto *context) log__printf(NULL, MOSQ_LOG_DEBUG, "Sending UNSUBACK to %s", context->id); /* We don't use Reason String or User Property yet. */ - return send__command_with_mid(context, CMD_UNSUBACK, mid, false, NULL); + return send__unsuback(context, mid, NULL); } diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index f9970a78f2..7a199b11f9 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -512,6 +512,7 @@ int restore_privileges(void); * ============================================================ */ int send__connack(struct mosquitto *context, int ack, int result); int send__suback(struct mosquitto *context, uint16_t mid, uint32_t payloadlen, const void *payload); +int send__unsuback(struct mosquitto *context, uint16_t mid, const struct mqtt5__property *properties); /* ============================================================ * Network functions diff --git a/src/send_unsuback.c b/src/send_unsuback.c new file mode 100644 index 0000000000..e48b6547fb --- /dev/null +++ b/src/send_unsuback.c @@ -0,0 +1,60 @@ +/* +Copyright (c) 2009-2018 Roger Light + +All rights reserved. This program and the accompanying materials +are made available under the terms of the Eclipse Public License v1.0 +and Eclipse Distribution License v1.0 which accompany this distribution. + +The Eclipse Public License is available at + http://www.eclipse.org/legal/epl-v10.html +and the Eclipse Distribution License is available at + http://www.eclipse.org/org/documents/edl-v10.php. + +Contributors: + Roger Light - initial implementation and documentation. +*/ + +#include "config.h" + +#include + +#include "mosquitto_broker_internal.h" +#include "mqtt_protocol.h" +#include "memory_mosq.h" +#include "packet_mosq.h" +#include "property_mosq.h" + + +int send__unsuback(struct mosquitto *mosq, uint16_t mid, const struct mqtt5__property *properties) +{ + struct mosquitto__packet *packet = NULL; + int rc; + int proplen, varbytes; + + assert(mosq); + packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet)); + if(!packet) return MOSQ_ERR_NOMEM; + + packet->command = CMD_UNSUBACK; + packet->remaining_length = 2; + + if(mosq->protocol == mosq_p_mqtt5){ + proplen = property__get_length_all(properties); + varbytes = packet__varint_bytes(proplen); + packet->remaining_length += varbytes + proplen; + } + + rc = packet__alloc(packet); + if(rc){ + mosquitto__free(packet); + return rc; + } + + packet__write_uint16(packet, mid); + + if(mosq->protocol == mosq_p_mqtt5){ + property__write_all(packet, properties); + } + + return packet__queue(mosq, packet); +} diff --git a/test/mosq_test.py b/test/mosq_test.py index 18cdec8743..85447d06a6 100644 --- a/test/mosq_test.py +++ b/test/mosq_test.py @@ -371,6 +371,9 @@ def gen_publish(topic, qos, payload=None, retain=False, dup=False, mid=0, proto_ pack_format = pack_format + "H" if proto_ver == 5: + if properties is None: + properties = struct.pack("!B", 0) + rl += len(properties) # This will break if len(properties) > 127 pack_format = pack_format + "%ds"%(len(properties)) @@ -400,33 +403,27 @@ def gen_publish(topic, qos, payload=None, retain=False, dup=False, mid=0, proto_ else: return struct.pack("!B" + str(len(rlpacked))+"s" + pack_format, cmd, rlpacked, len(topic), topic, payload) -def gen_puback(mid, proto_ver=4): +def _gen_command_with_mid(cmd, mid, proto_ver=4, reason_code=0): if proto_ver == 5: - return struct.pack('!BBHB', 64, 3, mid, 0) + return struct.pack('!BBHBB', cmd, 4, mid, reason_code, 0) else: - return struct.pack('!BBH', 64, 2, mid) + return struct.pack('!BBH', cmd, 2, mid) -def gen_pubrec(mid, proto_ver=4): - if proto_ver == 5: - return struct.pack('!BBHB', 80, 3, mid, 0) - else: - return struct.pack('!BBH', 80, 2, mid) +def gen_puback(mid, proto_ver=4, reason_code=0): + return _gen_command_with_mid(64, mid, proto_ver, reason_code) + +def gen_pubrec(mid, proto_ver=4, reason_code=0): + return _gen_command_with_mid(80, mid, proto_ver, reason_code) -def gen_pubrel(mid, dup=False, proto_ver=4): +def gen_pubrel(mid, dup=False, proto_ver=4, reason_code=0): if dup: cmd = 96+8+2 else: cmd = 96+2 - if proto_ver == 5: - return struct.pack('!BBHB', cmd, 3, mid, 0) - else: - return struct.pack('!BBH', cmd, 2, mid) + return _gen_command_with_mid(cmd, mid, proto_ver, reason_code) -def gen_pubcomp(mid, proto_ver=4): - if proto_ver == 5: - return struct.pack('!BBHB', 112, 3, mid, 0) - else: - return struct.pack('!BBH', 112, 2, mid) +def gen_pubcomp(mid, proto_ver=4, reason_code=0): + return _gen_command_with_mid(112, mid, proto_ver, reason_code) def gen_subscribe(mid, topic, qos, proto_ver=4): if proto_ver == 5: From 383608613a4beb9a3f14b4f3850f4a14c83e9c22 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 1 Nov 2018 11:37:57 +0000 Subject: [PATCH 075/254] Client+lib will property support. --- client/client_shared.c | 7 ++++--- lib/linker.version | 1 + lib/mosquitto.h | 34 ++++++++++++++++++++++++++++++++++ lib/options.c | 8 +++++++- lib/will_mosq.c | 21 ++++++++++++++++++++- lib/will_mosq.h | 2 +- src/bridge.c | 8 ++++---- 7 files changed, 71 insertions(+), 10 deletions(-) diff --git a/client/client_shared.c b/client/client_shared.c index aa2529aa51..df70a10837 100644 --- a/client/client_shared.c +++ b/client/client_shared.c @@ -905,9 +905,11 @@ int client_opts_set(struct mosquitto *mosq, struct mosq_config *cfg) { int rc; - if(cfg->will_topic && mosquitto_will_set(mosq, cfg->will_topic, + mosquitto_opts_set(mosq, MOSQ_OPT_PROTOCOL_VERSION, &(cfg->protocol_version)); + + if(cfg->will_topic && mosquitto_will_set_with_properties(mosq, cfg->will_topic, cfg->will_payloadlen, cfg->will_payload, cfg->will_qos, - cfg->will_retain)){ + cfg->will_retain, cfg->will_props)){ if(!cfg->quiet) fprintf(stderr, "Error: Problem setting will.\n"); mosquitto_lib_cleanup(); @@ -954,7 +956,6 @@ int client_opts_set(struct mosquitto *mosq, struct mosq_config *cfg) } } #endif - mosquitto_opts_set(mosq, MOSQ_OPT_PROTOCOL_VERSION, &(cfg->protocol_version)); return MOSQ_ERR_SUCCESS; } diff --git a/lib/linker.version b/lib/linker.version index 9ec233cca9..c12be67eec 100644 --- a/lib/linker.version +++ b/lib/linker.version @@ -108,4 +108,5 @@ MOSQ_1.6 { mosquitto_string_to_command; mosquitto_string_to_property_info; mosquitto_subscribe_multiple; + mosquitto_will_set_with_properties; } MOSQ_1.5; diff --git a/lib/mosquitto.h b/lib/mosquitto.h index c7ba275d86..fd658e4d39 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -316,6 +316,40 @@ libmosq_EXPORT int mosquitto_reinitialise(struct mosquitto *mosq, const char *id */ libmosq_EXPORT int mosquitto_will_set(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain); +/* + * Function: mosquitto_will_set_with_properties + * + * Configure will information for a mosquitto instance, with attached + * properties. By default, clients do not have a will. This must be called + * before calling . + * + * Parameters: + * mosq - a valid mosquitto instance. + * topic - the topic on which to publish the will. + * payloadlen - the size of the payload (bytes). Valid values are between 0 and + * 268,435,455. + * payload - pointer to the data to send. If payloadlen > 0 this must be a + * valid memory location. + * qos - integer value 0, 1 or 2 indicating the Quality of Service to be + * used for the will. + * retain - set to true to make the will a retained message. + * properties - list of MQTT 5 properties. Can be NULL. On success only, the + * property list becomes the property of libmosquitto once this + * function is called and will be freed by the library. The + * property list must be freed by the application on error. + * + * 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_PAYLOAD_SIZE - if payloadlen is too large. + * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8. + * MOSQ_ERR_NOT_SUPPORTED - if properties is not NULL and the client is not + * using MQTT v5 + * MOSQ_ERR_PROTOCOL - if a property is invalid for use with wills. + */ +libmosq_EXPORT int mosquitto_will_set_with_properties(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain, mosquitto_property *properties); + /* * Function: mosquitto_will_clear * diff --git a/lib/options.c b/lib/options.c index 5ec323023d..12a19d8b6c 100644 --- a/lib/options.c +++ b/lib/options.c @@ -30,9 +30,15 @@ and the Eclipse Distribution License is available at int mosquitto_will_set(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain) +{ + return mosquitto_will_set_with_properties(mosq, topic, payloadlen, payload, qos, retain, NULL); +} + + +int mosquitto_will_set_with_properties(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain, mosquitto_property *properties) { if(!mosq) return MOSQ_ERR_INVAL; - return will__set(mosq, topic, payloadlen, payload, qos, retain); + return will__set(mosq, topic, payloadlen, payload, qos, retain, properties); } diff --git a/lib/will_mosq.c b/lib/will_mosq.c index 7062b5126a..b9a13b9d9f 100644 --- a/lib/will_mosq.c +++ b/lib/will_mosq.c @@ -33,10 +33,12 @@ and the Eclipse Distribution License is available at #include "read_handle.h" #include "send_mosq.h" #include "util_mosq.h" +#include "will_mosq.h" -int will__set(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain) +int will__set(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain, mosquitto_property *properties) { int rc = MOSQ_ERR_SUCCESS; + mosquitto_property *p; if(!mosq || !topic) return MOSQ_ERR_INVAL; if(payloadlen < 0 || payloadlen > MQTT_MAX_PAYLOAD) return MOSQ_ERR_PAYLOAD_SIZE; @@ -45,9 +47,22 @@ int will__set(struct mosquitto *mosq, const char *topic, int payloadlen, const v if(mosquitto_pub_topic_check(topic)) return MOSQ_ERR_INVAL; if(mosquitto_validate_utf8(topic, strlen(topic))) return MOSQ_ERR_MALFORMED_UTF8; + if(properties){ + if(mosq->protocol != mosq_p_mqtt5){ + return MOSQ_ERR_NOT_SUPPORTED; + } + p = properties; + while(p){ + rc = mosquitto_property_command_check(CMD_WILL, p->identifier); + if(rc) return rc; + p = p->next; + } + } + if(mosq->will){ mosquitto__free(mosq->will->msg.topic); mosquitto__free(mosq->will->msg.payload); + mosquitto_property_free_all(&mosq->will->properties); mosquitto__free(mosq->will); } @@ -75,6 +90,8 @@ int will__set(struct mosquitto *mosq, const char *topic, int payloadlen, const v mosq->will->msg.qos = qos; mosq->will->msg.retain = retain; + mosq->will->properties = properties; + return MOSQ_ERR_SUCCESS; cleanup: @@ -99,6 +116,8 @@ int will__clear(struct mosquitto *mosq) mosquitto__free(mosq->will->msg.payload); mosq->will->msg.payload = NULL; + mosquitto_property_free_all(&mosq->will->properties); + mosquitto__free(mosq->will); mosq->will = NULL; diff --git a/lib/will_mosq.h b/lib/will_mosq.h index 7afb4089d5..e46d1bd96f 100644 --- a/lib/will_mosq.h +++ b/lib/will_mosq.h @@ -20,7 +20,7 @@ and the Eclipse Distribution License is available at #include "mosquitto.h" #include "mosquitto_internal.h" -int will__set(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain); +int will__set(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain, mosquitto_property *properties); int will__clear(struct mosquitto *mosq); #endif diff --git a/src/bridge.c b/src/bridge.c index cbff3a9a54..2446184d90 100644 --- a/src/bridge.c +++ b/src/bridge.c @@ -159,7 +159,7 @@ int bridge__connect_step1(struct mosquitto_db *db, struct mosquitto *context) context->bridge->initial_notification_done = true; } notification_payload = '0'; - rc = will__set(context, context->bridge->notification_topic, 1, ¬ification_payload, 1, true); + rc = will__set(context, context->bridge->notification_topic, 1, ¬ification_payload, 1, true, NULL); if(rc != MOSQ_ERR_SUCCESS){ return rc; } @@ -177,7 +177,7 @@ int bridge__connect_step1(struct mosquitto_db *db, struct mosquitto *context) } notification_payload = '0'; - rc = will__set(context, notification_topic, 1, ¬ification_payload, 1, true); + rc = will__set(context, notification_topic, 1, ¬ification_payload, 1, true, NULL); mosquitto__free(notification_topic); if(rc != MOSQ_ERR_SUCCESS){ return rc; @@ -327,7 +327,7 @@ int bridge__connect(struct mosquitto_db *db, struct mosquitto *context) if (!context->bridge->notifications_local_only) { notification_payload = '0'; - rc = will__set(context, context->bridge->notification_topic, 1, ¬ification_payload, 1, true); + rc = will__set(context, context->bridge->notification_topic, 1, ¬ification_payload, 1, true, NULL); if(rc != MOSQ_ERR_SUCCESS){ return rc; } @@ -347,7 +347,7 @@ int bridge__connect(struct mosquitto_db *db, struct mosquitto *context) if (!context->bridge->notifications_local_only) { notification_payload = '0'; - rc = will__set(context, notification_topic, 1, ¬ification_payload, 1, true); + rc = will__set(context, notification_topic, 1, ¬ification_payload, 1, true, NULL); mosquitto__free(notification_topic); if(rc != MOSQ_ERR_SUCCESS){ return rc; From 741a8a9cc379c9e2927421e52605cb11d3ab2d8f Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 1 Nov 2018 11:57:47 +0000 Subject: [PATCH 076/254] Client disconnect property support, plus disconnect packet fix. --- client/pub_client.c | 12 +++++----- client/sub_client.c | 56 +++++++++++++++++-------------------------- lib/linker.version | 1 + lib/send_disconnect.c | 4 +++- 4 files changed, 32 insertions(+), 41 deletions(-) diff --git a/client/pub_client.c b/client/pub_client.c index ffeb2ec185..cd950d923a 100644 --- a/client/pub_client.c +++ b/client/pub_client.c @@ -94,7 +94,7 @@ void my_connect_callback(struct mosquitto *mosq, void *obj, int result) break; } } - mosquitto_disconnect(mosq); + mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); } }else{ if(result && !quiet){ @@ -113,11 +113,11 @@ void my_publish_callback(struct mosquitto *mosq, void *obj, int mid) last_mid_sent = mid; if(mode == MSGMODE_STDIN_LINE){ if(mid == last_mid){ - mosquitto_disconnect(mosq); + mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); disconnect_sent = true; } }else if(disconnect_sent == false){ - mosquitto_disconnect(mosq); + mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); disconnect_sent = true; } } @@ -419,7 +419,7 @@ int main(int argc, char *argv[]) rc2 = mosquitto_publish_with_properties(mosq, &mid_sent, topic, buf_len_actual-1, buf, qos, retain, cfg.publish_props); if(rc2){ if(!quiet) fprintf(stderr, "Error: Publish returned %d, disconnecting.\n", rc2); - mosquitto_disconnect(mosq); + mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); } break; }else{ @@ -438,7 +438,7 @@ int main(int argc, char *argv[]) if(feof(stdin)){ if(last_mid == -1){ /* Empty file */ - mosquitto_disconnect(mosq); + mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); disconnect_sent = true; status = STATUS_DISCONNECTING; }else{ @@ -448,7 +448,7 @@ int main(int argc, char *argv[]) } }else if(status == STATUS_WAITING){ if(last_mid_sent == last_mid && disconnect_sent == false){ - mosquitto_disconnect(mosq); + mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); disconnect_sent = true; } #ifdef WIN32 diff --git a/client/sub_client.c b/client/sub_client.c index 5e9a972db3..355d2bb1fd 100644 --- a/client/sub_client.c +++ b/client/sub_client.c @@ -34,6 +34,7 @@ and the Eclipse Distribution License is available at #include #include "client_shared.h" +static struct mosq_config cfg; bool process_messages = true; int msg_count = 0; struct mosquitto *mosq = NULL; @@ -43,7 +44,7 @@ void my_signal_handler(int signum) { if(signum == SIGALRM){ process_messages = false; - mosquitto_disconnect(mosq); + mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); } } #endif @@ -53,36 +54,32 @@ void print_message(struct mosq_config *cfg, const struct mosquitto_message *mess void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message) { - struct mosq_config *cfg; int i; bool res; if(process_messages == false) return; - assert(obj); - cfg = (struct mosq_config *)obj; - - if(cfg->retained_only && !message->retain && process_messages){ + if(cfg.retained_only && !message->retain && process_messages){ process_messages = false; - mosquitto_disconnect(mosq); + mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); return; } - if(message->retain && cfg->no_retain) return; - if(cfg->filter_outs){ - for(i=0; ifilter_out_count; i++){ - mosquitto_topic_matches_sub(cfg->filter_outs[i], message->topic, &res); + if(message->retain && cfg.no_retain) return; + if(cfg.filter_outs){ + for(i=0; itopic, &res); if(res) return; } } - print_message(cfg, message); + print_message(&cfg, message); - if(cfg->msg_count>0){ + if(cfg.msg_count>0){ msg_count++; - if(cfg->msg_count == msg_count){ + if(cfg.msg_count == msg_count){ process_messages = false; - mosquitto_disconnect(mosq); + mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); } } } @@ -90,41 +87,33 @@ void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquit void my_connect_callback(struct mosquitto *mosq, void *obj, int result, int flags) { int i; - struct mosq_config *cfg; - - assert(obj); - cfg = (struct mosq_config *)obj; if(!result){ - mosquitto_subscribe_multiple(mosq, NULL, cfg->topic_count, cfg->topics, cfg->qos, cfg->subscribe_props); + mosquitto_subscribe_multiple(mosq, NULL, cfg.topic_count, cfg.topics, cfg.qos, cfg.subscribe_props); - for(i=0; iunsub_topic_count; i++){ - mosquitto_unsubscribe(mosq, NULL, cfg->unsub_topics[i]); + for(i=0; iquiet){ + if(result && !cfg.quiet){ fprintf(stderr, "%s\n", mosquitto_connack_string(result)); } - mosquitto_disconnect(mosq); + mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); } } void my_subscribe_callback(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos) { int i; - struct mosq_config *cfg; - - assert(obj); - cfg = (struct mosq_config *)obj; - if(!cfg->quiet) printf("Subscribed (mid: %d): %d", mid, granted_qos[0]); + if(!cfg.quiet) printf("Subscribed (mid: %d): %d", mid, granted_qos[0]); for(i=1; iquiet) printf(", %d", granted_qos[i]); + if(!cfg.quiet) printf(", %d", granted_qos[i]); } - if(!cfg->quiet) printf("\n"); + if(!cfg.quiet) printf("\n"); - if(cfg->exit_after_sub){ - mosquitto_disconnect(mosq); + if(cfg.exit_after_sub){ + mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); } } @@ -240,7 +229,6 @@ void print_usage(void) int main(int argc, char *argv[]) { - struct mosq_config cfg; int rc; #ifndef WIN32 struct sigaction sigact; diff --git a/lib/linker.version b/lib/linker.version index c12be67eec..83476ccc6e 100644 --- a/lib/linker.version +++ b/lib/linker.version @@ -95,6 +95,7 @@ MOSQ_1.5 { MOSQ_1.6 { global: mosquitto_connect_bind_with_properties; + mosquitto_disconnect_with_properties; mosquitto_property_add_binary; mosquitto_property_add_byte; mosquitto_property_add_int16; diff --git a/lib/send_disconnect.c b/lib/send_disconnect.c index 9593ea2eb8..d998c3f6b2 100644 --- a/lib/send_disconnect.c +++ b/lib/send_disconnect.c @@ -54,7 +54,8 @@ int send__disconnect(struct mosquitto *mosq, const struct mqtt5__property *prope if(mosq->protocol == mosq_p_mqtt5){ proplen = property__get_length_all(properties); varbytes = packet__varint_bytes(proplen); - packet->remaining_length = proplen+varbytes; + /* 1 here is the reason code */ + packet->remaining_length = 1 + proplen + varbytes; }else{ packet->remaining_length = 0; } @@ -65,6 +66,7 @@ int send__disconnect(struct mosquitto *mosq, const struct mqtt5__property *prope return rc; } if(mosq->protocol == mosq_p_mqtt5){ + packet__write_byte(packet, 0); property__write_all(packet, properties); } From 49a8642986a5fb1a9d1d37ef9065dc7e6fc9d545 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 1 Nov 2018 11:59:59 +0000 Subject: [PATCH 077/254] Disallow properties that are invalid for a command. --- client/client_props.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client/client_props.c b/client/client_props.c index 908fbb0f73..de9db8e3cb 100644 --- a/client/client_props.c +++ b/client/client_props.c @@ -85,6 +85,11 @@ int cfg_parse_property(struct mosq_config *cfg, int argc, char *argv[], int *idx return MOSQ_ERR_INVAL; } + if(mosquitto_property_command_check(cmd, identifier)){ + fprintf(stderr, "Error: %s property not allow for %s in --property argument.\n\n", propname, cmdname); + return MOSQ_ERR_INVAL; + } + if(identifier == MQTT_PROP_USER_PROPERTY){ if((*idx)+3 > argc-1){ /* Not enough args */ From de3a9af1f78cd768fc5abb391418fab39557f4c7 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 1 Nov 2018 14:12:52 +0000 Subject: [PATCH 078/254] Client+library support for unsubscribe properties. --- client/client_props.c | 2 +- client/sub_client.c | 2 +- lib/actions.c | 7 ++++++- lib/linker.version | 2 ++ lib/mosquitto.h | 24 ++++++++++++++++++++++++ lib/send_mosq.h | 2 +- lib/send_unsubscribe.c | 4 ++-- src/handle_connack.c | 2 +- 8 files changed, 38 insertions(+), 7 deletions(-) diff --git a/client/client_props.c b/client/client_props.c index de9db8e3cb..93ce27f865 100644 --- a/client/client_props.c +++ b/client/client_props.c @@ -128,7 +128,7 @@ int cfg_parse_property(struct mosq_config *cfg, int argc, char *argv[], int *idx break; case CMD_UNSUBSCRIBE: - proplist = &cfg->subscribe_props; + proplist = &cfg->unsubscribe_props; break; case CMD_DISCONNECT: diff --git a/client/sub_client.c b/client/sub_client.c index 355d2bb1fd..d86f7e01a2 100644 --- a/client/sub_client.c +++ b/client/sub_client.c @@ -92,7 +92,7 @@ void my_connect_callback(struct mosquitto *mosq, void *obj, int result, int flag mosquitto_subscribe_multiple(mosq, NULL, cfg.topic_count, cfg.topics, cfg.qos, cfg.subscribe_props); for(i=0; isock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; @@ -144,6 +149,6 @@ int mosquitto_unsubscribe(struct mosquitto *mosq, int *mid, const char *sub) if(mosquitto_sub_topic_check(sub)) return MOSQ_ERR_INVAL; if(mosquitto_validate_utf8(sub, strlen(sub))) return MOSQ_ERR_MALFORMED_UTF8; - return send__unsubscribe(mosq, mid, sub); + return send__unsubscribe(mosq, mid, sub, properties); } diff --git a/lib/linker.version b/lib/linker.version index 83476ccc6e..499aa303dc 100644 --- a/lib/linker.version +++ b/lib/linker.version @@ -109,5 +109,7 @@ MOSQ_1.6 { mosquitto_string_to_command; mosquitto_string_to_property_info; mosquitto_subscribe_multiple; + mosquitto_subscribe_with_properties; + mosquitto_unsubscribe_with_properties; mosquitto_will_set_with_properties; } MOSQ_1.5; diff --git a/lib/mosquitto.h b/lib/mosquitto.h index fd658e4d39..b5eba8af72 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -892,6 +892,30 @@ int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count */ libmosq_EXPORT int mosquitto_unsubscribe(struct mosquitto *mosq, int *mid, const char *sub); +/* + * Function: mosquitto_unsubscribe_with_properties + * + * Unsubscribe from a topic, with attached MQTT properties. + * + * Parameters: + * mosq - a valid mosquitto instance. + * mid - a pointer to an int. If not NULL, the function will set this to + * the message id of this particular message. This can be then used + * with the unsubscribe callback to determine when the message has been + * sent. + * sub - the unsubscription pattern. + * properties - a valid mosquitto_property list, or NULL. Only used with MQTT + * v5 clients. + * + * 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_MALFORMED_UTF8 - if the topic is not valid UTF-8 + */ +libmosq_EXPORT int mosquitto_unsubscribe_with_properties(struct mosquitto *mosq, int *mid, const char *sub, const mosquitto_property *properties); + /* ====================================================================== * diff --git a/lib/send_mosq.h b/lib/send_mosq.h index 68d118995c..094c782c5a 100644 --- a/lib/send_mosq.h +++ b/lib/send_mosq.h @@ -33,6 +33,6 @@ int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint3 int send__pubrec(struct mosquitto *mosq, uint16_t mid); int send__pubrel(struct mosquitto *mosq, uint16_t mid); int send__subscribe(struct mosquitto *mosq, int *mid, int topic_count, char *const *const topic, int topic_qos, const struct mqtt5__property *properties); -int send__unsubscribe(struct mosquitto *mosq, int *mid, const char *topic); +int send__unsubscribe(struct mosquitto *mosq, int *mid, const char *topic, const mosquitto_property *properties); #endif diff --git a/lib/send_unsubscribe.c b/lib/send_unsubscribe.c index 105a7d793d..a3e75251bd 100644 --- a/lib/send_unsubscribe.c +++ b/lib/send_unsubscribe.c @@ -29,17 +29,17 @@ and the Eclipse Distribution License is available at #include "mqtt_protocol.h" #include "packet_mosq.h" #include "property_mosq.h" +#include "send_mosq.h" #include "util_mosq.h" -int send__unsubscribe(struct mosquitto *mosq, int *mid, const char *topic) +int send__unsubscribe(struct mosquitto *mosq, int *mid, const char *topic, const mosquitto_property *properties) { /* FIXME - only deals with a single topic */ struct mosquitto__packet *packet = NULL; uint32_t packetlen; uint16_t local_mid; int rc; - struct mqtt5__property *properties = NULL; int proplen, varbytes; assert(mosq); diff --git a/src/handle_connack.c b/src/handle_connack.c index c04625ae6d..038dab0ed0 100644 --- a/src/handle_connack.c +++ b/src/handle_connack.c @@ -91,7 +91,7 @@ int handle__connack(struct mosquitto_db *db, struct mosquitto *context) } }else{ if(context->bridge->attempt_unsubscribe){ - if(send__unsubscribe(context, NULL, context->bridge->topics[i].remote_topic)){ + if(send__unsubscribe(context, NULL, context->bridge->topics[i].remote_topic, NULL)){ /* direction = inwards only. This means we should not be subscribed * to the topic. It is possible that we used to be subscribed to * this topic so unsubscribe. */ From 55b46037dac626e308ddcd746e5a677140a9e424 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 1 Nov 2018 14:22:00 +0000 Subject: [PATCH 079/254] Change -y to -D in clients. --- client/client_shared.c | 12 +++--- client/pub_client.c | 4 +- client/sub_client.c | 5 +-- man/mosquitto_pub.1.xml | 93 ++++++++++++++++++++-------------------- man/mosquitto_sub.1.xml | 95 +++++++++++++++++++++-------------------- 5 files changed, 105 insertions(+), 104 deletions(-) diff --git a/client/client_shared.c b/client/client_shared.c index df70a10837..1e2240b562 100644 --- a/client/client_shared.c +++ b/client/client_shared.c @@ -466,6 +466,12 @@ int client_config_line_proc(struct mosq_config *cfg, int pub_or_sub, int argc, c } }else if(!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")){ cfg->debug = true; + }else if(!strcmp(argv[i], "-D") || !strcmp(argv[i], "--property")){ + i++; + if(cfg_parse_property(cfg, argc, argv, &i)){ + return 1; + } + cfg->protocol_version = MQTT_PROTOCOL_V5; }else if(!strcmp(argv[i], "-f") || !strcmp(argv[i], "--file")){ if(pub_or_sub == CLIENT_SUB){ goto unknown_option; @@ -883,12 +889,6 @@ int client_config_line_proc(struct mosq_config *cfg, int pub_or_sub, int argc, c goto unknown_option; } cfg->verbose = 1; - }else if(!strcmp(argv[i], "-y") || !strcmp(argv[i], "--property")){ - i++; - if(cfg_parse_property(cfg, argc, argv, &i)){ - return 1; - } - cfg->protocol_version = MQTT_PROTOCOL_V5; }else{ goto unknown_option; } diff --git a/client/pub_client.c b/client/pub_client.c index cd950d923a..acec809ef7 100644 --- a/client/pub_client.c +++ b/client/pub_client.c @@ -232,11 +232,12 @@ void print_usage(void) printf(" [--proxy socks-url]\n"); #endif printf(" [--property command identifier value]\n"); - printf(" [-y command identifier value]\n"); + printf(" [-D command identifier value]\n"); printf(" mosquitto_pub --help\n\n"); printf(" -A : bind the outgoing socket to this host/ip address. Use to control which interface\n"); printf(" the client communicates over.\n"); printf(" -d : enable debug messages.\n"); + printf(" -D : Define MQTT v5 properties. See the documentation for more details.\n"); printf(" -f : send the contents of a file as the message.\n"); printf(" -h : mqtt host to connect to. Defaults to localhost.\n"); printf(" -i : id to use for this client. Defaults to mosquitto_pub_ appended with the process id.\n"); @@ -261,7 +262,6 @@ void print_usage(void) printf(" -u : provide a username\n"); printf(" -V : specify the version of the MQTT protocol to use when connecting.\n"); printf(" Can be mqttv5, mqttv311 or mqttv31. Defaults to mqttv311.\n"); - printf(" -y,--property : Add MQTT v5 properties. See the documentation for more details.\n"); printf(" --help : display this message.\n"); printf(" --quiet : don't print error messages.\n"); printf(" --will-payload : payload for the client Will, which is sent by the broker in case of\n"); diff --git a/client/sub_client.c b/client/sub_client.c index d86f7e01a2..ce6d4171e7 100644 --- a/client/sub_client.c +++ b/client/sub_client.c @@ -154,14 +154,14 @@ void print_usage(void) #ifdef WITH_SOCKS printf(" [--proxy socks-url]\n"); #endif - printf(" [-y command identifier value]\n"); - printf(" [--property command identifier value]\n"); + printf(" [-D command identifier value]\n"); printf(" mosquitto_sub --help\n\n"); printf(" -A : bind the outgoing socket to this host/ip address. Use to control which interface\n"); printf(" the client communicates over.\n"); printf(" -c : disable 'clean session' (store subscription and pending messages when client disconnects).\n"); printf(" -C : disconnect and exit after receiving the 'msg_count' messages.\n"); printf(" -d : enable debug messages.\n"); + printf(" -D : Define MQTT v5 properties. See the documentation for more details.\n"); printf(" -E : Exit once all subscriptions have been acknowledged by the broker.\n"); printf(" -F : output format.\n"); printf(" -h : mqtt host to connect to. Defaults to localhost.\n"); @@ -189,7 +189,6 @@ void print_usage(void) #ifndef WIN32 printf(" -W : Specifies a timeout in seconds how long to process incoming MQTT messages.\n"); #endif - printf(" -y, --property : Add MQTT v5 properties. See the documentation for more details.\n"); printf(" --help : display this message.\n"); printf(" --quiet : don't print error messages.\n"); printf(" --retained-only : only handle messages with the retained flag set, and exit when the\n"); diff --git a/man/mosquitto_pub.1.xml b/man/mosquitto_pub.1.xml index e3b43df804..c95c0cbab3 100644 --- a/man/mosquitto_pub.1.xml +++ b/man/mosquitto_pub.1.xml @@ -20,7 +20,7 @@ hostname - port number + port-number username password @@ -29,13 +29,14 @@ URL - bind_address + bind-address - client_id - client id prefix - keepalive time - message QoS + command identifier value + client-id + client-id-prefix + keepalive-time + message-QoS @@ -46,7 +47,6 @@ - command identifier value topic payload @@ -74,8 +74,6 @@ socks-url protocol-version - command identifier value - mosquitto_pub @@ -189,6 +187,41 @@ Enable debug messages. + + + + + Use an MQTT v5 property with this publish. If you use + this option, the client will be set to be an MQTT v5 + client. This option has two forms: + + + is the MQTT command/packet + identifier and can be one of CONNECT, PUBLISH, PUBREL, + DISCONNECT, AUTH, or WILL. The properties available for + each command are listed in the + Properties + section. + + is the name of the + property to add. This is as described in the + specification, but with '-' as a word separator. For + example: + . More details + are in the Properties + section. + + is the value of the property + to add, with a data type that is property + specific. + + is only used for the + property as the first of + the two strings in the string pair. In that case, + is the second of the strings in + the pair. + + @@ -315,39 +348,6 @@ option. - - - - - Use an MQTT v5 property with this publish. If you use - this option, the client will be set to be an MQTT v5 - client. This option has two forms: - - - is the MQTT command/packet - identifier and can be one of CONNECT, PUBLISH, PUBREL, - DISCONNECT, AUTH, or WILL. The properties available for - each command are listed in the Properties - section. - - is the name of the - property to add. This is as described in the - specification, but with '-' as a word separator. For - example: - . More details - are in the Properties section. - - is the value of the property - to add, with a data type that is property - specific. - - is only used for the - property as the first of - the two strings in the string pair. In that case, - is the second of the strings in - the pair. - - @@ -516,11 +516,12 @@ arguments to modify the other will parameters. - + Properties - The option allows adding properties - to different stages of the mosquitto_pub run. The properties - supported for each command are as follows: + The / option + allows adding properties to different stages of the mosquitto_pub + run. The properties supported for each command are as + follows: Connect diff --git a/man/mosquitto_sub.1.xml b/man/mosquitto_sub.1.xml index 696c6c51d6..bffcd6e080 100644 --- a/man/mosquitto_sub.1.xml +++ b/man/mosquitto_sub.1.xml @@ -20,7 +20,7 @@ hostname - port number + port-number username password @@ -32,16 +32,17 @@ message-topic - bind_address + bind-address - msg count + msg-count + command identifier value - client_id - client id prefix - keepalive time + client-id + client-id-prefix + keepalive-time - message QoS + message-QoS @@ -51,8 +52,7 @@ unsub-topic protocol-version - message processing timeout - command identifier value + message-processing-timeout socks-url @@ -78,7 +78,6 @@ version - command identifier value mosquitto_sub @@ -212,6 +211,40 @@ Enable debug messages. + + + + + Use an MQTT v5 property with this publish. If you use + this option, the client will be set to be an MQTT v5 + client. This option has two forms: + + + is the MQTT command/packet + identifier and can be one of CONNECT, PUBACK, PUBREC, + PUBCOMP, SUBSCRIBE, UNSUBSCRIBE, DISCONNECT, AUTH, or + WILL. The properties available for each command are + listed in the Properties section. + + is the name of the + property to add. This is as described in the + specification, but with '-' as a word separator. For + example: + . More details + are in the Properties + section. + + is the value of the property + to add, with a data type that is property + specific. + + is only used for the + property as the first of + the two strings in the string pair. In that case, + is the second of the strings in + the pair. + + @@ -345,39 +378,6 @@ option. - - - - - Use an MQTT v5 property with this publish. If you use - this option, the client will be set to be an MQTT v5 - client. This option has two forms: - - - is the MQTT command/packet - identifier and can be one of CONNECT, PUBACK, PUBREC, - PUBCOMP, SUBSCRIBE, UNSUBSCRIBE, DISCONNECT, AUTH, or - WILL. The properties available for each command are - listed in the Properties section. - - is the name of the - property to add. This is as described in the - specification, but with '-' as a word separator. For - example: - . More details - are in the Properties section. - - is the value of the property - to add, with a data type that is property - specific. - - is only used for the - property as the first of - the two strings in the string pair. In that case, - is the second of the strings in - the pair. - - @@ -738,11 +738,12 @@ modify the other will parameters. - + Properties - The option allows adding properties - to different stages of the mosquitto_sub run. The properties - supported for each command are as follows: + The / option + allows adding properties to different stages of the mosquitto_sub + run. The properties supported for each command are as + follows: Connect From 8aa936936ef72f2f115a14b72e11665361b60f4f Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 1 Nov 2018 15:47:21 +0000 Subject: [PATCH 080/254] Library and client support for topic-alias. --- client/client_props.c | 3 +++ client/client_shared.h | 1 + client/pub_client.c | 18 +++++++++++++--- lib/actions.c | 47 +++++++++++++++++++++++++++++++----------- lib/send_publish.c | 14 +++++++++---- 5 files changed, 64 insertions(+), 19 deletions(-) diff --git a/client/client_props.c b/client/client_props.c index 93ce27f865..1e6415141d 100644 --- a/client/client_props.c +++ b/client/client_props.c @@ -112,6 +112,9 @@ int cfg_parse_property(struct mosq_config *cfg, int argc, char *argv[], int *idx break; case CMD_PUBLISH: + if(identifier == MQTT_PROP_TOPIC_ALIAS){ + cfg->have_topic_alias = true; + } if(identifier == MQTT_PROP_SUBSCRIPTION_IDENTIFIER){ fprintf(stderr, "Error: %s property not supported for %s in --property argument.\n\n", propname, cmdname); return MOSQ_ERR_INVAL; diff --git a/client/client_shared.h b/client/client_shared.h index 18adcf3f26..ade5b274a4 100644 --- a/client/client_shared.h +++ b/client/client_shared.h @@ -98,6 +98,7 @@ struct mosq_config { mosquitto_property *unsubscribe_props; mosquitto_property *disconnect_props; mosquitto_property *will_props; + bool have_topic_alias; /* pub */ }; int client_config_load(struct mosq_config *config, int pub_or_sub, int argc, char *argv[]); diff --git a/client/pub_client.c b/client/pub_client.c index acec809ef7..ff38e8eeca 100644 --- a/client/pub_client.c +++ b/client/pub_client.c @@ -55,6 +55,18 @@ static char *password = NULL; static bool disconnect_sent = false; static bool quiet = false; static struct mosq_config cfg; +static bool first_publish = true; + +int my_publish(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, void *payload, int qos, bool retain) +{ + if(cfg.protocol_version == MQTT_PROTOCOL_V5 && cfg.have_topic_alias && first_publish == false){ + return mosquitto_publish_with_properties(mosq, mid, NULL, payloadlen, payload, qos, retain, cfg.publish_props); + }else{ + first_publish = false; + return mosquitto_publish_with_properties(mosq, mid, topic, payloadlen, payload, qos, retain, cfg.publish_props); + } +} + void my_connect_callback(struct mosquitto *mosq, void *obj, int result) { @@ -65,10 +77,10 @@ void my_connect_callback(struct mosquitto *mosq, void *obj, int result) case MSGMODE_CMD: case MSGMODE_FILE: case MSGMODE_STDIN_FILE: - rc = mosquitto_publish_with_properties(mosq, &mid_sent, topic, msglen, message, qos, retain, cfg.publish_props); + rc = my_publish(mosq, &mid_sent, topic, msglen, message, qos, retain); break; case MSGMODE_NULL: - rc = mosquitto_publish_with_properties(mosq, &mid_sent, topic, 0, NULL, qos, retain, cfg.publish_props); + rc = my_publish(mosq, &mid_sent, topic, 0, NULL, qos, retain); break; case MSGMODE_STDIN_LINE: status = STATUS_CONNACK_RECVD; @@ -416,7 +428,7 @@ int main(int argc, char *argv[]) buf_len_actual = strlen(buf); if(buf[buf_len_actual-1] == '\n'){ buf[buf_len_actual-1] = '\0'; - rc2 = mosquitto_publish_with_properties(mosq, &mid_sent, topic, buf_len_actual-1, buf, qos, retain, cfg.publish_props); + rc2 = my_publish(mosq, &mid_sent, topic, buf_len_actual-1, buf, qos, retain); if(rc2){ if(!quiet) fprintf(stderr, "Error: Publish returned %d, disconnecting.\n", rc2); mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); diff --git a/lib/actions.c b/lib/actions.c index 25c5009e3d..3582697155 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -38,14 +38,35 @@ int mosquitto_publish_with_properties(struct mosquitto *mosq, int *mid, const ch struct mosquitto_message_all *message; uint16_t local_mid; int queue_status; - - if(!mosq || !topic || qos<0 || qos>2) return MOSQ_ERR_INVAL; - if(STREMPTY(topic)) return MOSQ_ERR_INVAL; - if(mosquitto_validate_utf8(topic, strlen(topic))) return MOSQ_ERR_MALFORMED_UTF8; - if(payloadlen < 0 || payloadlen > MQTT_MAX_PAYLOAD) return MOSQ_ERR_PAYLOAD_SIZE; - - if(mosquitto_pub_topic_check(topic) != MOSQ_ERR_SUCCESS){ - return MOSQ_ERR_INVAL; + const mosquitto_property *p; + bool have_topic_alias; + + if(!mosq || qos<0 || qos>2) return MOSQ_ERR_INVAL; + if(!topic || STREMPTY(topic)){ + if(topic) topic = NULL; + + if(mosq->protocol == mosq_p_mqtt5){ + p = properties; + have_topic_alias = false; + while(p){ + if(p->identifier == MQTT_PROP_TOPIC_ALIAS){ + have_topic_alias = true; + break; + } + p = p->next; + } + if(have_topic_alias == false){ + return MOSQ_ERR_INVAL; + } + }else{ + return MOSQ_ERR_INVAL; + } + }else{ + if(mosquitto_validate_utf8(topic, strlen(topic))) return MOSQ_ERR_MALFORMED_UTF8; + if(payloadlen < 0 || payloadlen > MQTT_MAX_PAYLOAD) return MOSQ_ERR_PAYLOAD_SIZE; + if(mosquitto_pub_topic_check(topic) != MOSQ_ERR_SUCCESS){ + return MOSQ_ERR_INVAL; + } } local_mid = mosquitto__mid_generate(mosq); @@ -62,10 +83,12 @@ int mosquitto_publish_with_properties(struct mosquitto *mosq, int *mid, const ch message->next = NULL; message->timestamp = mosquitto_time(); message->msg.mid = local_mid; - message->msg.topic = mosquitto__strdup(topic); - if(!message->msg.topic){ - message__cleanup(&message); - return MOSQ_ERR_NOMEM; + if(topic){ + message->msg.topic = mosquitto__strdup(topic); + if(!message->msg.topic){ + message__cleanup(&message); + return MOSQ_ERR_NOMEM; + } } if(payloadlen){ message->msg.payloadlen = payloadlen; diff --git a/lib/send_publish.c b/lib/send_publish.c index ef71ab7199..39878f8d5e 100644 --- a/lib/send_publish.c +++ b/lib/send_publish.c @@ -51,7 +51,6 @@ int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint3 #endif #endif assert(mosq); - assert(topic); #if defined(WITH_BROKER) && defined(WITH_WEBSOCKETS) if(mosq->sock == INVALID_SOCKET && !mosq->wsi) return MOSQ_ERR_NO_CONN; @@ -137,9 +136,12 @@ int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, int rc; assert(mosq); - assert(topic); - packetlen = 2+strlen(topic) + payloadlen; + if(topic){ + packetlen = 2+strlen(topic) + payloadlen; + }else{ + packetlen = 2 + payloadlen; + } if(qos > 0) packetlen += 2; /* For message id */ if(mosq->protocol == mosq_p_mqtt5){ proplen = property__get_length_all(properties); @@ -163,7 +165,11 @@ int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, return rc; } /* Variable header (topic string) */ - packet__write_string(packet, topic, strlen(topic)); + if(topic){ + packet__write_string(packet, topic, strlen(topic)); + }else{ + packet__write_uint16(packet, 0); + } if(qos > 0){ packet__write_uint16(packet, mid); } From 4c0c632dfac9430a4b5ad3513e6e5a4990fcfb28 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 1 Nov 2018 16:02:20 +0000 Subject: [PATCH 081/254] Client memory "leak" fixes. --- client/client_shared.c | 7 +++++-- client/pub_client.c | 45 +++++++++++++++++++++--------------------- client/sub_client.c | 28 +++++++++++++++----------- 3 files changed, 44 insertions(+), 36 deletions(-) diff --git a/client/client_shared.c b/client/client_shared.c index 1e2240b562..41fefa9037 100644 --- a/client/client_shared.c +++ b/client/client_shared.c @@ -184,7 +184,6 @@ void client_config_cleanup(struct mosq_config *cfg) mosquitto_property_free_all(&cfg->subscribe_props); mosquitto_property_free_all(&cfg->unsubscribe_props); mosquitto_property_free_all(&cfg->disconnect_props); - mosquitto_property_free_all(&cfg->will_props); } int client_config_load(struct mosq_config *cfg, int pub_or_sub, int argc, char *argv[]) @@ -339,7 +338,11 @@ int client_config_load(struct mosq_config *cfg, int pub_or_sub, int argc, char * } if(!cfg->host){ - cfg->host = "localhost"; + cfg->host = strdup("localhost"); + if(!cfg->host){ + if(!cfg->quiet) fprintf(stderr, "Error: Out of memory.\n"); + return 1; + } } return MOSQ_ERR_SUCCESS; } diff --git a/client/pub_client.c b/client/pub_client.c index ff38e8eeca..9b5291db55 100644 --- a/client/pub_client.c +++ b/client/pub_client.c @@ -326,18 +326,18 @@ int main(int argc, char *argv[]) return 1; } + mosquitto_lib_init(); + memset(&cfg, 0, sizeof(struct mosq_config)); rc = client_config_load(&cfg, CLIENT_PUB, argc, argv); if(rc){ - client_config_cleanup(&cfg); if(rc == 2){ /* --help */ print_usage(); }else{ fprintf(stderr, "\nUse 'mosquitto_pub --help' to see usage.\n"); } - free(buf); - return 1; + goto cleanup; } topic = cfg.topic; @@ -353,38 +353,31 @@ int main(int argc, char *argv[]) #ifndef WITH_THREADING if(cfg.pub_mode == MSGMODE_STDIN_LINE){ fprintf(stderr, "Error: '-l' mode not available, threading support has not been compiled in.\n"); - free(buf); - return 1; + goto cleanup; } #endif if(cfg.pub_mode == MSGMODE_STDIN_FILE){ if(load_stdin()){ fprintf(stderr, "Error loading input from stdin.\n"); - free(buf); - return 1; + goto cleanup; } }else if(cfg.file_input){ if(load_file(cfg.file_input)){ fprintf(stderr, "Error loading input file \"%s\".\n", cfg.file_input); - free(buf); - return 1; + goto cleanup; } } if(!topic || mode == MSGMODE_NONE){ fprintf(stderr, "Error: Both topic and message must be supplied.\n"); print_usage(); - free(buf); - return 1; + goto cleanup; } - mosquitto_lib_init(); - if(client_id_generate(&cfg, "mosqpub")){ - free(buf); - return 1; + goto cleanup; } mosq = mosquitto_new(cfg.id, true, NULL); @@ -397,9 +390,7 @@ int main(int argc, char *argv[]) if(!quiet) fprintf(stderr, "Error: Invalid id.\n"); break; } - mosquitto_lib_cleanup(); - free(buf); - return 1; + goto cleanup; } if(cfg.debug){ mosquitto_log_callback_set(mosq, my_log_callback); @@ -409,11 +400,12 @@ int main(int argc, char *argv[]) mosquitto_publish_callback_set(mosq, my_publish_callback); if(client_opts_set(mosq, &cfg)){ - free(buf); - return 1; + goto cleanup; } rc = client_connect(mosq, &cfg); - if(rc) return rc; + if(rc){ + goto cleanup; + } if(mode == MSGMODE_STDIN_LINE){ mosquitto_loop_start(mosq); @@ -440,9 +432,8 @@ int main(int argc, char *argv[]) read_len = 1024; buf2 = realloc(buf, buf_len); if(!buf2){ - free(buf); fprintf(stderr, "Error: Out of memory.\n"); - return 1; + goto cleanup; } buf = buf2; } @@ -487,9 +478,17 @@ int main(int argc, char *argv[]) } mosquitto_destroy(mosq); mosquitto_lib_cleanup(); + client_config_cleanup(&cfg); + free(buf); if(rc){ fprintf(stderr, "Error: %s\n", mosquitto_strerror(rc)); } return rc; + +cleanup: + mosquitto_lib_cleanup(); + client_config_cleanup(&cfg); + free(buf); + return 1; } diff --git a/client/sub_client.c b/client/sub_client.c index ce6d4171e7..8a9cf3a9a2 100644 --- a/client/sub_client.c +++ b/client/sub_client.c @@ -235,27 +235,26 @@ int main(int argc, char *argv[]) memset(&cfg, 0, sizeof(struct mosq_config)); + mosquitto_lib_init(); + rc = client_config_load(&cfg, CLIENT_SUB, argc, argv); if(rc){ - client_config_cleanup(&cfg); if(rc == 2){ /* --help */ print_usage(); }else{ fprintf(stderr, "\nUse 'mosquitto_sub --help' to see usage.\n"); } - return 1; + goto cleanup; } if(cfg.no_retain && cfg.retained_only){ fprintf(stderr, "\nError: Combining '-R' and '--retained-only' makes no sense.\n"); - return 1; + goto cleanup; } - mosquitto_lib_init(); - if(client_id_generate(&cfg, "mosqsub")){ - return 1; + goto cleanup; } mosq = mosquitto_new(cfg.id, cfg.clean_session, &cfg); @@ -268,11 +267,10 @@ int main(int argc, char *argv[]) if(!cfg.quiet) fprintf(stderr, "Error: Invalid id and/or clean_session.\n"); break; } - mosquitto_lib_cleanup(); - return 1; + goto cleanup; } if(client_opts_set(mosq, &cfg)){ - return 1; + goto cleanup; } if(cfg.debug){ mosquitto_log_callback_set(mosq, my_log_callback); @@ -282,7 +280,9 @@ int main(int argc, char *argv[]) mosquitto_message_callback_set(mosq, my_message_callback); rc = client_connect(mosq, &cfg); - if(rc) return rc; + if(rc){ + goto cleanup; + } #ifndef WIN32 sigact.sa_handler = my_signal_handler; @@ -291,7 +291,7 @@ int main(int argc, char *argv[]) if(sigaction(SIGALRM, &sigact, NULL) == -1){ perror("sigaction"); - return 1; + goto cleanup; } if(cfg.timeout){ @@ -307,9 +307,15 @@ int main(int argc, char *argv[]) if(cfg.msg_count>0 && rc == MOSQ_ERR_NO_CONN){ rc = 0; } + client_config_cleanup(&cfg); if(rc){ fprintf(stderr, "Error: %s\n", mosquitto_strerror(rc)); } return rc; + +cleanup: + mosquitto_lib_cleanup(); + client_config_cleanup(&cfg); + return 1; } From 4ca83c1768c3fea245eeea026367605cb3cc1d35 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 1 Nov 2018 16:50:23 +0000 Subject: [PATCH 082/254] Fix leak when handling publish props. --- src/handle_publish.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/handle_publish.c b/src/handle_publish.c index e190f928e5..fe47c855e5 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -163,28 +163,31 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) } if(p_prev){ p_prev->next = p->next; - msg_properties_last->next = NULL; p = p_prev->next; }else{ properties = p->next; - msg_properties_last->next = NULL; p = properties; } + msg_properties_last->next = NULL; break; case MQTT_PROP_TOPIC_ALIAS: + p_prev = p; p = p->next; break; case MQTT_PROP_RESPONSE_TOPIC: + p_prev = p; p = p->next; break; case MQTT_PROP_MESSAGE_EXPIRY_INTERVAL: + p_prev = p; p = p->next; break; case MQTT_PROP_SUBSCRIPTION_IDENTIFIER: + p_prev = p; p = p->next; break; From f9e0fa246a1e3b79611b229fcdffc28559c587e8 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 1 Nov 2018 18:53:06 +0000 Subject: [PATCH 083/254] Validate properties coming into client library. --- client/client_props.c | 2 +- client/client_shared.c | 36 ++++++++++++ lib/actions.c | 24 ++++++++ lib/connect.c | 13 +++++ lib/linker.version | 3 +- lib/mosquitto.c | 2 + lib/mosquitto.h | 39 ++++++++++++- lib/options.c | 9 +++ lib/property_mosq.c | 123 ++++++++++++++++++++--------------------- lib/will_mosq.c | 2 +- 10 files changed, 184 insertions(+), 69 deletions(-) diff --git a/client/client_props.c b/client/client_props.c index 1e6415141d..71dcc2d4c1 100644 --- a/client/client_props.c +++ b/client/client_props.c @@ -85,7 +85,7 @@ int cfg_parse_property(struct mosq_config *cfg, int argc, char *argv[], int *idx return MOSQ_ERR_INVAL; } - if(mosquitto_property_command_check(cmd, identifier)){ + if(mosquitto_property_check_command(cmd, identifier)){ fprintf(stderr, "Error: %s property not allow for %s in --property argument.\n\n", propname, cmdname); return MOSQ_ERR_INVAL; } diff --git a/client/client_shared.c b/client/client_shared.c index 41fefa9037..fb1ba31000 100644 --- a/client/client_shared.c +++ b/client/client_shared.c @@ -32,6 +32,7 @@ and the Eclipse Distribution License is available at #endif #include +#include #include "client_shared.h" static int mosquitto__parse_socks_url(struct mosq_config *cfg, char *url); @@ -184,6 +185,7 @@ void client_config_cleanup(struct mosq_config *cfg) mosquitto_property_free_all(&cfg->subscribe_props); mosquitto_property_free_all(&cfg->unsubscribe_props); mosquitto_property_free_all(&cfg->disconnect_props); + mosquitto_property_free_all(&cfg->will_props); } int client_config_load(struct mosq_config *cfg, int pub_or_sub, int argc, char *argv[]) @@ -344,6 +346,38 @@ int client_config_load(struct mosq_config *cfg, int pub_or_sub, int argc, char * return 1; } } + + rc = mosquitto_property_check_all(CMD_CONNECT, cfg->connect_props); + if(rc){ + if(!cfg->quiet) fprintf(stderr, "Error in CONNECT properties: %s\n", mosquitto_strerror(rc)); + return 1; + } + rc = mosquitto_property_check_all(CMD_PUBLISH, cfg->publish_props); + if(rc){ + if(!cfg->quiet) fprintf(stderr, "Error in PUBLISH properties: %s\n", mosquitto_strerror(rc)); + return 1; + } + rc = mosquitto_property_check_all(CMD_SUBSCRIBE, cfg->subscribe_props); + if(rc){ + if(!cfg->quiet) fprintf(stderr, "Error in SUBSCRIBE properties: %s\n", mosquitto_strerror(rc)); + return 1; + } + rc = mosquitto_property_check_all(CMD_UNSUBSCRIBE, cfg->unsubscribe_props); + if(rc){ + if(!cfg->quiet) fprintf(stderr, "Error in UNSUBSCRIBE properties: %s\n", mosquitto_strerror(rc)); + return 1; + } + rc = mosquitto_property_check_all(CMD_DISCONNECT, cfg->disconnect_props); + if(rc){ + if(!cfg->quiet) fprintf(stderr, "Error in DISCONNECT properties: %s\n", mosquitto_strerror(rc)); + return 1; + } + rc = mosquitto_property_check_all(CMD_WILL, cfg->will_props); + if(rc){ + if(!cfg->quiet) fprintf(stderr, "Error in Will properties: %s\n", mosquitto_strerror(rc)); + return 1; + } + return MOSQ_ERR_SUCCESS; } @@ -918,6 +952,8 @@ int client_opts_set(struct mosquitto *mosq, struct mosq_config *cfg) mosquitto_lib_cleanup(); return 1; } + cfg->will_props = NULL; + if(cfg->username && mosquitto_username_pw_set(mosq, cfg->username, cfg->password)){ if(!cfg->quiet) fprintf(stderr, "Error: Problem setting username and password.\n"); mosquitto_lib_cleanup(); diff --git a/lib/actions.c b/lib/actions.c index 3582697155..e0ccf0f370 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -40,6 +40,7 @@ int mosquitto_publish_with_properties(struct mosquitto *mosq, int *mid, const ch int queue_status; const mosquitto_property *p; bool have_topic_alias; + int rc; if(!mosq || qos<0 || qos>2) return MOSQ_ERR_INVAL; if(!topic || STREMPTY(topic)){ @@ -68,6 +69,10 @@ int mosquitto_publish_with_properties(struct mosquitto *mosq, int *mid, const ch return MOSQ_ERR_INVAL; } } + if(properties){ + rc = mosquitto_property_check_all(CMD_PUBLISH, properties); + if(rc) return rc; + } local_mid = mosquitto__mid_generate(mosq); if(mid){ @@ -132,12 +137,19 @@ int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const char *sub, int q int mosquitto_subscribe_with_properties(struct mosquitto *mosq, int *mid, const char *sub, int qos, const mosquitto_property *properties) { + int rc; + if(!mosq) return MOSQ_ERR_INVAL; if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; if(mosquitto_sub_topic_check(sub)) return MOSQ_ERR_INVAL; if(mosquitto_validate_utf8(sub, strlen(sub))) return MOSQ_ERR_MALFORMED_UTF8; + if(properties){ + rc = mosquitto_property_check_all(CMD_SUBSCRIBE, properties); + if(rc) return rc; + } + return send__subscribe(mosq, mid, 1, (char *const *const)&sub, qos, properties); } @@ -145,11 +157,17 @@ int mosquitto_subscribe_with_properties(struct mosquitto *mosq, int *mid, const int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, int qos, const mosquitto_property *properties) { int i; + int rc; if(!mosq || !sub_count || !sub) return MOSQ_ERR_INVAL; if(qos < 0 || qos > 2) return MOSQ_ERR_INVAL; if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; + if(mosq->protocol == mosq_p_mqtt5 && properties){ + rc = mosquitto_property_check_all(CMD_SUBSCRIBE, properties); + if(rc) return rc; + } + for(i=0; isock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; if(mosquitto_sub_topic_check(sub)) return MOSQ_ERR_INVAL; if(mosquitto_validate_utf8(sub, strlen(sub))) return MOSQ_ERR_MALFORMED_UTF8; + if(properties){ + rc = mosquitto_property_check_all(CMD_PUBLISH, properties); + if(rc) return rc; + } return send__unsubscribe(mosq, mid, sub, properties); } diff --git a/lib/connect.c b/lib/connect.c index 88eecca344..100d7e9f5b 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -22,6 +22,7 @@ and the Eclipse Distribution License is available at #include "messages_mosq.h" #include "memory_mosq.h" #include "packet_mosq.h" +#include "mqtt_protocol.h" #include "net_mosq.h" #include "send_mosq.h" #include "socks_mosq.h" @@ -80,6 +81,12 @@ int mosquitto_connect_bind(struct mosquitto *mosq, const char *host, int port, i int mosquitto_connect_bind_with_properties(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address, const mosquitto_property *properties) { int rc; + + if(properties){ + rc = mosquitto_property_check_all(CMD_CONNECT, properties); + if(rc) return rc; + } + rc = mosquitto__connect_init(mosq, host, port, keepalive, bind_address); if(rc) return rc; @@ -210,8 +217,14 @@ int mosquitto_disconnect(struct mosquitto *mosq) int mosquitto_disconnect_with_properties(struct mosquitto *mosq, const mosquitto_property *properties) { + int rc; if(!mosq) return MOSQ_ERR_INVAL; + if(properties){ + rc = mosquitto_property_check_all(CMD_DISCONNECT, properties); + if(rc) return rc; + } + pthread_mutex_lock(&mosq->state_mutex); mosq->state = mosq_cs_disconnecting; pthread_mutex_unlock(&mosq->state_mutex); diff --git a/lib/linker.version b/lib/linker.version index 499aa303dc..ccebe673e3 100644 --- a/lib/linker.version +++ b/lib/linker.version @@ -104,7 +104,8 @@ MOSQ_1.6 { mosquitto_property_add_string_pair; mosquitto_property_add_varint; mosquitto_property_free_all; - mosquitto_property_command_check; + mosquitto_property_check_command; + mosquitto_property_check_all; mosquitto_publish_with_properties; mosquitto_string_to_command; mosquitto_string_to_property_info; diff --git a/lib/mosquitto.c b/lib/mosquitto.c index ebecbdc939..be449fbe03 100644 --- a/lib/mosquitto.c +++ b/lib/mosquitto.c @@ -373,6 +373,8 @@ const char *mosquitto_strerror(int mosq_errno) return "Proxy error."; case MOSQ_ERR_MALFORMED_UTF8: return "Malformed UTF-8"; + case MOSQ_ERR_DUPLICATE_PROPERTY: + return "Duplicate property in property list"; default: return "Unknown error."; } diff --git a/lib/mosquitto.h b/lib/mosquitto.h index b5eba8af72..9dccb3df08 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -89,6 +89,7 @@ enum mosq_err_t { MOSQ_ERR_KEEPALIVE = 19, MOSQ_ERR_LOOKUP = 20, MOSQ_ERR_MALFORMED_PACKET = 19, + MOSQ_ERR_DUPLICATE_PROPERTY = 20, }; /* Error values */ @@ -347,6 +348,7 @@ libmosq_EXPORT int mosquitto_will_set(struct mosquitto *mosq, const char *topic, * MOSQ_ERR_NOT_SUPPORTED - if properties is not NULL and the client is not * using MQTT v5 * MOSQ_ERR_PROTOCOL - if a property is invalid for use with wills. + * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. */ libmosq_EXPORT int mosquitto_will_set_with_properties(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain, mosquitto_property *properties); @@ -483,6 +485,8 @@ libmosq_EXPORT int mosquitto_connect_bind(struct mosquitto *mosq, const char *ho * contains the error code, even on Windows. * Use strerror_r() where available or FormatMessage() on * Windows. + * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. + * MOSQ_ERR_PROTOCOL - if any property is invalid for use with CONNECT. * * See Also: * , , @@ -687,6 +691,8 @@ libmosq_EXPORT int mosquitto_disconnect(struct mosquitto *mosq); * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. + * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. + * MOSQ_ERR_PROTOCOL - if any property is invalid for use with DISCONNECT. */ libmosq_EXPORT int mosquitto_disconnect_with_properties(struct mosquitto *mosq, const mosquitto_property *properties); @@ -774,6 +780,8 @@ libmosq_EXPORT int mosquitto_publish(struct mosquitto *mosq, int *mid, const cha * broker. * MOSQ_ERR_PAYLOAD_SIZE - if payloadlen is too large. * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8 + * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. + * MOSQ_ERR_PROTOCOL - if any property is invalid for use with PUBLISH. */ libmosq_EXPORT int mosquitto_publish_with_properties( struct mosquitto *mosq, @@ -837,6 +845,8 @@ libmosq_EXPORT int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const c * 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_MALFORMED_UTF8 - if the topic is not valid UTF-8 + * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. + * MOSQ_ERR_PROTOCOL - if any property is invalid for use with SUBSCRIBE. */ libmosq_EXPORT int mosquitto_subscribe_with_properties(struct mosquitto *mosq, int *mid, const char *sub, int qos, const mosquitto_property *properties); @@ -913,6 +923,8 @@ libmosq_EXPORT int mosquitto_unsubscribe(struct mosquitto *mosq, int *mid, const * 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_MALFORMED_UTF8 - if the topic is not valid UTF-8 + * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. + * MOSQ_ERR_PROTOCOL - if any property is invalid for use with UNSUBSCRIBE. */ libmosq_EXPORT int mosquitto_unsubscribe_with_properties(struct mosquitto *mosq, int *mid, const char *sub, const mosquitto_property *properties); @@ -2285,7 +2297,7 @@ libmosq_EXPORT int mosquitto_property_add_string_pair(mosquitto_property **propl libmosq_EXPORT void mosquitto_property_free_all(mosquitto_property **properties); /* - * Function: mosquitto_property_command_check + * Function: mosquitto_property_check_command * * Check whether a property identifier is valid for the given command. * @@ -2297,7 +2309,30 @@ libmosq_EXPORT void mosquitto_property_free_all(mosquitto_property **properties) * MOSQ_ERR_SUCCESS - if the identifier is valid for command * MOSQ_ERR_PROTOCOL - if the identifier is not valid for use with command. */ -libmosq_EXPORT int mosquitto_property_command_check(int command, int identifier); +libmosq_EXPORT int mosquitto_property_check_command(int command, int identifier); + + +/* + * Function: mosquitto_property_check_all + * + * Check whether a list of properties are valid for a particular command, + * whether there are duplicates, and whether the values are valid where + * possible. + * + * Note that this function is used internally in the library whenever + * properties are passed to it, so in basic use this is not needed, but should + * be helpful to check property lists *before* the point of using them. + * + * Parameters: + * command - MQTT command (e.g. CMD_CONNECT) + * properties - list of MQTT properties to check. + * + * Returns: + * MOSQ_ERR_SUCCESS - if all properties are valid + * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. + * MOSQ_ERR_PROTOCOL - if any property is invalid + */ +libmosq_EXPORT int mosquitto_property_check_all(int command, const mosquitto_property *properties); /* Function: mosquitto_string_to_property_info * diff --git a/lib/options.c b/lib/options.c index 12a19d8b6c..4a66f30902 100644 --- a/lib/options.c +++ b/lib/options.c @@ -25,6 +25,7 @@ and the Eclipse Distribution License is available at #include "mosquitto.h" #include "mosquitto_internal.h" #include "memory_mosq.h" +#include "mqtt_protocol.h" #include "util_mosq.h" #include "will_mosq.h" @@ -37,7 +38,15 @@ int mosquitto_will_set(struct mosquitto *mosq, const char *topic, int payloadlen int mosquitto_will_set_with_properties(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain, mosquitto_property *properties) { + int rc; + if(!mosq) return MOSQ_ERR_INVAL; + + if(properties){ + rc = mosquitto_property_check_all(CMD_WILL, properties); + if(rc) return rc; + } + return will__set(mosq, topic, payloadlen, payload, qos, retain, properties); } diff --git a/lib/property_mosq.c b/lib/property_mosq.c index be8ef05e03..e932d96046 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -26,8 +26,6 @@ and the Eclipse Distribution License is available at #include "packet_mosq.h" #include "property_mosq.h" -static int property__command_check(int command, struct mqtt5__property *properties); - int property__read(struct mosquitto__packet *packet, int32_t *len, struct mqtt5__property *property) { @@ -146,7 +144,6 @@ int property__read_all(int command, struct mosquitto__packet *packet, struct mqt int rc; int32_t proplen; struct mqtt5__property *p, *tail = NULL; - struct mqtt5__property *current; rc = packet__read_varint(packet, &proplen, NULL); if(rc) return rc; @@ -172,54 +169,12 @@ int property__read_all(int command, struct mosquitto__packet *packet, struct mqt } tail = p; - /* Validity checks */ - if(p->identifier == MQTT_PROP_REQUEST_PROBLEM_INFORMATION - || p->identifier == MQTT_PROP_REQUEST_RESPONSE_INFORMATION - || p->identifier == MQTT_PROP_MAXIMUM_QOS - || p->identifier == MQTT_PROP_RETAIN_AVAILABLE - || p->identifier == MQTT_PROP_WILDCARD_SUB_AVAILABLE - || p->identifier == MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE - || p->identifier == MQTT_PROP_SHARED_SUB_AVAILABLE){ - - if(p->value.i8 > 1){ - mosquitto_property_free_all(properties); - return MOSQ_ERR_PROTOCOL; - } - }else if(p->identifier == MQTT_PROP_MAXIMUM_PACKET_SIZE){ - if( p->value.i32 == 0){ - mosquitto_property_free_all(properties); - return MOSQ_ERR_PROTOCOL; - } - }else if(p->identifier == MQTT_PROP_RECEIVE_MAXIMUM - || p->identifier == MQTT_PROP_TOPIC_ALIAS){ - - if(p->value.i16 == 0){ - mosquitto_property_free_all(properties); - return MOSQ_ERR_PROTOCOL; - } - } } - /* Check for duplicates */ - current = *properties; - while(current){ - tail = current->next; - while(tail){ - if(current->identifier == tail->identifier - && current->identifier != MQTT_PROP_USER_PROPERTY){ - - mosquitto_property_free_all(properties); - return MOSQ_ERR_PROTOCOL; - } - tail = tail->next; - } - current = current->next; - } - - /* Check for properties on incorrect commands */ - if(property__command_check(command, *properties)){ + rc = mosquitto_property_check_all(command, *properties); + if(rc){ mosquitto_property_free_all(properties); - return MOSQ_ERR_PROTOCOL; + return rc; } return MOSQ_ERR_SUCCESS; } @@ -280,6 +235,8 @@ void mosquitto_property_free_all(struct mqtt5__property **property) { struct mqtt5__property *p, *next; + if(!property) return; + p = *property; while(p){ next = p->next; @@ -459,7 +416,7 @@ int property__write_all(struct mosquitto__packet *packet, const struct mqtt5__pr } -int mosquitto_property_command_check(int command, int identifier) +int mosquitto_property_check_command(int command, int identifier) { switch(identifier){ case MQTT_PROP_PAYLOAD_FORMAT_INDICATOR: @@ -552,21 +509,6 @@ int mosquitto_property_command_check(int command, int identifier) return MOSQ_ERR_SUCCESS; } -static int property__command_check(int command, struct mqtt5__property *properties) -{ - struct mqtt5__property *p; - int rc; - - p = properties; - while(p){ - rc = mosquitto_property_command_check(command, p->identifier); - if(rc) return rc; - - p = p->next; - } - return MOSQ_ERR_SUCCESS; -} - int mosquitto_string_to_property_info(const char *propname, int *identifier, int *type) { @@ -878,3 +820,56 @@ int mosquitto_property_add_string_pair(mosquitto_property **proplist, int identi property__add(proplist, prop); return MOSQ_ERR_SUCCESS; } + +int mosquitto_property_check_all(int command, const mosquitto_property *properties) +{ + const mosquitto_property *p, *tail; + int rc; + + p = properties; + + while(p){ + /* Validity checks */ + if(p->identifier == MQTT_PROP_REQUEST_PROBLEM_INFORMATION + || p->identifier == MQTT_PROP_REQUEST_RESPONSE_INFORMATION + || p->identifier == MQTT_PROP_MAXIMUM_QOS + || p->identifier == MQTT_PROP_RETAIN_AVAILABLE + || p->identifier == MQTT_PROP_WILDCARD_SUB_AVAILABLE + || p->identifier == MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE + || p->identifier == MQTT_PROP_SHARED_SUB_AVAILABLE){ + + if(p->value.i8 > 1){ + return MOSQ_ERR_PROTOCOL; + } + }else if(p->identifier == MQTT_PROP_MAXIMUM_PACKET_SIZE){ + if( p->value.i32 == 0){ + return MOSQ_ERR_PROTOCOL; + } + }else if(p->identifier == MQTT_PROP_RECEIVE_MAXIMUM + || p->identifier == MQTT_PROP_TOPIC_ALIAS){ + + if(p->value.i16 == 0){ + return MOSQ_ERR_PROTOCOL; + } + } + + /* Check for properties on incorrect commands */ + rc = mosquitto_property_check_command(command, p->identifier); + if(rc) return rc; + + /* Check for duplicates */ + tail = p->next; + while(tail){ + if(p->identifier == tail->identifier + && p->identifier != MQTT_PROP_USER_PROPERTY){ + + return MOSQ_ERR_DUPLICATE_PROPERTY; + } + tail = tail->next; + } + + p = p->next; + } + + return MOSQ_ERR_SUCCESS; +} diff --git a/lib/will_mosq.c b/lib/will_mosq.c index b9a13b9d9f..154badbc89 100644 --- a/lib/will_mosq.c +++ b/lib/will_mosq.c @@ -53,7 +53,7 @@ int will__set(struct mosquitto *mosq, const char *topic, int payloadlen, const v } p = properties; while(p){ - rc = mosquitto_property_command_check(CMD_WILL, p->identifier); + rc = mosquitto_property_check_command(CMD_WILL, p->identifier); if(rc) return rc; p = p->next; } From 80f526a5e58c95f00eb908bee71fdb9e75af615f Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 1 Nov 2018 21:51:35 +0000 Subject: [PATCH 084/254] Message Expiry Interval support. --- src/database.c | 16 ++++++++++++++-- src/handle_publish.c | 12 ++++++++++-- src/mosquitto_broker_internal.h | 3 ++- src/persist.c | 2 +- 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/database.c b/src/database.c index 236d5bf052..5cf640fcc1 100644 --- a/src/database.c +++ b/src/database.c @@ -590,13 +590,13 @@ int db__messages_easy_queue(struct mosquitto_db *db, struct mosquitto *context, local_properties = *properties; *properties = NULL; } - if(db__message_store(db, source_id, 0, topic_heap, qos, payloadlen, &payload_uhpa, retain, &stored, local_properties, 0)) return 1; + if(db__message_store(db, source_id, 0, topic_heap, qos, payloadlen, &payload_uhpa, retain, &stored, 0, local_properties, 0)) return 1; return sub__messages_queue(db, source_id, topic_heap, qos, retain, &stored); } /* This function requires topic to be allocated on the heap. Once called, it owns topic and will free it on error. Likewise payload and properties. */ -int db__message_store(struct mosquitto_db *db, const char *source, uint16_t source_mid, char *topic, int qos, uint32_t payloadlen, mosquitto__payload_uhpa *payload, int retain, struct mosquitto_msg_store **stored, struct mqtt5__property *properties, dbid_t store_id) +int db__message_store(struct mosquitto_db *db, const char *source, uint16_t source_mid, char *topic, int qos, uint32_t payloadlen, mosquitto__payload_uhpa *payload, int retain, struct mosquitto_msg_store **stored, uint32_t message_expiry_interval, struct mqtt5__property *properties, dbid_t store_id) { struct mosquitto_msg_store *temp = NULL; int rc = MOSQ_ERR_SUCCESS; @@ -638,6 +638,11 @@ int db__message_store(struct mosquitto_db *db, const char *source, uint16_t sour }else{ temp->payload.ptr = NULL; } + if(message_expiry_interval > 0){ + temp->message_expiry_time = time(NULL) + message_expiry_interval; + }else{ + temp->message_expiry_time = 0; + } temp->dest_ids = NULL; temp->dest_id_count = 0; @@ -867,6 +872,7 @@ int db__message_write(struct mosquitto_db *db, struct mosquitto *context) const void *payload; int msg_count = 0; struct mqtt5__property *properties; + time_t now; if(!context || context->sock == INVALID_SOCKET || (context->state == mosq_cs_connected && !context->id)){ @@ -877,9 +883,15 @@ int db__message_write(struct mosquitto_db *db, struct mosquitto *context) return MOSQ_ERR_SUCCESS; } + now = time(NULL); tail = context->inflight_msgs; while(tail){ msg_count++; + if(tail->store->message_expiry_time && now > tail->store->message_expiry_time){ + /* Message is expired, must not send. */ + db__message_remove(db, context, &tail, last); + continue; + } mid = tail->mid; retries = tail->dup; retain = tail->retain; diff --git a/src/handle_publish.c b/src/handle_publish.c index fe47c855e5..8862394e08 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -48,6 +48,7 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) struct mqtt5__property *properties = NULL; struct mqtt5__property *p, *p_prev; struct mqtt5__property *msg_properties = NULL, *msg_properties_last; + uint32_t message_expiry_interval = 0; #ifdef WITH_BRIDGE char *topic_temp; @@ -182,6 +183,7 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) break; case MQTT_PROP_MESSAGE_EXPIRY_INTERVAL: + message_expiry_interval = p->value.i32; p_prev = p; p = p->next; break; @@ -206,6 +208,7 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) topic_mount = mosquitto__malloc(len+1); if(!topic_mount){ mosquitto__free(topic); + mosquitto_property_free_all(&msg_properties); return MOSQ_ERR_NOMEM; } snprintf(topic_mount, len, "%s%s", context->listener->mount_point, topic); @@ -222,11 +225,13 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) } if(UHPA_ALLOC(payload, payloadlen+1) == 0){ mosquitto__free(topic); + mosquitto_property_free_all(&msg_properties); return MOSQ_ERR_NOMEM; } if(packet__read_bytes(&context->in_packet, UHPA_ACCESS(payload, payloadlen), payloadlen)){ mosquitto__free(topic); UHPA_FREE(payload, payloadlen); + mosquitto_property_free_all(&msg_properties); return 1; } } @@ -239,6 +244,7 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) }else if(rc != MOSQ_ERR_SUCCESS){ mosquitto__free(topic); UHPA_FREE(payload, payloadlen); + mosquitto_property_free_all(&msg_properties); return rc; } @@ -248,7 +254,8 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) } if(!stored){ dup = 0; - if(db__message_store(db, context->id, mid, topic, qos, payloadlen, &payload, retain, &stored, msg_properties, 0)){ + if(db__message_store(db, context->id, mid, topic, qos, payloadlen, &payload, retain, &stored, message_expiry_interval, msg_properties, 0)){ + mosquitto_property_free_all(&msg_properties); return 1; } msg_properties = NULL; /* Now belongs to db__message_store() */ @@ -256,6 +263,7 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) mosquitto__free(topic); topic = stored->topic; dup = 1; + mosquitto_property_free_all(&msg_properties); } switch(qos){ @@ -294,7 +302,7 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) case 2: db__message_store_find(context, mid, &stored); if(!stored){ - if(db__message_store(db, context->id, mid, NULL, qos, 0, NULL, false, &stored, NULL, 0)){ + if(db__message_store(db, context->id, mid, NULL, qos, 0, NULL, false, &stored, 0, NULL, 0)){ return 1; } res = db__message_insert(db, context, mid, mosq_md_in, qos, false, stored); diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index 7a199b11f9..8140bb17e0 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -317,6 +317,7 @@ struct mosquitto_msg_store{ char* topic; struct mqtt5__property *properties; mosquitto__payload_uhpa payload; + time_t message_expiry_time; uint32_t payloadlen; uint16_t source_mid; uint16_t mid; @@ -555,7 +556,7 @@ int db__message_write(struct mosquitto_db *db, struct mosquitto *context); void db__message_dequeue_first(struct mosquitto *context); int db__messages_delete(struct mosquitto_db *db, struct mosquitto *context); int db__messages_easy_queue(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int qos, uint32_t payloadlen, const void *payload, int retain, struct mqtt5__property **properties); -int db__message_store(struct mosquitto_db *db, const char *source, uint16_t source_mid, char *topic, int qos, uint32_t payloadlen, mosquitto__payload_uhpa *payload, int retain, struct mosquitto_msg_store **stored, struct mqtt5__property *properties, dbid_t store_id); +int db__message_store(struct mosquitto_db *db, const char *source, uint16_t source_mid, char *topic, int qos, uint32_t payloadlen, mosquitto__payload_uhpa *payload, int retain, struct mosquitto_msg_store **stored, uint32_t message_expiry_interval, struct mqtt5__property *properties, dbid_t store_id); int db__message_store_find(struct mosquitto *context, uint16_t mid, struct mosquitto_msg_store **stored); void db__msg_store_add(struct mosquitto_db *db, struct mosquitto_msg_store *store); void db__msg_store_remove(struct mosquitto_db *db, struct mosquitto_msg_store *store); diff --git a/src/persist.c b/src/persist.c index cccd04ade7..c434a41e0f 100644 --- a/src/persist.c +++ b/src/persist.c @@ -717,7 +717,7 @@ static int persist__msg_store_chunk_restore(struct mosquitto_db *db, FILE *db_fp read_e(db_fptr, UHPA_ACCESS(payload, payloadlen), payloadlen); } - rc = db__message_store(db, source_id, source_mid, topic, qos, payloadlen, &payload, retain, &stored, NULL, store_id); + rc = db__message_store(db, source_id, source_mid, topic, qos, payloadlen, &payload, retain, &stored, 0, NULL, store_id); mosquitto__free(source_id); if(rc == MOSQ_ERR_SUCCESS){ From f77c1ca91b54ed706b07af00e2d171107bc9cda2 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 1 Nov 2018 23:50:54 +0000 Subject: [PATCH 085/254] private struct mqtt5__property -> public mosquitto_property. --- lib/connect.c | 2 +- lib/handle_auth.c | 2 +- lib/handle_connack.c | 2 +- lib/handle_pubackcomp.c | 2 +- lib/handle_publish.c | 2 +- lib/handle_pubrec.c | 2 +- lib/handle_pubrel.c | 2 +- lib/handle_suback.c | 2 +- lib/handle_unsuback.c | 2 +- lib/mosquitto_internal.h | 2 +- lib/property_mosq.c | 60 ++++++++++++++++----------------- lib/property_mosq.h | 10 +++--- lib/send_connect.c | 2 +- lib/send_disconnect.c | 2 +- lib/send_mosq.c | 2 +- lib/send_mosq.h | 12 +++---- lib/send_publish.c | 4 +-- lib/send_subscribe.c | 2 +- src/database.c | 8 ++--- src/handle_auth.c | 2 +- src/handle_connack.c | 2 +- src/handle_connect.c | 4 +-- src/handle_publish.c | 6 ++-- src/handle_subscribe.c | 2 +- src/handle_unsubscribe.c | 2 +- src/mosquitto_broker_internal.h | 8 ++--- src/send_connack.c | 2 +- src/send_suback.c | 2 +- src/send_unsuback.c | 2 +- test/unit/property_read.c | 36 ++++++++++---------- test/unit/property_write.c | 46 ++++++++++++------------- 31 files changed, 118 insertions(+), 118 deletions(-) diff --git a/lib/connect.c b/lib/connect.c index 100d7e9f5b..f0f369148d 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -27,7 +27,7 @@ and the Eclipse Distribution License is available at #include "send_mosq.h" #include "socks_mosq.h" -static int mosquitto__reconnect(struct mosquitto *mosq, bool blocking, const struct mqtt5__property *properties); +static int mosquitto__reconnect(struct mosquitto *mosq, bool blocking, const mosquitto_property *properties); static int mosquitto__connect_init(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address); diff --git a/lib/handle_auth.c b/lib/handle_auth.c index fa798ee333..5b84d3de31 100644 --- a/lib/handle_auth.c +++ b/lib/handle_auth.c @@ -30,7 +30,7 @@ int handle__auth(struct mosquitto *mosq) { int rc = 0; uint8_t reason_code; - struct mqtt5__property *properties = NULL; + mosquitto_property *properties = NULL; if(!mosq) return MOSQ_ERR_INVAL; log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received AUTH", mosq->id); diff --git a/lib/handle_connack.c b/lib/handle_connack.c index 0c96fdf9f1..ba11088315 100644 --- a/lib/handle_connack.c +++ b/lib/handle_connack.c @@ -33,7 +33,7 @@ int handle__connack(struct mosquitto *mosq) uint8_t connect_flags; uint8_t reason_code; int rc; - struct mqtt5__property *properties = NULL; + mosquitto_property *properties = NULL; assert(mosq); rc = packet__read_byte(&mosq->in_packet, &connect_flags); diff --git a/lib/handle_pubackcomp.c b/lib/handle_pubackcomp.c index 3f8ae22f9e..2169df7001 100644 --- a/lib/handle_pubackcomp.c +++ b/lib/handle_pubackcomp.c @@ -44,7 +44,7 @@ int handle__pubackcomp(struct mosquitto *mosq, const char *type) { uint16_t mid; int rc; - struct mqtt5__property *properties = NULL; + mosquitto_property *properties = NULL; assert(mosq); rc = packet__read_uint16(&mosq->in_packet, &mid); diff --git a/lib/handle_publish.c b/lib/handle_publish.c index 3bfd19fb9b..c3c53b583c 100644 --- a/lib/handle_publish.c +++ b/lib/handle_publish.c @@ -38,7 +38,7 @@ int handle__publish(struct mosquitto *mosq) int rc = 0; uint16_t mid; int slen; - struct mqtt5__property *properties = NULL; + mosquitto_property *properties = NULL; assert(mosq); diff --git a/lib/handle_pubrec.c b/lib/handle_pubrec.c index 778db6aacf..4bd580293f 100644 --- a/lib/handle_pubrec.c +++ b/lib/handle_pubrec.c @@ -39,7 +39,7 @@ int handle__pubrec(struct mosquitto *mosq) { uint16_t mid; int rc; - struct mqtt5__property *properties = NULL; + mosquitto_property *properties = NULL; assert(mosq); rc = packet__read_uint16(&mosq->in_packet, &mid); diff --git a/lib/handle_pubrel.c b/lib/handle_pubrel.c index 440791e871..d9d5dda53a 100644 --- a/lib/handle_pubrel.c +++ b/lib/handle_pubrel.c @@ -43,7 +43,7 @@ int handle__pubrel(struct mosquitto_db *db, struct mosquitto *mosq) struct mosquitto_message_all *message = NULL; #endif int rc; - struct mqtt5__property *properties = NULL; + mosquitto_property *properties = NULL; assert(mosq); if(mosq->protocol != mosq_p_mqtt31){ diff --git a/lib/handle_suback.c b/lib/handle_suback.c index c41297b8a6..65b71e52e2 100644 --- a/lib/handle_suback.c +++ b/lib/handle_suback.c @@ -39,7 +39,7 @@ int handle__suback(struct mosquitto *mosq) int qos_count; int i = 0; int rc; - struct mqtt5__property *properties = NULL; + mosquitto_property *properties = NULL; assert(mosq); #ifdef WITH_BROKER diff --git a/lib/handle_unsuback.c b/lib/handle_unsuback.c index 83050f6569..72ca3d58b4 100644 --- a/lib/handle_unsuback.c +++ b/lib/handle_unsuback.c @@ -41,7 +41,7 @@ int handle__unsuback(struct mosquitto *mosq) { uint16_t mid; int rc; - struct mqtt5__property *properties = NULL; + mosquitto_property *properties = NULL; assert(mosq); #ifdef WITH_BROKER diff --git a/lib/mosquitto_internal.h b/lib/mosquitto_internal.h index 2fac25bad2..e8fc1b7e3e 100644 --- a/lib/mosquitto_internal.h +++ b/lib/mosquitto_internal.h @@ -147,7 +147,7 @@ struct mosquitto__packet{ struct mosquitto_message_all{ struct mosquitto_message_all *next; - struct mqtt5__property *properties; + mosquitto_property *properties; time_t timestamp; //enum mosquitto_msg_direction direction; enum mosquitto_msg_state state; diff --git a/lib/property_mosq.c b/lib/property_mosq.c index e932d96046..4dd5c22e7c 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -27,7 +27,7 @@ and the Eclipse Distribution License is available at #include "property_mosq.h" -int property__read(struct mosquitto__packet *packet, int32_t *len, struct mqtt5__property *property) +int property__read(struct mosquitto__packet *packet, int32_t *len, mosquitto_property *property) { int rc; int32_t property_identifier; @@ -43,7 +43,7 @@ int property__read(struct mosquitto__packet *packet, int32_t *len, struct mqtt5_ if(rc) return rc; *len -= 1; - memset(property, 0, sizeof(struct mqtt5__property)); + memset(property, 0, sizeof(mosquitto_property)); property->identifier = property_identifier; @@ -139,11 +139,11 @@ int property__read(struct mosquitto__packet *packet, int32_t *len, struct mqtt5_ } -int property__read_all(int command, struct mosquitto__packet *packet, struct mqtt5__property **properties) +int property__read_all(int command, struct mosquitto__packet *packet, mosquitto_property **properties) { int rc; int32_t proplen; - struct mqtt5__property *p, *tail = NULL; + mosquitto_property *p, *tail = NULL; rc = packet__read_varint(packet, &proplen, NULL); if(rc) return rc; @@ -153,7 +153,7 @@ int property__read_all(int command, struct mosquitto__packet *packet, struct mqt /* The order of properties must be preserved for some types, so keep the * same order for all */ while(proplen > 0){ - p = mosquitto__calloc(1, sizeof(struct mqtt5__property)); + p = mosquitto__calloc(1, sizeof(mosquitto_property)); rc = property__read(packet, &proplen, p); if(rc){ @@ -180,7 +180,7 @@ int property__read_all(int command, struct mosquitto__packet *packet, struct mqt } -void property__free(struct mqtt5__property **property) +void property__free(mosquitto_property **property) { if(!property || !(*property)) return; @@ -231,9 +231,9 @@ void property__free(struct mqtt5__property **property) } -void mosquitto_property_free_all(struct mqtt5__property **property) +void mosquitto_property_free_all(mosquitto_property **property) { - struct mqtt5__property *p, *next; + mosquitto_property *p, *next; if(!property) return; @@ -247,7 +247,7 @@ void mosquitto_property_free_all(struct mqtt5__property **property) } -int property__get_length(const struct mqtt5__property *property) +int property__get_length(const mosquitto_property *property) { if(!property) return 0; @@ -317,9 +317,9 @@ int property__get_length(const struct mqtt5__property *property) } -int property__get_length_all(const struct mqtt5__property *property) +int property__get_length_all(const mosquitto_property *property) { - const struct mqtt5__property *p; + const mosquitto_property *p; int len = 0; p = property; @@ -331,7 +331,7 @@ int property__get_length_all(const struct mqtt5__property *property) } -int property__write(struct mosquitto__packet *packet, const struct mqtt5__property *property) +int property__write(struct mosquitto__packet *packet, const mosquitto_property *property) { int rc; @@ -397,10 +397,10 @@ int property__write(struct mosquitto__packet *packet, const struct mqtt5__proper } -int property__write_all(struct mosquitto__packet *packet, const struct mqtt5__property *properties) +int property__write_all(struct mosquitto__packet *packet, const mosquitto_property *properties) { int rc; - const struct mqtt5__property *p; + const mosquitto_property *p; rc = packet__write_varint(packet, property__get_length_all(properties)); if(rc) return rc; @@ -600,9 +600,9 @@ int mosquitto_string_to_property_info(const char *propname, int *identifier, int } -static void property__add(struct mqtt5__property **proplist, struct mqtt5__property *prop) +static void property__add(mosquitto_property **proplist, struct mqtt5__property *prop) { - struct mqtt5__property *p; + mosquitto_property *p; if(!(*proplist)){ *proplist = prop; @@ -619,7 +619,7 @@ static void property__add(struct mqtt5__property **proplist, struct mqtt5__prope int mosquitto_property_add_byte(mosquitto_property **proplist, int identifier, uint8_t value) { - struct mqtt5__property *prop; + mosquitto_property *prop; if(!proplist) return MOSQ_ERR_INVAL; if(identifier != MQTT_PROP_PAYLOAD_FORMAT_INDICATOR @@ -633,7 +633,7 @@ int mosquitto_property_add_byte(mosquitto_property **proplist, int identifier, u return MOSQ_ERR_INVAL; } - prop = mosquitto__calloc(1, sizeof(struct mqtt5__property)); + prop = mosquitto__calloc(1, sizeof(mosquitto_property)); if(!prop) return MOSQ_ERR_NOMEM; prop->identifier = identifier; @@ -646,7 +646,7 @@ int mosquitto_property_add_byte(mosquitto_property **proplist, int identifier, u int mosquitto_property_add_int16(mosquitto_property **proplist, int identifier, uint16_t value) { - struct mqtt5__property *prop; + mosquitto_property *prop; if(!proplist) return MOSQ_ERR_INVAL; if(identifier != MQTT_PROP_SERVER_KEEP_ALIVE @@ -656,7 +656,7 @@ int mosquitto_property_add_int16(mosquitto_property **proplist, int identifier, return MOSQ_ERR_INVAL; } - prop = mosquitto__calloc(1, sizeof(struct mqtt5__property)); + prop = mosquitto__calloc(1, sizeof(mosquitto_property)); if(!prop) return MOSQ_ERR_NOMEM; prop->identifier = identifier; @@ -669,7 +669,7 @@ int mosquitto_property_add_int16(mosquitto_property **proplist, int identifier, int mosquitto_property_add_int32(mosquitto_property **proplist, int identifier, uint32_t value) { - struct mqtt5__property *prop; + mosquitto_property *prop; if(!proplist) return MOSQ_ERR_INVAL; if(identifier != MQTT_PROP_MESSAGE_EXPIRY_INTERVAL @@ -680,7 +680,7 @@ int mosquitto_property_add_int32(mosquitto_property **proplist, int identifier, return MOSQ_ERR_INVAL; } - prop = mosquitto__calloc(1, sizeof(struct mqtt5__property)); + prop = mosquitto__calloc(1, sizeof(mosquitto_property)); if(!prop) return MOSQ_ERR_NOMEM; prop->identifier = identifier; @@ -693,12 +693,12 @@ int mosquitto_property_add_int32(mosquitto_property **proplist, int identifier, int mosquitto_property_add_varint(mosquitto_property **proplist, int identifier, uint32_t value) { - struct mqtt5__property *prop; + mosquitto_property *prop; if(!proplist || value > 268435455) return MOSQ_ERR_INVAL; if(identifier != MQTT_PROP_SUBSCRIPTION_IDENTIFIER) return MOSQ_ERR_INVAL; - prop = mosquitto__calloc(1, sizeof(struct mqtt5__property)); + prop = mosquitto__calloc(1, sizeof(mosquitto_property)); if(!prop) return MOSQ_ERR_NOMEM; prop->identifier = identifier; @@ -711,7 +711,7 @@ int mosquitto_property_add_varint(mosquitto_property **proplist, int identifier, int mosquitto_property_add_binary(mosquitto_property **proplist, int identifier, const void *value, uint16_t len) { - struct mqtt5__property *prop; + mosquitto_property *prop; if(!proplist) return MOSQ_ERR_INVAL; if(identifier != MQTT_PROP_CORRELATION_DATA @@ -720,7 +720,7 @@ int mosquitto_property_add_binary(mosquitto_property **proplist, int identifier, return MOSQ_ERR_INVAL; } - prop = mosquitto__calloc(1, sizeof(struct mqtt5__property)); + prop = mosquitto__calloc(1, sizeof(mosquitto_property)); if(!prop) return MOSQ_ERR_NOMEM; prop->identifier = identifier; @@ -743,7 +743,7 @@ int mosquitto_property_add_binary(mosquitto_property **proplist, int identifier, int mosquitto_property_add_string(mosquitto_property **proplist, int identifier, const char *value) { - struct mqtt5__property *prop; + mosquitto_property *prop; if(!proplist) return MOSQ_ERR_INVAL; if(value){ @@ -761,7 +761,7 @@ int mosquitto_property_add_string(mosquitto_property **proplist, int identifier, return MOSQ_ERR_INVAL; } - prop = mosquitto__calloc(1, sizeof(struct mqtt5__property)); + prop = mosquitto__calloc(1, sizeof(mosquitto_property)); if(!prop) return MOSQ_ERR_NOMEM; prop->identifier = identifier; @@ -782,7 +782,7 @@ int mosquitto_property_add_string(mosquitto_property **proplist, int identifier, int mosquitto_property_add_string_pair(mosquitto_property **proplist, int identifier, const char *name, const char *value) { - struct mqtt5__property *prop; + mosquitto_property *prop; if(!proplist) return MOSQ_ERR_INVAL; if(identifier != MQTT_PROP_USER_PROPERTY) return MOSQ_ERR_INVAL; @@ -793,7 +793,7 @@ int mosquitto_property_add_string_pair(mosquitto_property **proplist, int identi if(mosquitto_validate_utf8(value, strlen(value))) return MOSQ_ERR_MALFORMED_UTF8; } - prop = mosquitto__calloc(1, sizeof(struct mqtt5__property)); + prop = mosquitto__calloc(1, sizeof(mosquitto_property)); if(!prop) return MOSQ_ERR_NOMEM; prop->identifier = identifier; diff --git a/lib/property_mosq.h b/lib/property_mosq.h index dd2ecf9578..97c11564e7 100644 --- a/lib/property_mosq.h +++ b/lib/property_mosq.h @@ -39,11 +39,11 @@ struct mqtt5__property { }; -int property__read_all(int command, struct mosquitto__packet *packet, struct mqtt5__property **property); -int property__write_all(struct mosquitto__packet *packet, const struct mqtt5__property *property); -void property__free(struct mqtt5__property **property); +int property__read_all(int command, struct mosquitto__packet *packet, mosquitto_property **property); +int property__write_all(struct mosquitto__packet *packet, const mosquitto_property *property); +void property__free(mosquitto_property **property); -int property__get_length(const struct mqtt5__property *property); -int property__get_length_all(const struct mqtt5__property *property); +int property__get_length(const mosquitto_property *property); +int property__get_length_all(const mosquitto_property *property); #endif diff --git a/lib/send_connect.c b/lib/send_connect.c index 1c703fd72b..a052a39806 100644 --- a/lib/send_connect.c +++ b/lib/send_connect.c @@ -31,7 +31,7 @@ and the Eclipse Distribution License is available at #include "packet_mosq.h" #include "property_mosq.h" -int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session, const struct mqtt5__property *properties) +int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session, const mosquitto_property *properties) { struct mosquitto__packet *packet = NULL; int payloadlen; diff --git a/lib/send_disconnect.c b/lib/send_disconnect.c index d998c3f6b2..d29a153e69 100644 --- a/lib/send_disconnect.c +++ b/lib/send_disconnect.c @@ -32,7 +32,7 @@ and the Eclipse Distribution License is available at #include "send_mosq.h" -int send__disconnect(struct mosquitto *mosq, const struct mqtt5__property *properties) +int send__disconnect(struct mosquitto *mosq, const mosquitto_property *properties) { struct mosquitto__packet *packet = NULL; int rc; diff --git a/lib/send_mosq.c b/lib/send_mosq.c index eb0d6561b9..3899589cd4 100644 --- a/lib/send_mosq.c +++ b/lib/send_mosq.c @@ -111,7 +111,7 @@ int send__pubrel(struct mosquitto *mosq, uint16_t mid) } /* For PUBACK, PUBCOMP, PUBREC, and PUBREL */ -int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup, uint8_t reason_code, const struct mqtt5__property *properties) +int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup, uint8_t reason_code, const mosquitto_property *properties) { struct mosquitto__packet *packet = NULL; int rc; diff --git a/lib/send_mosq.h b/lib/send_mosq.h index 094c782c5a..fdf3b7ea9c 100644 --- a/lib/send_mosq.h +++ b/lib/send_mosq.h @@ -20,19 +20,19 @@ and the Eclipse Distribution License is available at #include "property_mosq.h" int send__simple_command(struct mosquitto *mosq, uint8_t command); -int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup, uint8_t reason_code, const struct mqtt5__property *properties); -int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const struct mqtt5__property *properties); +int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup, uint8_t reason_code, const mosquitto_property *properties); +int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const mosquitto_property *properties); -int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session, const struct mqtt5__property *properties); -int send__disconnect(struct mosquitto *mosq, const struct mqtt5__property *properties); +int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session, const mosquitto_property *properties); +int send__disconnect(struct mosquitto *mosq, const mosquitto_property *properties); int send__pingreq(struct mosquitto *mosq); int send__pingresp(struct mosquitto *mosq); int send__puback(struct mosquitto *mosq, uint16_t mid); int send__pubcomp(struct mosquitto *mosq, uint16_t mid); -int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const struct mqtt5__property *properties); +int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const mosquitto_property *properties); int send__pubrec(struct mosquitto *mosq, uint16_t mid); int send__pubrel(struct mosquitto *mosq, uint16_t mid); -int send__subscribe(struct mosquitto *mosq, int *mid, int topic_count, char *const *const topic, int topic_qos, const struct mqtt5__property *properties); +int send__subscribe(struct mosquitto *mosq, int *mid, int topic_count, char *const *const topic, int topic_qos, const mosquitto_property *properties); int send__unsubscribe(struct mosquitto *mosq, int *mid, const char *topic, const mosquitto_property *properties); #endif diff --git a/lib/send_publish.c b/lib/send_publish.c index 39878f8d5e..ee25d3b499 100644 --- a/lib/send_publish.c +++ b/lib/send_publish.c @@ -37,7 +37,7 @@ and the Eclipse Distribution License is available at #include "send_mosq.h" -int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const struct mqtt5__property *properties) +int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const mosquitto_property *properties) { #ifdef WITH_BROKER size_t len; @@ -128,7 +128,7 @@ int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint3 } -int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const struct mqtt5__property *properties) +int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const mosquitto_property *properties) { struct mosquitto__packet *packet = NULL; int packetlen; diff --git a/lib/send_subscribe.c b/lib/send_subscribe.c index 7feeb3a9f7..1fb02b1466 100644 --- a/lib/send_subscribe.c +++ b/lib/send_subscribe.c @@ -33,7 +33,7 @@ and the Eclipse Distribution License is available at #include "util_mosq.h" -int send__subscribe(struct mosquitto *mosq, int *mid, int topic_count, const char **topic, int topic_qos, const struct mqtt5__property *properties) +int send__subscribe(struct mosquitto *mosq, int *mid, int topic_count, const char **topic, int topic_qos, const mosquitto_property *properties) { struct mosquitto__packet *packet = NULL; uint32_t packetlen; diff --git a/src/database.c b/src/database.c index 5cf640fcc1..3de5728936 100644 --- a/src/database.c +++ b/src/database.c @@ -559,13 +559,13 @@ int db__messages_delete(struct mosquitto_db *db, struct mosquitto *context) return MOSQ_ERR_SUCCESS; } -int db__messages_easy_queue(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int qos, uint32_t payloadlen, const void *payload, int retain, struct mqtt5__property **properties) +int db__messages_easy_queue(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int qos, uint32_t payloadlen, const void *payload, int retain, mosquitto_property **properties) { struct mosquitto_msg_store *stored; char *source_id; char *topic_heap; mosquitto__payload_uhpa payload_uhpa; - struct mqtt5__property *local_properties = NULL; + mosquitto_property *local_properties = NULL; assert(db); @@ -596,7 +596,7 @@ int db__messages_easy_queue(struct mosquitto_db *db, struct mosquitto *context, } /* This function requires topic to be allocated on the heap. Once called, it owns topic and will free it on error. Likewise payload and properties. */ -int db__message_store(struct mosquitto_db *db, const char *source, uint16_t source_mid, char *topic, int qos, uint32_t payloadlen, mosquitto__payload_uhpa *payload, int retain, struct mosquitto_msg_store **stored, uint32_t message_expiry_interval, struct mqtt5__property *properties, dbid_t store_id) +int db__message_store(struct mosquitto_db *db, const char *source, uint16_t source_mid, char *topic, int qos, uint32_t payloadlen, mosquitto__payload_uhpa *payload, int retain, struct mosquitto_msg_store **stored, uint32_t message_expiry_interval, mosquitto_property *properties, dbid_t store_id) { struct mosquitto_msg_store *temp = NULL; int rc = MOSQ_ERR_SUCCESS; @@ -871,7 +871,7 @@ int db__message_write(struct mosquitto_db *db, struct mosquitto *context) uint32_t payloadlen; const void *payload; int msg_count = 0; - struct mqtt5__property *properties; + mosquitto_property *properties; time_t now; if(!context || context->sock == INVALID_SOCKET diff --git a/src/handle_auth.c b/src/handle_auth.c index 529f4e65c2..dd5b2d73b2 100644 --- a/src/handle_auth.c +++ b/src/handle_auth.c @@ -29,7 +29,7 @@ int handle__auth(struct mosquitto_db *db, struct mosquitto *context) { int rc = 0; uint8_t reason_code; - struct mqtt5__property *properties = NULL; + mosquitto_property *properties = NULL; if(!context) return MOSQ_ERR_INVAL; log__printf(NULL, MOSQ_LOG_DEBUG, "Received AUTH from %s", context->id); diff --git a/src/handle_connack.c b/src/handle_connack.c index 038dab0ed0..20ac526a9c 100644 --- a/src/handle_connack.c +++ b/src/handle_connack.c @@ -35,7 +35,7 @@ int handle__connack(struct mosquitto_db *db, struct mosquitto *context) char *notification_topic; int notification_topic_len; char notification_payload; - struct mqtt5__property *properties = NULL; + mosquitto_property *properties = NULL; if(!context){ return MOSQ_ERR_INVAL; diff --git a/src/handle_connect.c b/src/handle_connect.c index b617211fa0..a6f1ae78b1 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -131,7 +131,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) struct mosquitto__subleaf *leaf; int i; struct mosquitto__security_options *security_opts; - struct mqtt5__property *properties = NULL; + mosquitto_property *properties = NULL; #ifdef WITH_TLS X509 *client_cert = NULL; X509_NAME *name; @@ -722,7 +722,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) int handle__disconnect(struct mosquitto_db *db, struct mosquitto *context) { int rc; - struct mqtt5__property *properties = NULL; + mosquitto_property *properties = NULL; if(!context){ return MOSQ_ERR_INVAL; diff --git a/src/handle_publish.c b/src/handle_publish.c index 8862394e08..31b1df5b34 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -45,9 +45,9 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) int len; int slen; char *topic_mount; - struct mqtt5__property *properties = NULL; - struct mqtt5__property *p, *p_prev; - struct mqtt5__property *msg_properties = NULL, *msg_properties_last; + mosquitto_property *properties = NULL; + mosquitto_property *p, *p_prev; + mosquitto_property *msg_properties = NULL, *msg_properties_last; uint32_t message_expiry_interval = 0; #ifdef WITH_BRIDGE diff --git a/src/handle_subscribe.c b/src/handle_subscribe.c index b96ad255bd..0715b47589 100644 --- a/src/handle_subscribe.c +++ b/src/handle_subscribe.c @@ -39,7 +39,7 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) int len; int slen; char *sub_mount; - struct mqtt5__property *properties = NULL; + mosquitto_property *properties = NULL; if(!context) return MOSQ_ERR_INVAL; log__printf(NULL, MOSQ_LOG_DEBUG, "Received SUBSCRIBE from %s", context->id); diff --git a/src/handle_unsubscribe.c b/src/handle_unsubscribe.c index d760a5d7c7..6fb24e2d80 100644 --- a/src/handle_unsubscribe.c +++ b/src/handle_unsubscribe.c @@ -31,7 +31,7 @@ int handle__unsubscribe(struct mosquitto_db *db, struct mosquitto *context) char *sub; int slen; int rc; - struct mqtt5__property *properties = NULL; + mosquitto_property *properties = NULL; if(!context) return MOSQ_ERR_INVAL; log__printf(NULL, MOSQ_LOG_DEBUG, "Received UNSUBSCRIBE from %s", context->id); diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index 8140bb17e0..06f3d2f631 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -315,7 +315,7 @@ struct mosquitto_msg_store{ int dest_id_count; int ref_count; char* topic; - struct mqtt5__property *properties; + mosquitto_property *properties; mosquitto__payload_uhpa payload; time_t message_expiry_time; uint32_t payloadlen; @@ -513,7 +513,7 @@ int restore_privileges(void); * ============================================================ */ int send__connack(struct mosquitto *context, int ack, int result); int send__suback(struct mosquitto *context, uint16_t mid, uint32_t payloadlen, const void *payload); -int send__unsuback(struct mosquitto *context, uint16_t mid, const struct mqtt5__property *properties); +int send__unsuback(struct mosquitto *context, uint16_t mid, const mosquitto_property *properties); /* ============================================================ * Network functions @@ -555,8 +555,8 @@ int db__message_update(struct mosquitto *context, uint16_t mid, enum mosquitto_m int db__message_write(struct mosquitto_db *db, struct mosquitto *context); void db__message_dequeue_first(struct mosquitto *context); int db__messages_delete(struct mosquitto_db *db, struct mosquitto *context); -int db__messages_easy_queue(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int qos, uint32_t payloadlen, const void *payload, int retain, struct mqtt5__property **properties); -int db__message_store(struct mosquitto_db *db, const char *source, uint16_t source_mid, char *topic, int qos, uint32_t payloadlen, mosquitto__payload_uhpa *payload, int retain, struct mosquitto_msg_store **stored, uint32_t message_expiry_interval, struct mqtt5__property *properties, dbid_t store_id); +int db__messages_easy_queue(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int qos, uint32_t payloadlen, const void *payload, int retain, mosquitto_property **properties); +int db__message_store(struct mosquitto_db *db, const char *source, uint16_t source_mid, char *topic, int qos, uint32_t payloadlen, mosquitto__payload_uhpa *payload, int retain, struct mosquitto_msg_store **stored, uint32_t message_expiry_interval, mosquitto_property *properties, dbid_t store_id); int db__message_store_find(struct mosquitto *context, uint16_t mid, struct mosquitto_msg_store **stored); void db__msg_store_add(struct mosquitto_db *db, struct mosquitto_msg_store *store); void db__msg_store_remove(struct mosquitto_db *db, struct mosquitto_msg_store *store); diff --git a/src/send_connack.c b/src/send_connack.c index 7414298aac..ac39b63645 100644 --- a/src/send_connack.c +++ b/src/send_connack.c @@ -27,7 +27,7 @@ int send__connack(struct mosquitto *context, int ack, int result) { struct mosquitto__packet *packet = NULL; int rc; - struct mqtt5__property *properties = NULL; + mosquitto_property *properties = NULL; int proplen, varbytes; if(context){ diff --git a/src/send_suback.c b/src/send_suback.c index 20eeb270af..49daeebce9 100644 --- a/src/send_suback.c +++ b/src/send_suback.c @@ -28,7 +28,7 @@ int send__suback(struct mosquitto *context, uint16_t mid, uint32_t payloadlen, c { struct mosquitto__packet *packet = NULL; int rc; - struct mqtt5__property *properties = NULL; + mosquitto_property *properties = NULL; int proplen, varbytes; log__printf(NULL, MOSQ_LOG_DEBUG, "Sending SUBACK to %s", context->id); diff --git a/src/send_unsuback.c b/src/send_unsuback.c index e48b6547fb..59fc50a373 100644 --- a/src/send_unsuback.c +++ b/src/send_unsuback.c @@ -25,7 +25,7 @@ and the Eclipse Distribution License is available at #include "property_mosq.h" -int send__unsuback(struct mosquitto *mosq, uint16_t mid, const struct mqtt5__property *properties) +int send__unsuback(struct mosquitto *mosq, uint16_t mid, const mosquitto_property *properties) { struct mosquitto__packet *packet = NULL; int rc; diff --git a/test/unit/property_read.c b/test/unit/property_read.c index f124ae216b..8d9c4433dd 100644 --- a/test/unit/property_read.c +++ b/test/unit/property_read.c @@ -14,7 +14,7 @@ static void byte_prop_read_helper( uint8_t value_expected) { struct mosquitto__packet packet; - struct mqtt5__property *properties; + mosquitto_property *properties; int rc; memset(&packet, 0, sizeof(struct mosquitto__packet)); @@ -70,7 +70,7 @@ static void int32_prop_read_helper( uint32_t value_expected) { struct mosquitto__packet packet; - struct mqtt5__property *properties; + mosquitto_property *properties; int rc; memset(&packet, 0, sizeof(struct mosquitto__packet)); @@ -120,7 +120,7 @@ static void int16_prop_read_helper( uint16_t value_expected) { struct mosquitto__packet packet; - struct mqtt5__property *properties; + mosquitto_property *properties; int rc; memset(&packet, 0, sizeof(struct mosquitto__packet)); @@ -165,7 +165,7 @@ static void string_prop_read_helper( const char *value_expected) { struct mosquitto__packet packet; - struct mqtt5__property *properties; + mosquitto_property *properties; int rc; memset(&packet, 0, sizeof(struct mosquitto__packet)); @@ -230,7 +230,7 @@ static void binary_prop_read_helper( int len_expected) { struct mosquitto__packet packet; - struct mqtt5__property *properties; + mosquitto_property *properties; int rc; memset(&packet, 0, sizeof(struct mosquitto__packet)); @@ -279,7 +279,7 @@ static void string_pair_prop_read_helper( bool expect_multiple) { struct mosquitto__packet packet; - struct mqtt5__property *properties; + mosquitto_property *properties; int rc; memset(&packet, 0, sizeof(struct mosquitto__packet)); @@ -314,7 +314,7 @@ static void varint_prop_read_helper( uint32_t value_expected) { struct mosquitto__packet packet; - struct mqtt5__property *properties; + mosquitto_property *properties; int rc; memset(&packet, 0, sizeof(struct mosquitto__packet)); @@ -340,7 +340,7 @@ static void packet_helper_reason_string_user_property(int command) MQTT_PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e'}; struct mosquitto__packet packet; - struct mqtt5__property *properties, *p; + mosquitto_property *properties, *p; int rc; memset(&packet, 0, sizeof(struct mosquitto__packet)); @@ -378,7 +378,7 @@ static void packet_helper_reason_string_user_property(int command) static void TEST_no_properties(void) { struct mosquitto__packet packet; - struct mqtt5__property *properties = NULL; + mosquitto_property *properties = NULL; uint8_t payload[5]; int rc; @@ -395,7 +395,7 @@ static void TEST_no_properties(void) static void TEST_truncated(void) { struct mosquitto__packet packet; - struct mqtt5__property *properties = NULL; + mosquitto_property *properties = NULL; uint8_t payload[5]; int rc; @@ -440,7 +440,7 @@ static void TEST_truncated(void) static void TEST_invalid_property_id(void) { struct mosquitto__packet packet; - struct mqtt5__property *properties = NULL; + mosquitto_property *properties = NULL; uint8_t payload[5]; int rc; @@ -1209,7 +1209,7 @@ static void TEST_packet_connect(void) MQTT_PROP_AUTHENTICATION_DATA, 0x00, 0x02, 1, 2}; struct mosquitto__packet packet; - struct mqtt5__property *properties, *p; + mosquitto_property *properties, *p; int rc; payload[0] = sizeof(payload)-1; @@ -1298,7 +1298,7 @@ static void TEST_packet_connack(void) MQTT_PROP_AUTHENTICATION_DATA, 0x00, 0x02, 1, 2}; struct mosquitto__packet packet; - struct mqtt5__property *properties, *p; + mosquitto_property *properties, *p; int rc; payload[0] = sizeof(payload)-1; @@ -1422,7 +1422,7 @@ static void TEST_packet_publish(void) MQTT_PROP_CONTENT_TYPE, 0, 5, 'e', 'm', 'p', 't', 'y'}; struct mosquitto__packet packet; - struct mqtt5__property *properties, *p; + mosquitto_property *properties, *p; int rc; payload[0] = sizeof(payload)-1; @@ -1512,7 +1512,7 @@ static void TEST_packet_subscribe(void) MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 0x04}; struct mosquitto__packet packet; - struct mqtt5__property *properties, *p; + mosquitto_property *properties, *p; int rc; payload[0] = sizeof(payload)-1; @@ -1552,7 +1552,7 @@ static void TEST_packet_unsubscribe(void) MQTT_PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e'}; struct mosquitto__packet packet; - struct mqtt5__property *properties, *p; + mosquitto_property *properties, *p; int rc; payload[0] = sizeof(payload)-1; @@ -1588,7 +1588,7 @@ static void TEST_packet_disconnect(void) MQTT_PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e'}; struct mosquitto__packet packet; - struct mqtt5__property *properties, *p; + mosquitto_property *properties, *p; int rc; payload[0] = sizeof(payload)-1; @@ -1632,7 +1632,7 @@ static void TEST_packet_auth(void) MQTT_PROP_USER_PROPERTY, 0, 4, 'n', 'a', 'm', 'e', 0, 5, 'v', 'a', 'l', 'u', 'e'}; struct mosquitto__packet packet; - struct mqtt5__property *properties, *p; + mosquitto_property *properties, *p; int rc; payload[0] = sizeof(payload)-1; diff --git a/test/unit/property_write.c b/test/unit/property_write.c index 00533539e6..6cc341ceb7 100644 --- a/test/unit/property_write.c +++ b/test/unit/property_write.c @@ -12,12 +12,12 @@ static void byte_prop_write_helper( int identifier, uint8_t value_expected) { - struct mqtt5__property property; + mosquitto_property property; struct mosquitto__packet packet; - struct mqtt5__property *properties; + mosquitto_property *properties; int rc; - memset(&property, 0, sizeof(struct mqtt5__property)); + memset(&property, 0, sizeof(mosquitto_property)); property.identifier = identifier; property.value.i8 = value_expected; @@ -52,12 +52,12 @@ static void int32_prop_write_helper( int identifier, uint32_t value_expected) { - struct mqtt5__property property; + mosquitto_property property; struct mosquitto__packet packet; - struct mqtt5__property *properties; + mosquitto_property *properties; int rc; - memset(&property, 0, sizeof(struct mqtt5__property)); + memset(&property, 0, sizeof(mosquitto_property)); property.identifier = identifier; property.value.i32 = value_expected; @@ -92,12 +92,12 @@ static void int16_prop_write_helper( int identifier, uint16_t value_expected) { - struct mqtt5__property property; + mosquitto_property property; struct mosquitto__packet packet; - struct mqtt5__property *properties; + mosquitto_property *properties; int rc; - memset(&property, 0, sizeof(struct mqtt5__property)); + memset(&property, 0, sizeof(mosquitto_property)); property.identifier = identifier; property.value.i16 = value_expected; @@ -131,12 +131,12 @@ static void string_prop_write_helper( int identifier, const char *value_expected) { - struct mqtt5__property property; + mosquitto_property property; struct mosquitto__packet packet; - struct mqtt5__property *properties; + mosquitto_property *properties; int rc; - memset(&property, 0, sizeof(struct mqtt5__property)); + memset(&property, 0, sizeof(mosquitto_property)); property.identifier = identifier; property.value.s.v = strdup(value_expected); @@ -175,12 +175,12 @@ static void binary_prop_write_helper( const uint8_t *value_expected, int len_expected) { - struct mqtt5__property property; + mosquitto_property property; struct mosquitto__packet packet; - struct mqtt5__property *properties; + mosquitto_property *properties; int rc; - memset(&property, 0, sizeof(struct mqtt5__property)); + memset(&property, 0, sizeof(mosquitto_property)); property.identifier = identifier; property.value.bin.v = malloc(len_expected); @@ -219,12 +219,12 @@ static void string_pair_prop_write_helper( const char *value_expected, bool expect_multiple) { - struct mqtt5__property property; + mosquitto_property property; struct mosquitto__packet packet; - struct mqtt5__property *properties; + mosquitto_property *properties; int rc; - memset(&property, 0, sizeof(struct mqtt5__property)); + memset(&property, 0, sizeof(mosquitto_property)); property.identifier = identifier; property.value.s.v = strdup(value_expected); @@ -269,12 +269,12 @@ static void varint_prop_write_helper( int identifier, uint32_t value_expected) { - struct mqtt5__property property; + mosquitto_property property; struct mosquitto__packet packet; - struct mqtt5__property *properties; + mosquitto_property *properties; int rc; - memset(&property, 0, sizeof(struct mqtt5__property)); + memset(&property, 0, sizeof(mosquitto_property)); property.identifier = identifier; property.value.varint = value_expected; @@ -316,12 +316,12 @@ static void varint_prop_write_helper( static void TEST_bad_identifier(void) { - struct mqtt5__property property; + mosquitto_property property; struct mosquitto__packet packet; uint8_t payload[10]; int rc; - memset(&property, 0, sizeof(struct mqtt5__property)); + memset(&property, 0, sizeof(mosquitto_property)); memset(&packet, 0, sizeof(struct mosquitto__packet)); property.identifier = 0xFFFF; packet.packet_length = 10; From eda150f95361b661650683be23445ad6f747adf1 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 8 Nov 2018 16:10:18 +0000 Subject: [PATCH 086/254] Add cunit dependency for travis. --- travis-install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/travis-install.sh b/travis-install.sh index ba03483287..f1f31dd1c3 100755 --- a/travis-install.sh +++ b/travis-install.sh @@ -3,7 +3,7 @@ if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get update -qq - sudo apt-get install -y debhelper libc-ares-dev libssl-dev libwrap0-dev python-all python3-all uthash-dev uuid-dev libuuid1 xsltproc docbook-xsl + sudo apt-get install -y debhelper libc-ares-dev libssl-dev libwrap0-dev python-all python3-all uthash-dev uuid-dev libuuid1 xsltproc docbook-xsl libcunit1-dev fi if [ "$TRAVIS_OS_NAME" == "osx" ]; then From 9464e3fe190818bf6e0ae9dcb56a9020b1f303f7 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 20 Nov 2018 10:15:34 +0000 Subject: [PATCH 087/254] Guard against possible null client id. --- src/persist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/persist.c b/src/persist.c index b83327c340..3299356d17 100644 --- a/src/persist.c +++ b/src/persist.c @@ -287,7 +287,7 @@ static int persist__subs_retain_write(struct mosquitto_db *db, FILE *db_fptr, st sub = node->subs; while(sub){ - if(sub->context->clean_session == false){ + if(sub->context->clean_session == false && sub->context->id){ length = htonl(2+strlen(sub->context->id) + 2+strlen(thistopic) + sizeof(uint8_t)); i16temp = htons(DB_CHUNK_SUB); From 158189393e5f29b36457ba332258ef0335f7756e Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 20 Nov 2018 14:36:18 +0000 Subject: [PATCH 088/254] Add v5 client callbacks. --- lib/callbacks.c | 42 +++++++++++++ lib/handle_connack.c | 7 ++- lib/handle_pubackcomp.c | 11 +++- lib/handle_publish.c | 17 ++++- lib/handle_pubrel.c | 11 +++- lib/handle_suback.c | 13 +++- lib/handle_unsuback.c | 13 +++- lib/linker.version | 6 ++ lib/loop.c | 10 +++ lib/mosquitto.h | 131 +++++++++++++++++++++++++++++++++++++++ lib/mosquitto_internal.h | 6 ++ lib/packet_mosq.c | 11 ++++ lib/srv_mosq.c | 5 ++ lib/util_mosq.c | 5 ++ 14 files changed, 276 insertions(+), 12 deletions(-) diff --git a/lib/callbacks.c b/lib/callbacks.c index 037ee82b70..0d6747b948 100644 --- a/lib/callbacks.c +++ b/lib/callbacks.c @@ -34,6 +34,13 @@ void mosquitto_connect_with_flags_callback_set(struct mosquitto *mosq, void (*on pthread_mutex_unlock(&mosq->callback_mutex); } +void mosquitto_connect_v5_callback_set(struct mosquitto *mosq, void (*on_connect)(struct mosquitto *, void *, int, int, const mosquitto_property *)) +{ + pthread_mutex_lock(&mosq->callback_mutex); + mosq->on_connect_v5 = on_connect; + pthread_mutex_unlock(&mosq->callback_mutex); +} + void mosquitto_disconnect_callback_set(struct mosquitto *mosq, void (*on_disconnect)(struct mosquitto *, void *, int)) { pthread_mutex_lock(&mosq->callback_mutex); @@ -41,6 +48,13 @@ void mosquitto_disconnect_callback_set(struct mosquitto *mosq, void (*on_disconn pthread_mutex_unlock(&mosq->callback_mutex); } +void mosquitto_disconnect_v5_callback_set(struct mosquitto *mosq, void (*on_disconnect)(struct mosquitto *, void *, int, const mosquitto_property *)) +{ + pthread_mutex_lock(&mosq->callback_mutex); + mosq->on_disconnect_v5 = on_disconnect; + pthread_mutex_unlock(&mosq->callback_mutex); +} + void mosquitto_publish_callback_set(struct mosquitto *mosq, void (*on_publish)(struct mosquitto *, void *, int)) { pthread_mutex_lock(&mosq->callback_mutex); @@ -48,6 +62,13 @@ void mosquitto_publish_callback_set(struct mosquitto *mosq, void (*on_publish)(s pthread_mutex_unlock(&mosq->callback_mutex); } +void mosquitto_publish_v5_callback_set(struct mosquitto *mosq, void (*on_publish)(struct mosquitto *, void *, int, const mosquitto_property *props)) +{ + pthread_mutex_lock(&mosq->callback_mutex); + mosq->on_publish_v5 = on_publish; + pthread_mutex_unlock(&mosq->callback_mutex); +} + void mosquitto_message_callback_set(struct mosquitto *mosq, void (*on_message)(struct mosquitto *, void *, const struct mosquitto_message *)) { pthread_mutex_lock(&mosq->callback_mutex); @@ -55,6 +76,13 @@ void mosquitto_message_callback_set(struct mosquitto *mosq, void (*on_message)(s pthread_mutex_unlock(&mosq->callback_mutex); } +void mosquitto_message_v5_callback_set(struct mosquitto *mosq, void (*on_message)(struct mosquitto *, void *, const struct mosquitto_message *, const mosquitto_property *props)) +{ + pthread_mutex_lock(&mosq->callback_mutex); + mosq->on_message_v5 = on_message; + pthread_mutex_unlock(&mosq->callback_mutex); +} + void mosquitto_subscribe_callback_set(struct mosquitto *mosq, void (*on_subscribe)(struct mosquitto *, void *, int, int, const int *)) { pthread_mutex_lock(&mosq->callback_mutex); @@ -62,6 +90,13 @@ void mosquitto_subscribe_callback_set(struct mosquitto *mosq, void (*on_subscrib pthread_mutex_unlock(&mosq->callback_mutex); } +void mosquitto_subscribe_v5_callback_set(struct mosquitto *mosq, void (*on_subscribe)(struct mosquitto *, void *, int, int, const int *, const mosquitto_property *props)) +{ + pthread_mutex_lock(&mosq->callback_mutex); + mosq->on_subscribe_v5 = on_subscribe; + pthread_mutex_unlock(&mosq->callback_mutex); +} + void mosquitto_unsubscribe_callback_set(struct mosquitto *mosq, void (*on_unsubscribe)(struct mosquitto *, void *, int)) { pthread_mutex_lock(&mosq->callback_mutex); @@ -69,6 +104,13 @@ void mosquitto_unsubscribe_callback_set(struct mosquitto *mosq, void (*on_unsubs pthread_mutex_unlock(&mosq->callback_mutex); } +void mosquitto_unsubscribe_v5_callback_set(struct mosquitto *mosq, void (*on_unsubscribe)(struct mosquitto *, void *, int, const mosquitto_property *props)) +{ + pthread_mutex_lock(&mosq->callback_mutex); + mosq->on_unsubscribe_v5 = on_unsubscribe; + pthread_mutex_unlock(&mosq->callback_mutex); +} + void mosquitto_log_callback_set(struct mosquitto *mosq, void (*on_log)(struct mosquitto *, void *, int, const char *)) { pthread_mutex_lock(&mosq->log_callback_mutex); diff --git a/lib/handle_connack.c b/lib/handle_connack.c index ba11088315..75a5db8726 100644 --- a/lib/handle_connack.c +++ b/lib/handle_connack.c @@ -46,7 +46,6 @@ int handle__connack(struct mosquitto *mosq) if(rc) return rc; mosquitto_property_free_all(&properties); } - mosquitto_property_free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received CONNACK (%d)", mosq->id, reason_code); pthread_mutex_lock(&mosq->callback_mutex); @@ -60,7 +59,13 @@ int handle__connack(struct mosquitto *mosq) mosq->on_connect_with_flags(mosq, mosq->userdata, reason_code, connect_flags); mosq->in_callback = false; } + if(mosq->on_connect_v5){ + mosq->in_callback = true; + mosq->on_connect_v5(mosq, mosq->userdata, reason_code, connect_flags, properties); + mosq->in_callback = false; + } pthread_mutex_unlock(&mosq->callback_mutex); + mosquitto_property_free_all(&properties); switch(reason_code){ case 0: if(mosq->state != mosq_cs_disconnecting){ diff --git a/lib/handle_pubackcomp.c b/lib/handle_pubackcomp.c index 2169df7001..0ed07ff1e2 100644 --- a/lib/handle_pubackcomp.c +++ b/lib/handle_pubackcomp.c @@ -54,13 +54,14 @@ int handle__pubackcomp(struct mosquitto *mosq, const char *type) if(mosq->protocol == mosq_p_mqtt5){ rc = property__read_all(CMD_PUBACK, &mosq->in_packet, &properties); if(rc) return rc; - /* Immediately free, we don't do anything with Reason String or User Property at the moment */ - mosquitto_property_free_all(&properties); } #ifdef WITH_BROKER log__printf(NULL, MOSQ_LOG_DEBUG, "Received %s from %s (Mid: %d)", type, mosq->id, mid); + /* Immediately free, we don't do anything with Reason String or User Property at the moment */ + mosquitto_property_free_all(&properties); + if(mid){ rc = db__message_delete(db, mosq, mid, mosq_md_out); if(rc == MOSQ_ERR_NOT_FOUND){ @@ -81,7 +82,13 @@ int handle__pubackcomp(struct mosquitto *mosq, const char *type) mosq->on_publish(mosq, mosq->userdata, mid); mosq->in_callback = false; } + if(mosq->on_publish_v5){ + mosq->in_callback = true; + mosq->on_publish_v5(mosq, mosq->userdata, mid, properties); + mosq->in_callback = false; + } pthread_mutex_unlock(&mosq->callback_mutex); + mosquitto_property_free_all(&properties); } #endif diff --git a/lib/handle_publish.c b/lib/handle_publish.c index c3c53b583c..659260a1e4 100644 --- a/lib/handle_publish.c +++ b/lib/handle_publish.c @@ -79,18 +79,19 @@ int handle__publish(struct mosquitto *mosq) if(rc) return rc; mosquitto_property_free_all(&properties); } - mosquitto_property_free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ message->msg.payloadlen = mosq->in_packet.remaining_length - mosq->in_packet.pos; if(message->msg.payloadlen){ message->msg.payload = mosquitto__calloc(message->msg.payloadlen+1, sizeof(uint8_t)); if(!message->msg.payload){ message__cleanup(&message); + mosquitto_property_free_all(&properties); return MOSQ_ERR_NOMEM; } rc = packet__read_bytes(&mosq->in_packet, message->msg.payload, message->msg.payloadlen); if(rc){ message__cleanup(&message); + mosquitto_property_free_all(&properties); return rc; } } @@ -109,8 +110,14 @@ int handle__publish(struct mosquitto *mosq) mosq->on_message(mosq, mosq->userdata, &message->msg); mosq->in_callback = false; } + if(mosq->on_message_v5){ + mosq->in_callback = true; + mosq->on_message_v5(mosq, mosq->userdata, &message->msg, properties); + mosq->in_callback = false; + } pthread_mutex_unlock(&mosq->callback_mutex); message__cleanup(&message); + mosquitto_property_free_all(&properties); return MOSQ_ERR_SUCCESS; case 1: rc = send__puback(mosq, message->msg.mid); @@ -120,8 +127,14 @@ int handle__publish(struct mosquitto *mosq) mosq->on_message(mosq, mosq->userdata, &message->msg); mosq->in_callback = false; } + if(mosq->on_message_v5){ + mosq->in_callback = true; + mosq->on_message_v5(mosq, mosq->userdata, &message->msg, properties); + mosq->in_callback = false; + } pthread_mutex_unlock(&mosq->callback_mutex); message__cleanup(&message); + mosquitto_property_free_all(&properties); return rc; case 2: rc = send__pubrec(mosq, message->msg.mid); @@ -129,9 +142,11 @@ int handle__publish(struct mosquitto *mosq) message->state = mosq_ms_wait_for_pubrel; message__queue(mosq, message, mosq_md_in); pthread_mutex_unlock(&mosq->in_message_mutex); + mosquitto_property_free_all(&properties); return rc; default: message__cleanup(&message); + mosquitto_property_free_all(&properties); return MOSQ_ERR_PROTOCOL; } } diff --git a/lib/handle_pubrel.c b/lib/handle_pubrel.c index d9d5dda53a..8c60645903 100644 --- a/lib/handle_pubrel.c +++ b/lib/handle_pubrel.c @@ -58,13 +58,14 @@ int handle__pubrel(struct mosquitto_db *db, struct mosquitto *mosq) if(mosq->protocol == mosq_p_mqtt5){ rc = property__read_all(CMD_PUBREL, &mosq->in_packet, &properties); if(rc) return rc; - /* Immediately free, we don't do anything with Reason String or User Property at the moment */ - mosquitto_property_free_all(&properties); } #ifdef WITH_BROKER log__printf(NULL, MOSQ_LOG_DEBUG, "Received PUBREL from %s (Mid: %d)", mosq->id, mid); + /* Immediately free, we don't do anything with Reason String or User Property at the moment */ + mosquitto_property_free_all(&properties); + if(db__message_release(db, mosq, mid, mosq_md_in)){ /* Message not found. Still send a PUBCOMP anyway because this could be * due to a repeated PUBREL after a client has reconnected. */ @@ -82,7 +83,13 @@ int handle__pubrel(struct mosquitto_db *db, struct mosquitto *mosq) mosq->on_message(mosq, mosq->userdata, &message->msg); mosq->in_callback = false; } + if(mosq->on_message_v5){ + mosq->in_callback = true; + mosq->on_message_v5(mosq, mosq->userdata, &message->msg, properties); + mosq->in_callback = false; + } pthread_mutex_unlock(&mosq->callback_mutex); + mosquitto_property_free_all(&properties); message__cleanup(&message); } #endif diff --git a/lib/handle_suback.c b/lib/handle_suback.c index 65b71e52e2..5f142ac589 100644 --- a/lib/handle_suback.c +++ b/lib/handle_suback.c @@ -54,8 +54,6 @@ int handle__suback(struct mosquitto *mosq) if(mosq->protocol == mosq_p_mqtt5){ rc = property__read_all(CMD_SUBACK, &mosq->in_packet, &properties); if(rc) return rc; - /* Immediately free, we don't do anything with Reason String or User Property at the moment */ - mosquitto_property_free_all(&properties); } qos_count = mosq->in_packet.remaining_length - mosq->in_packet.pos; @@ -70,14 +68,23 @@ int handle__suback(struct mosquitto *mosq) granted_qos[i] = (int)qos; i++; } -#ifndef WITH_BROKER +#ifdef WITH_BROKER + /* Immediately free, we don't do anything with Reason String or User Property at the moment */ + mosquitto_property_free_all(&properties); +#else pthread_mutex_lock(&mosq->callback_mutex); if(mosq->on_subscribe){ mosq->in_callback = true; mosq->on_subscribe(mosq, mosq->userdata, mid, qos_count, granted_qos); mosq->in_callback = false; } + if(mosq->on_subscribe_v5){ + mosq->in_callback = true; + mosq->on_subscribe_v5(mosq, mosq->userdata, mid, qos_count, granted_qos, properties); + mosq->in_callback = false; + } pthread_mutex_unlock(&mosq->callback_mutex); + mosquitto_property_free_all(&properties); #endif mosquitto__free(granted_qos); diff --git a/lib/handle_unsuback.c b/lib/handle_unsuback.c index 72ca3d58b4..bce4d369ee 100644 --- a/lib/handle_unsuback.c +++ b/lib/handle_unsuback.c @@ -56,18 +56,25 @@ int handle__unsuback(struct mosquitto *mosq) if(mosq->protocol == mosq_p_mqtt5){ rc = property__read_all(CMD_UNSUBACK, &mosq->in_packet, &properties); if(rc) return rc; - /* Immediately free, we don't do anything with Reason String or User Property at the moment */ - mosquitto_property_free_all(&properties); } -#ifndef WITH_BROKER +#ifdef WITH_BROKER + /* Immediately free, we don't do anything with Reason String or User Property at the moment */ + mosquitto_property_free_all(&properties); +#else pthread_mutex_lock(&mosq->callback_mutex); if(mosq->on_unsubscribe){ mosq->in_callback = true; mosq->on_unsubscribe(mosq, mosq->userdata, mid); mosq->in_callback = false; } + if(mosq->on_unsubscribe_v5){ + mosq->in_callback = true; + mosq->on_unsubscribe_v5(mosq, mosq->userdata, mid, properties); + mosq->in_callback = false; + } pthread_mutex_unlock(&mosq->callback_mutex); + mosquitto_property_free_all(&properties); #endif return MOSQ_ERR_SUCCESS; diff --git a/lib/linker.version b/lib/linker.version index ccebe673e3..490b4a2352 100644 --- a/lib/linker.version +++ b/lib/linker.version @@ -113,4 +113,10 @@ MOSQ_1.6 { mosquitto_subscribe_with_properties; mosquitto_unsubscribe_with_properties; mosquitto_will_set_with_properties; + mosquitto_connect_v5_callback_set; + mosquitto_disconnect_v5_callback_set; + mosquitto_publish_v5_callback_set; + mosquitto_message_v5_callback_set; + mosquitto_subscribe_v5_callback_set; + mosquitto_unsubscribe_v5_callback_set; } MOSQ_1.5; diff --git a/lib/loop.c b/lib/loop.c index 0725d227d0..628d7d12dd 100644 --- a/lib/loop.c +++ b/lib/loop.c @@ -319,6 +319,11 @@ int mosquitto_loop_misc(struct mosquitto *mosq) mosq->on_disconnect(mosq, mosq->userdata, rc); mosq->in_callback = false; } + if(mosq->on_disconnect_v5){ + mosq->in_callback = true; + mosq->on_disconnect_v5(mosq, mosq->userdata, rc, NULL); + mosq->in_callback = false; + } pthread_mutex_unlock(&mosq->callback_mutex); return MOSQ_ERR_CONN_LOST; } @@ -341,6 +346,11 @@ static int mosquitto__loop_rc_handle(struct mosquitto *mosq, int rc) mosq->on_disconnect(mosq, mosq->userdata, rc); mosq->in_callback = false; } + if(mosq->on_disconnect_v5){ + mosq->in_callback = true; + mosq->on_disconnect_v5(mosq, mosq->userdata, rc, NULL); + mosq->in_callback = false; + } pthread_mutex_unlock(&mosq->callback_mutex); return rc; } diff --git a/lib/mosquitto.h b/lib/mosquitto.h index 9dccb3df08..0f586fb2bc 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -1593,6 +1593,32 @@ libmosq_EXPORT void mosquitto_connect_callback_set(struct mosquitto *mosq, void */ libmosq_EXPORT void mosquitto_connect_with_flags_callback_set(struct mosquitto *mosq, void (*on_connect)(struct mosquitto *, void *, int, int)); +/* + * Function: mosquitto_connect_v5_callback_set + * + * Set the connect callback. This is called when the broker sends a CONNACK + * message in response to a connection. + * + * Parameters: + * mosq - a valid mosquitto instance. + * on_connect - a callback function in the following form: + * void callback(struct mosquitto *mosq, void *obj, int rc) + * + * Callback Parameters: + * mosq - the mosquitto instance making the callback. + * obj - the user data provided in + * rc - the return code of the connection response, one of: + * * 0 - success + * * 1 - connection refused (unacceptable protocol version) + * * 2 - connection refused (identifier rejected) + * * 3 - connection refused (broker unavailable) + * * 4-255 - reserved for future use + * flags - the connect flags. + * props - list of MQTT 5 properties, or NULL + * + */ +libmosq_EXPORT void mosquitto_connect_v5_callback_set(struct mosquitto *mosq, void (*on_connect)(struct mosquitto *, void *, int, int, const mosquitto_property *props)); + /* * Function: mosquitto_disconnect_callback_set * @@ -1613,6 +1639,27 @@ libmosq_EXPORT void mosquitto_connect_with_flags_callback_set(struct mosquitto * */ libmosq_EXPORT void mosquitto_disconnect_callback_set(struct mosquitto *mosq, void (*on_disconnect)(struct mosquitto *, void *, int)); +/* + * Function: mosquitto_disconnect_v5_callback_set + * + * Set the disconnect callback. This is called when the broker has received the + * DISCONNECT command and has disconnected the client. + * + * Parameters: + * mosq - a valid mosquitto instance. + * on_disconnect - a callback function in the following form: + * void callback(struct mosquitto *mosq, void *obj) + * + * Callback Parameters: + * mosq - the mosquitto instance making the callback. + * obj - the user data provided in + * rc - integer value indicating the reason for the disconnect. A value of 0 + * means the client has called . Any other value + * indicates that the disconnect is unexpected. + * props - list of MQTT 5 properties, or NULL + */ +libmosq_EXPORT void mosquitto_disconnect_v5_callback_set(struct mosquitto *mosq, void (*on_disconnect)(struct mosquitto *, void *, int, const mosquitto_property *)); + /* * Function: mosquitto_publish_callback_set * @@ -1631,6 +1678,25 @@ libmosq_EXPORT void mosquitto_disconnect_callback_set(struct mosquitto *mosq, vo */ libmosq_EXPORT void mosquitto_publish_callback_set(struct mosquitto *mosq, void (*on_publish)(struct mosquitto *, void *, int)); +/* + * Function: mosquitto_publish_v5_callback_set + * + * Set the publish callback. This is called when a message initiated with + * has been sent to the broker successfully. + * + * Parameters: + * mosq - a valid mosquitto instance. + * on_publish - a callback function in the following form: + * void callback(struct mosquitto *mosq, void *obj, int mid) + * + * Callback Parameters: + * mosq - the mosquitto instance making the callback. + * obj - the user data provided in + * mid - the message id of the sent message. + * props - list of MQTT 5 properties, or NULL + */ +libmosq_EXPORT void mosquitto_publish_v5_callback_set(struct mosquitto *mosq, void (*on_publish)(struct mosquitto *, void *, int, const mosquitto_property *)); + /* * Function: mosquitto_message_callback_set * @@ -1654,6 +1720,30 @@ libmosq_EXPORT void mosquitto_publish_callback_set(struct mosquitto *mosq, void */ libmosq_EXPORT void mosquitto_message_callback_set(struct mosquitto *mosq, void (*on_message)(struct mosquitto *, void *, const struct mosquitto_message *)); +/* + * Function: mosquitto_message_v5_callback_set + * + * Set the message callback. This is called when a message is received from the + * broker. + * + * Parameters: + * mosq - a valid mosquitto instance. + * on_message - a callback function in the following form: + * void callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message) + * + * Callback Parameters: + * mosq - the mosquitto instance making the callback. + * obj - the user data provided in + * message - the message data. This variable and associated memory will be + * freed by the library after the callback completes. The client + * should make copies of any of the data it requires. + * props - list of MQTT 5 properties, or NULL + * + * See Also: + * + */ +libmosq_EXPORT void mosquitto_message_v5_callback_set(struct mosquitto *mosq, void (*on_message)(struct mosquitto *, void *, const struct mosquitto_message *, const mosquitto_property *)); + /* * Function: mosquitto_subscribe_callback_set * @@ -1675,6 +1765,28 @@ libmosq_EXPORT void mosquitto_message_callback_set(struct mosquitto *mosq, void */ libmosq_EXPORT void mosquitto_subscribe_callback_set(struct mosquitto *mosq, void (*on_subscribe)(struct mosquitto *, void *, int, int, const int *)); +/* + * Function: mosquitto_subscribe_v5_callback_set + * + * Set the subscribe callback. This is called when the broker responds to a + * subscription request. + * + * Parameters: + * mosq - a valid mosquitto instance. + * on_subscribe - a callback function in the following form: + * void callback(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos) + * + * Callback Parameters: + * mosq - the mosquitto instance making the callback. + * obj - the user data provided in + * mid - the message id of the subscribe message. + * qos_count - the number of granted subscriptions (size of granted_qos). + * granted_qos - an array of integers indicating the granted QoS for each of + * the subscriptions. + * props - list of MQTT 5 properties, or NULL + */ +libmosq_EXPORT void mosquitto_subscribe_v5_callback_set(struct mosquitto *mosq, void (*on_subscribe)(struct mosquitto *, void *, int, int, const int *, const mosquitto_property *)); + /* * Function: mosquitto_unsubscribe_callback_set * @@ -1693,6 +1805,25 @@ libmosq_EXPORT void mosquitto_subscribe_callback_set(struct mosquitto *mosq, voi */ libmosq_EXPORT void mosquitto_unsubscribe_callback_set(struct mosquitto *mosq, void (*on_unsubscribe)(struct mosquitto *, void *, int)); +/* + * Function: mosquitto_unsubscribe_v5_callback_set + * + * Set the unsubscribe callback. This is called when the broker responds to a + * unsubscription request. + * + * Parameters: + * mosq - a valid mosquitto instance. + * on_unsubscribe - a callback function in the following form: + * void callback(struct mosquitto *mosq, void *obj, int mid) + * + * Callback Parameters: + * mosq - the mosquitto instance making the callback. + * obj - the user data provided in + * mid - the message id of the unsubscribe message. + * props - list of MQTT 5 properties, or NULL + */ +libmosq_EXPORT void mosquitto_unsubscribe_v5_callback_set(struct mosquitto *mosq, void (*on_unsubscribe)(struct mosquitto *, void *, int, const mosquitto_property *)); + /* * Function: mosquitto_log_callback_set * diff --git a/lib/mosquitto_internal.h b/lib/mosquitto_internal.h index e8fc1b7e3e..acc1d21ecd 100644 --- a/lib/mosquitto_internal.h +++ b/lib/mosquitto_internal.h @@ -254,11 +254,17 @@ struct mosquitto { struct mosquitto_message_all *out_messages_last; void (*on_connect)(struct mosquitto *, void *userdata, int rc); void (*on_connect_with_flags)(struct mosquitto *, void *userdata, int rc, int flags); + void (*on_connect_v5)(struct mosquitto *, void *userdata, int rc, int flags, const mosquitto_property *props); void (*on_disconnect)(struct mosquitto *, void *userdata, int rc); + void (*on_disconnect_v5)(struct mosquitto *, void *userdata, int rc, const mosquitto_property *props); void (*on_publish)(struct mosquitto *, void *userdata, int mid); + void (*on_publish_v5)(struct mosquitto *, void *userdata, int mid, const mosquitto_property *props); void (*on_message)(struct mosquitto *, void *userdata, const struct mosquitto_message *message); + void (*on_message_v5)(struct mosquitto *, void *userdata, const struct mosquitto_message *message, const mosquitto_property *props); void (*on_subscribe)(struct mosquitto *, void *userdata, int mid, int qos_count, const int *granted_qos); + void (*on_subscribe_v5)(struct mosquitto *, void *userdata, int mid, int qos_count, const int *granted_qos, const mosquitto_property *props); void (*on_unsubscribe)(struct mosquitto *, void *userdata, int mid); + void (*on_unsubscribe_v5)(struct mosquitto *, void *userdata, int mid, const mosquitto_property *props); void (*on_log)(struct mosquitto *, void *userdata, int level, const char *str); //void (*on_error)(); char *host; diff --git a/lib/packet_mosq.c b/lib/packet_mosq.c index 1994df252c..ce61cb5026 100644 --- a/lib/packet_mosq.c +++ b/lib/packet_mosq.c @@ -217,6 +217,12 @@ int packet__write(struct mosquitto *mosq) mosq->on_publish(mosq, mosq->userdata, packet->mid); mosq->in_callback = false; } + if(mosq->on_publish_v5){ + /* This is a QoS=0 message */ + mosq->in_callback = true; + mosq->on_publish_v5(mosq, mosq->userdata, packet->mid, NULL); + mosq->in_callback = false; + } pthread_mutex_unlock(&mosq->callback_mutex); }else if(((packet->command)&0xF0) == CMD_DISCONNECT){ /* FIXME what cleanup needs doing here? @@ -250,6 +256,11 @@ int packet__write(struct mosquitto *mosq) mosq->on_disconnect(mosq, mosq->userdata, MOSQ_ERR_SUCCESS); mosq->in_callback = false; } + if(mosq->on_disconnect_v5){ + mosq->in_callback = true; + mosq->on_disconnect_v5(mosq, mosq->userdata, MOSQ_ERR_SUCCESS, NULL); + mosq->in_callback = false; + } pthread_mutex_unlock(&mosq->callback_mutex); pthread_mutex_unlock(&mosq->current_out_packet_mutex); return MOSQ_ERR_SUCCESS; diff --git a/lib/srv_mosq.c b/lib/srv_mosq.c index 0219dd8a0d..53e7881ddb 100644 --- a/lib/srv_mosq.c +++ b/lib/srv_mosq.c @@ -49,6 +49,11 @@ static void srv_callback(void *arg, int status, int timeouts, unsigned char *abu mosq->on_disconnect(mosq, mosq->userdata, MOSQ_ERR_LOOKUP); mosq->in_callback = false; } + if(mosq->on_disconnect_v5){ + mosq->in_callback = true; + mosq->on_disconnect_v5(mosq, mosq->userdata, MOSQ_ERR_LOOKUP, NULL); + mosq->in_callback = false; + } pthread_mutex_unlock(&mosq->callback_mutex); } } diff --git a/lib/util_mosq.c b/lib/util_mosq.c index 4909862c61..e67eaa1533 100644 --- a/lib/util_mosq.c +++ b/lib/util_mosq.c @@ -107,6 +107,11 @@ void mosquitto__check_keepalive(struct mosquitto *mosq) mosq->on_disconnect(mosq, mosq->userdata, rc); mosq->in_callback = false; } + if(mosq->on_disconnect_v5){ + mosq->in_callback = true; + mosq->on_disconnect_v5(mosq, mosq->userdata, rc, NULL); + mosq->in_callback = false; + } pthread_mutex_unlock(&mosq->callback_mutex); #endif } From 59b3fdfdf864aa247c4e5551608eeb7eaa8ba86d Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 20 Nov 2018 16:41:42 +0000 Subject: [PATCH 089/254] Add client property value reading functions. --- lib/linker.version | 20 ++++-- lib/mosquitto.h | 146 +++++++++++++++++++++++++++++++++++++++++++ lib/property_mosq.c | 149 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 308 insertions(+), 7 deletions(-) diff --git a/lib/linker.version b/lib/linker.version index 490b4a2352..06f6e40aac 100644 --- a/lib/linker.version +++ b/lib/linker.version @@ -95,7 +95,10 @@ MOSQ_1.5 { MOSQ_1.6 { global: mosquitto_connect_bind_with_properties; + mosquitto_connect_v5_callback_set; + mosquitto_disconnect_v5_callback_set; mosquitto_disconnect_with_properties; + mosquitto_message_v5_callback_set; mosquitto_property_add_binary; mosquitto_property_add_byte; mosquitto_property_add_int16; @@ -103,20 +106,25 @@ MOSQ_1.6 { mosquitto_property_add_string; mosquitto_property_add_string_pair; mosquitto_property_add_varint; + mosquitto_property_get_property; + mosquitto_property_read_binary; + mosquitto_property_read_byte; + mosquitto_property_read_int16; + mosquitto_property_read_int32; + mosquitto_property_read_string; + mosquitto_property_read_string_pair; + mosquitto_property_read_varint; mosquitto_property_free_all; mosquitto_property_check_command; mosquitto_property_check_all; + mosquitto_publish_v5_callback_set; mosquitto_publish_with_properties; mosquitto_string_to_command; mosquitto_string_to_property_info; mosquitto_subscribe_multiple; + mosquitto_subscribe_v5_callback_set; mosquitto_subscribe_with_properties; + mosquitto_unsubscribe_v5_callback_set; mosquitto_unsubscribe_with_properties; mosquitto_will_set_with_properties; - mosquitto_connect_v5_callback_set; - mosquitto_disconnect_v5_callback_set; - mosquitto_publish_v5_callback_set; - mosquitto_message_v5_callback_set; - mosquitto_subscribe_v5_callback_set; - mosquitto_unsubscribe_v5_callback_set; } MOSQ_1.5; diff --git a/lib/mosquitto.h b/lib/mosquitto.h index 0f586fb2bc..ec392a0411 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -2412,6 +2412,152 @@ libmosq_EXPORT int mosquitto_property_add_string(mosquitto_property **proplist, */ libmosq_EXPORT int mosquitto_property_add_string_pair(mosquitto_property **proplist, int identifier, const char *name, const char *value); +/* + * Function: mosquitto_property_get_property + * + * Retrieve a property matching an identifier, from a property list. This + * function can search for multiple entries of an identifier by using the + * returned value and skip_first. + * + * Parameters: + * proplist - mosquitto_property pointer, the list of properties + * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) + * skip_first - boolean that indicates whether the first item in the list + * should be ignored or not. + * + * Returns: + * A valid property pointer if the property is found + * NULL, if the property is not found, or proplist is NULL. + * + * Example: + * // proplist is obtained from a callback + * mosquitto_property *prop; + * prop = mosquitto_property_get_property(proplist, MQTT_PROP_USER_PROPERTY, false); + * while(prop){ + * mosquitto_property_read_string_pair(prop, &key, &value); + * printf("key: %s value: %s\n", key, value); + * + * prop = mosquitto_property_get_property(prop, MQTT_PROP_USER_PROPERTY, true); + * } + */ +libmosq_EXPORT const mosquitto_property *mosquitto_property_get_property(const mosquitto_property *proplist, int identifier, bool skip_first); + +/* + * Function: mosquitto_property_read_byte + * + * Read a byte property value from a property. + * + * Parameters: + * property - property to read + * value - pointer to integer, for the property to be stored in + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if property or value is NULL, or if property is not a byte + */ +libmosq_EXPORT int mosquitto_property_read_byte(const mosquitto_property *property, uint8_t *value); + +/* + * Function: mosquitto_property_read_int16 + * + * Read an int16 property value from a property. + * + * Parameters: + * property - property to read + * value - pointer to integer, for the property to be stored in + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if property or value is NULL, or if property is not a uint16 + */ +libmosq_EXPORT int mosquitto_property_read_int16(const mosquitto_property *property, uint16_t *value); + +/* + * Function: mosquitto_property_read_int32 + * + * Read an int32 property value from a property. + * + * Parameters: + * property - pointer to mosquitto_property pointer, the list of properties + * value - pointer to integer, for the property to be stored in + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if property or value is NULL, or if property is not an int32 + */ +libmosq_EXPORT int mosquitto_property_read_int32(const mosquitto_property *property, uint32_t *value); + +/* + * Function: mosquitto_property_read_varint + * + * Read a varint property value from a property. + * + * Parameters: + * property - property to read + * value - pointer to integer, for the property to be stored in + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if property or value is NULL, or if property is not a varint + */ +libmosq_EXPORT int mosquitto_property_read_varint(const mosquitto_property *property, uint32_t *value); + +/* + * Function: mosquitto_property_read_binary + * + * Read a binary property value from a property. + * + * On success, value must be free()'d by the application. + * + * Parameters: + * property - property to read + * value - pointer to void pointer, for the property data to be stored in + * len - int pointer to store the data length + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if property, len, or value is NULL, or if property is not a binary type + * MOSQ_ERR_NOMEM - on out of memory + */ +libmosq_EXPORT int mosquitto_property_read_binary(const mosquitto_property *property, void **value, int *len); + +/* + * Function: mosquitto_property_read_string + * + * Read a string property value from a property. + * + * On success, value must be free()'d by the application. + * + * Parameters: + * property - property to read + * value - pointer to char*, for the property data to be stored in + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if property or value is NULL, or if property is not a string + * MOSQ_ERR_NOMEM - on out of memory + */ +libmosq_EXPORT int mosquitto_property_read_string(const mosquitto_property *property, char **value); + +/* + * Function: mosquitto_property_read_string_pair + * + * Read a string pair property value pair from a property. + * + * On success, name and value must be free()'d by the application. + * + * Parameters: + * property - property to read + * name - pointer to char* for the name property data to be stored in + * value - pointer to char* for the value property data to be stored in + * + * Returns: + * MOSQ_ERR_SUCCESS - on success + * MOSQ_ERR_INVAL - if property, name, or value is NULL, or if property is not a string pair + * MOSQ_ERR_NOMEM - on out of memory + */ +libmosq_EXPORT int mosquitto_property_read_string_pair(const mosquitto_property *property, char **name, char **value); + /* * Function: mosquitto_property_free_all * diff --git a/lib/property_mosq.c b/lib/property_mosq.c index 4dd5c22e7c..46ab2d8a94 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -768,7 +768,6 @@ int mosquitto_property_add_string(mosquitto_property **proplist, int identifier, if(value && strlen(value)){ prop->value.s.v = mosquitto__strdup(value); if(!prop->value.s.v){ - mosquitto__free(prop->name.v); mosquitto__free(prop); return MOSQ_ERR_NOMEM; } @@ -873,3 +872,151 @@ int mosquitto_property_check_all(int command, const mosquitto_property *properti return MOSQ_ERR_SUCCESS; } + +const mosquitto_property *mosquitto_property_get_property(const mosquitto_property *proplist, int identifier, bool skip_first) +{ + const mosquitto_property *p; + bool is_first = true; + + p = proplist; + + while(p){ + if(p->identifier == identifier){ + if(!is_first || !skip_first){ + return p; + } + is_first = false; + } + p = p->next; + } + return NULL; +} + + +int mosquitto_property_read_byte(const mosquitto_property *property, uint8_t *value) +{ + if(!property || !value) return MOSQ_ERR_INVAL; + if(property->identifier != MQTT_PROP_PAYLOAD_FORMAT_INDICATOR + && property->identifier != MQTT_PROP_REQUEST_PROBLEM_INFORMATION + && property->identifier != MQTT_PROP_REQUEST_RESPONSE_INFORMATION + && property->identifier != MQTT_PROP_MAXIMUM_QOS + && property->identifier != MQTT_PROP_RETAIN_AVAILABLE + && property->identifier != MQTT_PROP_WILDCARD_SUB_AVAILABLE + && property->identifier != MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE + && property->identifier != MQTT_PROP_SHARED_SUB_AVAILABLE){ + return MOSQ_ERR_INVAL; + } + + *value = property->value.i8; + + return MOSQ_ERR_SUCCESS; +} + + +int mosquitto_property_read_int16(const mosquitto_property *property, uint16_t *value) +{ + if(!property || !value) return MOSQ_ERR_INVAL; + if(property->identifier != MQTT_PROP_SERVER_KEEP_ALIVE + && property->identifier != MQTT_PROP_RECEIVE_MAXIMUM + && property->identifier != MQTT_PROP_TOPIC_ALIAS_MAXIMUM + && property->identifier != MQTT_PROP_TOPIC_ALIAS){ + return MOSQ_ERR_INVAL; + } + + *value = property->value.i16; + + return MOSQ_ERR_SUCCESS; +} + + +int mosquitto_property_read_int32(const mosquitto_property *property, uint32_t *value) +{ + if(!property || !value) return MOSQ_ERR_INVAL; + if(property->identifier != MQTT_PROP_MESSAGE_EXPIRY_INTERVAL + && property->identifier != MQTT_PROP_SESSION_EXPIRY_INTERVAL + && property->identifier != MQTT_PROP_WILL_DELAY_INTERVAL + && property->identifier != MQTT_PROP_MAXIMUM_PACKET_SIZE){ + + return MOSQ_ERR_INVAL; + } + + *value = property->value.i32; + + return MOSQ_ERR_SUCCESS; +} + + +int mosquitto_property_read_varint(const mosquitto_property *property, uint32_t *value) +{ + if(!property || !value) return MOSQ_ERR_INVAL; + if(property->identifier != MQTT_PROP_SUBSCRIPTION_IDENTIFIER){ + return MOSQ_ERR_INVAL; + } + + *value = property->value.varint; + + return MOSQ_ERR_SUCCESS; +} + + +int mosquitto_property_read_binary(const mosquitto_property *property, void **value, int *len) +{ + if(!property || !value || !len) return MOSQ_ERR_INVAL; + if(property->identifier != MQTT_PROP_CORRELATION_DATA + && property->identifier != MQTT_PROP_AUTHENTICATION_DATA){ + + return MOSQ_ERR_INVAL; + } + + *len = property->value.bin.len; + *value = malloc(*len); + if(!value) return MOSQ_ERR_NOMEM; + + memcpy(*value, property->value.bin.v, *len); + + return MOSQ_ERR_SUCCESS; +} + + +int mosquitto_property_read_string(const mosquitto_property *property, char **value) +{ + if(!property || !value) return MOSQ_ERR_INVAL; + if(property->identifier != MQTT_PROP_CONTENT_TYPE + && property->identifier != MQTT_PROP_RESPONSE_TOPIC + && property->identifier != MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER + && property->identifier != MQTT_PROP_AUTHENTICATION_METHOD + && property->identifier != MQTT_PROP_RESPONSE_INFORMATION + && property->identifier != MQTT_PROP_SERVER_REFERENCE + && property->identifier != MQTT_PROP_REASON_STRING){ + + return MOSQ_ERR_INVAL; + } + + *value = calloc(1, property->value.s.len+1); + if(!value) return MOSQ_ERR_NOMEM; + + memcpy(*value, property->value.s.v, property->value.s.len); + + return MOSQ_ERR_SUCCESS; +} + + +int mosquitto_property_read_string_pair(const mosquitto_property *property, char **name, char **value) +{ + if(!property || !name || !value) return MOSQ_ERR_INVAL; + if(property->identifier != MQTT_PROP_USER_PROPERTY) return MOSQ_ERR_INVAL; + + *name = calloc(1, property->name.len+1); + if(!name) return MOSQ_ERR_NOMEM; + + *value = calloc(1, property->value.s.len+1); + if(!value){ + free(*name); + return MOSQ_ERR_NOMEM; + } + + memcpy(*name, property->name.v, property->name.len); + memcpy(*value, property->value.s.v, property->value.s.len); + + return MOSQ_ERR_SUCCESS; +} From 94631ae68b97e4acc9460a439bbcd0e3a87d23f6 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 20 Nov 2018 17:54:44 +0000 Subject: [PATCH 090/254] Don't free properties any more, we use them. --- lib/handle_publish.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/handle_publish.c b/lib/handle_publish.c index 659260a1e4..ed93703e7e 100644 --- a/lib/handle_publish.c +++ b/lib/handle_publish.c @@ -77,7 +77,6 @@ int handle__publish(struct mosquitto *mosq) if(mosq->protocol == mosq_p_mqtt5){ rc = property__read_all(CMD_PUBLISH, &mosq->in_packet, &properties); if(rc) return rc; - mosquitto_property_free_all(&properties); } message->msg.payloadlen = mosq->in_packet.remaining_length - mosq->in_packet.pos; From 22f284671df22899de680998e2152fa8061fbc59 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 20 Nov 2018 17:58:12 +0000 Subject: [PATCH 091/254] Request-response test with/without correlation data --- test/lib/03-request-response-correlation.py | 99 +++++++++++++++++++ test/lib/03-request-response.py | 96 ++++++++++++++++++ test/lib/Makefile | 2 + test/lib/c/03-request-response-1.c | 61 ++++++++++++ test/lib/c/03-request-response-2.c | 68 +++++++++++++ .../lib/c/03-request-response-correlation-1.c | 62 ++++++++++++ test/lib/c/Makefile | 11 ++- test/lib/ptest.py | 6 +- 8 files changed, 400 insertions(+), 5 deletions(-) create mode 100755 test/lib/03-request-response-correlation.py create mode 100755 test/lib/03-request-response.py create mode 100644 test/lib/c/03-request-response-1.c create mode 100644 test/lib/c/03-request-response-2.c create mode 100644 test/lib/c/03-request-response-correlation-1.c diff --git a/test/lib/03-request-response-correlation.py b/test/lib/03-request-response-correlation.py new file mode 100755 index 0000000000..43b055a18e --- /dev/null +++ b/test/lib/03-request-response-correlation.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python + +import inspect +import os +import socket +import sys + +# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder +cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) +if cmd_subfolder not in sys.path: + sys.path.insert(0, cmd_subfolder) + +import mosq_test +import mqtt5_props + +port = mosq_test.get_lib_port() + + +resp_topic = "response/topic" +pub_topic = "request/topic" + +rc = 1 +keepalive = 60 +connect1_packet = mosq_test.gen_connect("request-test", keepalive=keepalive, proto_ver=5) +connect2_packet = mosq_test.gen_connect("response-test", keepalive=keepalive, proto_ver=5) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +mid = 1 +subscribe1_packet = mosq_test.gen_subscribe(mid, resp_topic, 0, proto_ver=5) +subscribe2_packet = mosq_test.gen_subscribe(mid, pub_topic, 0, proto_ver=5) +suback_packet = mosq_test.gen_suback(mid, 0, proto_ver=5) + + +props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_RESPONSE_TOPIC, resp_topic) +props += mqtt5_props.gen_string_prop(mqtt5_props.PROP_CORRELATION_DATA, "corridor") +props = mqtt5_props.prop_finalise(props) +publish1_packet = mosq_test.gen_publish(pub_topic, qos=0, payload="action", proto_ver=5, properties=props) + +props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_CORRELATION_DATA, "corridor") +props = mqtt5_props.prop_finalise(props) +publish2_packet = mosq_test.gen_publish(resp_topic, qos=0, payload="a response", proto_ver=5, properties=props) + + +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) + +env = dict(os.environ) +env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' +try: + pp = env['PYTHONPATH'] +except KeyError: + pp = '' +env['PYTHONPATH'] = '../../lib/python:'+pp +client1 = mosq_test.start_client(filename="03-request-response-correlation-1.log", cmd=["c/03-request-response-correlation-1.test"], env=env, port=port) + +try: + (conn1, address) = sock.accept() + conn1.settimeout(10) + + client2 = mosq_test.start_client(filename="03-request-response-2.log", cmd=["c/03-request-response-2.test"], env=env, port=port) + (conn2, address) = sock.accept() + conn2.settimeout(10) + + if mosq_test.expect_packet(conn1, "connect1", connect1_packet): + conn1.send(connack_packet) + + if mosq_test.expect_packet(conn2, "connect2", connect2_packet): + conn2.send(connack_packet) + + if mosq_test.expect_packet(conn1, "subscribe1", subscribe1_packet): + conn1.send(suback_packet) + + if mosq_test.expect_packet(conn2, "subscribe2", subscribe2_packet): + conn2.send(suback_packet) + + if mosq_test.expect_packet(conn1, "publish1", publish1_packet): + conn2.send(publish1_packet) + + if mosq_test.expect_packet(conn2, "publish2", publish2_packet): + rc = 0 + + conn1.close() + conn2.close() +finally: + client1.terminate() + client1.wait() + client2.terminate() + client2.wait() + if rc: + (stdo, stde) = client1.communicate() + print(stde) + (stdo, stde) = client2.communicate() + print(stde) + sock.close() + +exit(rc) diff --git a/test/lib/03-request-response.py b/test/lib/03-request-response.py new file mode 100755 index 0000000000..6ff0486134 --- /dev/null +++ b/test/lib/03-request-response.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python + +import inspect +import os +import socket +import sys + +# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder +cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) +if cmd_subfolder not in sys.path: + sys.path.insert(0, cmd_subfolder) + +import mosq_test +import mqtt5_props + +port = mosq_test.get_lib_port() + + +resp_topic = "response/topic" +pub_topic = "request/topic" + +rc = 1 +keepalive = 60 +connect1_packet = mosq_test.gen_connect("request-test", keepalive=keepalive, proto_ver=5) +connect2_packet = mosq_test.gen_connect("response-test", keepalive=keepalive, proto_ver=5) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +mid = 1 +subscribe1_packet = mosq_test.gen_subscribe(mid, resp_topic, 0, proto_ver=5) +subscribe2_packet = mosq_test.gen_subscribe(mid, pub_topic, 0, proto_ver=5) +suback_packet = mosq_test.gen_suback(mid, 0, proto_ver=5) + + +props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_RESPONSE_TOPIC, resp_topic) +props = mqtt5_props.prop_finalise(props) +publish1_packet = mosq_test.gen_publish(pub_topic, qos=0, payload="action", proto_ver=5, properties=props) + +publish2_packet = mosq_test.gen_publish(resp_topic, qos=0, payload="a response", 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) + +env = dict(os.environ) +env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' +try: + pp = env['PYTHONPATH'] +except KeyError: + pp = '' +env['PYTHONPATH'] = '../../lib/python:'+pp +client1 = mosq_test.start_client(filename="03-request-response-1.log", cmd=["c/03-request-response-1.test"], env=env, port=port) + +try: + (conn1, address) = sock.accept() + conn1.settimeout(10) + + client2 = mosq_test.start_client(filename="03-request-response-2.log", cmd=["c/03-request-response-2.test"], env=env, port=port) + (conn2, address) = sock.accept() + conn2.settimeout(10) + + if mosq_test.expect_packet(conn1, "connect1", connect1_packet): + conn1.send(connack_packet) + + if mosq_test.expect_packet(conn2, "connect2", connect2_packet): + conn2.send(connack_packet) + + if mosq_test.expect_packet(conn1, "subscribe1", subscribe1_packet): + conn1.send(suback_packet) + + if mosq_test.expect_packet(conn2, "subscribe2", subscribe2_packet): + conn2.send(suback_packet) + + if mosq_test.expect_packet(conn1, "publish1", publish1_packet): + conn2.send(publish1_packet) + + if mosq_test.expect_packet(conn2, "publish2", publish2_packet): + rc = 0 + + conn1.close() + conn2.close() +finally: + client1.terminate() + client1.wait() + client2.terminate() + client2.wait() + if rc: + (stdo, stde) = client1.communicate() + print(stde) + (stdo, stde) = client2.communicate() + print(stde) + sock.close() + +exit(rc) diff --git a/test/lib/Makefile b/test/lib/Makefile index bf5a931fbe..c1107921e0 100644 --- a/test/lib/Makefile +++ b/test/lib/Makefile @@ -38,6 +38,8 @@ c cpp : test-compile ./03-publish-c2b-qos2-disconnect.py $@/03-publish-c2b-qos2-disconnect.test ./03-publish-b2c-qos1.py $@/03-publish-b2c-qos1.test ./03-publish-b2c-qos2.py $@/03-publish-b2c-qos2.test + ./03-request-response.py $@/03-request-response.test + ./03-request-response-correlation.py $@/03-request-response-correlation.test ./04-retain-qos0.py $@/04-retain-qos0.test ifeq ($(WITH_TLS),yes) ./08-ssl-connect-no-auth.py $@/08-ssl-connect-no-auth.test diff --git a/test/lib/c/03-request-response-1.c b/test/lib/c/03-request-response-1.c new file mode 100644 index 0000000000..5c7b5bf5ca --- /dev/null +++ b/test/lib/c/03-request-response-1.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include + +static int run = -1; +static int sent_mid = -1; + +void on_connect(struct mosquitto *mosq, void *obj, int rc) +{ + if(rc){ + exit(1); + }else{ + mosquitto_subscribe(mosq, NULL, "response/topic", 0); + } +} + +void on_subscribe(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos) +{ + mosquitto_property *props = NULL; + mosquitto_property_add_string(&props, MQTT_PROP_RESPONSE_TOPIC, "response/topic"); + mosquitto_publish_with_properties(mosq, NULL, "request/topic", 6, "action", 0, 0, props); + mosquitto_property_free_all(&props); +} + +void on_message(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg) +{ + if(!strcmp(msg->payload, "a response")){ + run = 0; + }else{ + run = 1; + } +} + +int main(int argc, char *argv[]) +{ + int rc; + struct mosquitto *mosq; + int ver = PROTOCOL_VERSION_v5; + + int port = atoi(argv[1]); + + mosquitto_lib_init(); + + mosq = mosquitto_new("request-test", true, NULL); + mosquitto_opts_set(mosq, MOSQ_OPT_PROTOCOL_VERSION, &ver); + mosquitto_connect_callback_set(mosq, on_connect); + mosquitto_subscribe_callback_set(mosq, on_subscribe); + mosquitto_message_callback_set(mosq, on_message); + + rc = mosquitto_connect(mosq, "localhost", port, 60); + + while(run == -1){ + rc = mosquitto_loop(mosq, -1, 1); + } + + mosquitto_lib_cleanup(); + return run; +} diff --git a/test/lib/c/03-request-response-2.c b/test/lib/c/03-request-response-2.c new file mode 100644 index 0000000000..8763496f56 --- /dev/null +++ b/test/lib/c/03-request-response-2.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include +#include + +static int run = -1; +static int sent_mid = -1; + +void on_connect(struct mosquitto *mosq, void *obj, int rc) +{ + if(rc){ + exit(1); + }else{ + mosquitto_subscribe(mosq, NULL, "request/topic", 0); + } +} + +void on_message_v5(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg, const mosquitto_property *props) +{ + const mosquitto_property *p_resp, *p_corr = NULL; + char *resp_topic = NULL; + int rc; + + if(!strcmp(msg->topic, "request/topic")){ + p_resp = mosquitto_property_get_property(props, MQTT_PROP_RESPONSE_TOPIC, false); + if(p_resp){ + p_corr = mosquitto_property_get_property(props, MQTT_PROP_CORRELATION_DATA, false); + if(mosquitto_property_read_string(p_resp, &resp_topic) == MOSQ_ERR_SUCCESS){ + rc = mosquitto_publish_with_properties(mosq, NULL, resp_topic, strlen("a response"), "a response", 0, false, p_corr); + free(resp_topic); + } + } + } +} + +void on_publish(struct mosquitto *mosq, void *obj, int mid) +{ + run = 0; +} + + +int main(int argc, char *argv[]) +{ + int rc; + struct mosquitto *mosq; + int ver = PROTOCOL_VERSION_v5; + + int port = atoi(argv[1]); + + mosquitto_lib_init(); + + mosq = mosquitto_new("response-test", true, NULL); + mosquitto_opts_set(mosq, MOSQ_OPT_PROTOCOL_VERSION, &ver); + mosquitto_connect_callback_set(mosq, on_connect); + mosquitto_publish_callback_set(mosq, on_publish); + mosquitto_message_v5_callback_set(mosq, on_message_v5); + + rc = mosquitto_connect(mosq, "localhost", port, 60); + + while(run == -1){ + rc = mosquitto_loop(mosq, -1, 1); + } + + mosquitto_lib_cleanup(); + return run; +} diff --git a/test/lib/c/03-request-response-correlation-1.c b/test/lib/c/03-request-response-correlation-1.c new file mode 100644 index 0000000000..7724525644 --- /dev/null +++ b/test/lib/c/03-request-response-correlation-1.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include +#include + +static int run = -1; +static int sent_mid = -1; + +void on_connect(struct mosquitto *mosq, void *obj, int rc) +{ + if(rc){ + exit(1); + }else{ + mosquitto_subscribe(mosq, NULL, "response/topic", 0); + } +} + +void on_subscribe(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos) +{ + mosquitto_property *props = NULL; + mosquitto_property_add_string(&props, MQTT_PROP_RESPONSE_TOPIC, "response/topic"); + mosquitto_property_add_binary(&props, MQTT_PROP_CORRELATION_DATA, "corridor", 8); + mosquitto_publish_with_properties(mosq, NULL, "request/topic", 6, "action", 0, 0, props); + mosquitto_property_free_all(&props); +} + +void on_message(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg) +{ + if(!strcmp(msg->payload, "a response")){ + run = 0; + }else{ + run = 1; + } +} + +int main(int argc, char *argv[]) +{ + int rc; + struct mosquitto *mosq; + int ver = PROTOCOL_VERSION_v5; + + int port = atoi(argv[1]); + + mosquitto_lib_init(); + + mosq = mosquitto_new("request-test", true, NULL); + mosquitto_opts_set(mosq, MOSQ_OPT_PROTOCOL_VERSION, &ver); + mosquitto_connect_callback_set(mosq, on_connect); + mosquitto_subscribe_callback_set(mosq, on_subscribe); + mosquitto_message_callback_set(mosq, on_message); + + rc = mosquitto_connect(mosq, "localhost", port, 60); + + while(run == -1){ + rc = mosquitto_loop(mosq, -1, 1); + } + + mosquitto_lib_cleanup(); + return run; +} diff --git a/test/lib/c/Makefile b/test/lib/c/Makefile index 9678766a47..7d936ff3cc 100644 --- a/test/lib/c/Makefile +++ b/test/lib/c/Makefile @@ -53,6 +53,15 @@ all : 01 02 03 04 08 09 03-publish-b2c-qos1.test : 03-publish-b2c-qos1.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) +03-request-response-1.test : 03-request-response-1.c + $(CC) $< -o $@ $(CFLAGS) $(LIBS) + +03-request-response-2.test : 03-request-response-2.c + $(CC) $< -o $@ $(CFLAGS) $(LIBS) + +03-request-response-correlation-1.test : 03-request-response-correlation-1.c + $(CC) $< -o $@ $(CFLAGS) $(LIBS) + 03-publish-b2c-qos2.test : 03-publish-b2c-qos2.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) @@ -81,7 +90,7 @@ all : 01 02 03 04 08 09 02 : 02-subscribe-qos0.test 02-subscribe-qos1.test 02-subscribe-qos2.test 02-unsubscribe.test -03 : 03-publish-qos0.test 03-publish-qos0-no-payload.test 03-publish-c2b-qos1-disconnect.test 03-publish-c2b-qos2.test 03-publish-c2b-qos2-disconnect.test 03-publish-b2c-qos1.test 03-publish-b2c-qos2.test +03 : 03-publish-qos0.test 03-publish-qos0-no-payload.test 03-publish-c2b-qos1-disconnect.test 03-publish-c2b-qos2.test 03-publish-c2b-qos2-disconnect.test 03-publish-b2c-qos1.test 03-publish-b2c-qos2.test 03-request-response-1.test 03-request-response-2.test 03-request-response-correlation-1.test 04 : 04-retain-qos0.test diff --git a/test/lib/ptest.py b/test/lib/ptest.py index 428213790c..c16079f906 100755 --- a/test/lib/ptest.py +++ b/test/lib/ptest.py @@ -23,14 +23,14 @@ ('./03-publish-c2b-qos2.py', 'c/03-publish-c2b-qos2.test'), ('./03-publish-qos0-no-payload.py', 'c/03-publish-qos0-no-payload.test'), ('./03-publish-qos0.py', 'c/03-publish-qos0.test'), + ('./03-request-response.py', 'c/03-request-response.test'), + ('./03-request-response-correlation.py', 'c/03-request-response-correlation.test'), ('./04-retain-qos0.py', 'c/04-retain-qos0.test'), ('./08-ssl-bad-cacert.py', 'c/08-ssl-bad-cacert.test'), ('./08-ssl-connect-cert-auth-enc.py', 'c/08-ssl-connect-cert-auth-enc.test'), ('./08-ssl-connect-cert-auth.py', 'c/08-ssl-connect-cert-auth.test'), ('./08-ssl-connect-no-auth.py', 'c/08-ssl-connect-no-auth.test'), - ('./09-util-topic-matching.py', 'c/09-util-topic-matching.test'), ('./09-util-topic-tokenise.py', 'c/09-util-topic-tokenise.test'), - ('./09-util-utf8-validate.py', 'c/09-util-utf8-validate.test'), ('./01-con-discon-success.py', 'cpp/01-con-discon-success.test'), ('./01-keepalive-pingreq.py', 'cpp/01-keepalive-pingreq.test'), @@ -54,9 +54,7 @@ ('./08-ssl-connect-cert-auth-enc.py', 'cpp/08-ssl-connect-cert-auth-enc.test'), ('./08-ssl-connect-cert-auth.py', 'cpp/08-ssl-connect-cert-auth.test'), ('./08-ssl-connect-no-auth.py', 'cpp/08-ssl-connect-no-auth.test'), - ('./09-util-topic-matching.py', 'cpp/09-util-topic-matching.test'), ('./09-util-topic-tokenise.py', 'cpp/09-util-topic-tokenise.test'), - ('./09-util-utf8-validate.py', 'cpp/09-util-utf8-validate.test'), ] minport = 1888 From bb745b3308138cd2a65e38a7680f3af18c81ad23 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 9 Nov 2018 22:23:11 +0000 Subject: [PATCH 092/254] Client prop test for format-payload-indicator. --- test/lib/11-prop-send-payload-format.py | 75 ++++++++++++++++++++++++ test/lib/Makefile | 3 +- test/lib/c/11-prop-send-payload-format.c | 58 ++++++++++++++++++ test/lib/c/Makefile | 7 ++- test/lib/ptest.py | 2 + test/mosq_test.py | 9 ++- 6 files changed, 150 insertions(+), 4 deletions(-) create mode 100755 test/lib/11-prop-send-payload-format.py create mode 100644 test/lib/c/11-prop-send-payload-format.c diff --git a/test/lib/11-prop-send-payload-format.py b/test/lib/11-prop-send-payload-format.py new file mode 100755 index 0000000000..7e53699071 --- /dev/null +++ b/test/lib/11-prop-send-payload-format.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python + +# Test whether a client sends a correct PUBLISH to a topic with QoS 0. + +# The client should connect to port 1888 with keepalive=60, clean session set, +# and client id publish-qos0-test +# The test will send a CONNACK message to the client with rc=0. Upon receiving +# the CONNACK and verifying that rc=0, the client should send a PUBLISH message +# to topic "pub/qos0/test" with payload "message" and QoS=0. If rc!=0, the +# client should exit with an error. +# After sending the PUBLISH message, the client should send a DISCONNECT message. + +import inspect +import os +import socket +import sys + +# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder +cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) +if cmd_subfolder not in sys.path: + sys.path.insert(0, cmd_subfolder) + +import mosq_test +import mqtt5_props + +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_byte_prop(mqtt5_props.PROP_PAYLOAD_FORMAT_INDICATOR, 0x01) +props = mqtt5_props.prop_finalise(props) +publish_packet = mosq_test.gen_publish("prop/qos0", qos=0, payload="message", proto_ver=5, properties=props) + +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) + + if mosq_test.expect_packet(conn, "publish", publish_packet): + if mosq_test.expect_packet(conn, "disconnect", disconnect_packet): + rc = 0 + + conn.close() +finally: + client.terminate() + client.wait() + if rc: + (stdo, stde) = client.communicate() + print(stde) + sock.close() + +exit(rc) diff --git a/test/lib/Makefile b/test/lib/Makefile index c1107921e0..b1ef54f464 100644 --- a/test/lib/Makefile +++ b/test/lib/Makefile @@ -20,7 +20,7 @@ test-compile-c : test-compile-cpp : $(MAKE) -C cpp -c cpp : test-compile +c : test-compile ./01-con-discon-success.py $@/01-con-discon-success.test ./01-will-set.py $@/01-will-set.test ./01-unpwd-set.py $@/01-unpwd-set.test @@ -49,6 +49,7 @@ ifeq ($(WITH_TLS),yes) #./08-ssl-fake-cacert.py $@/08-ssl-fake-cacert.test endif ./09-util-topic-tokenise.py $@/09-util-topic-tokenise.test + ./11-prop-send-payload-format.py $@/11-prop-send-payload-format.test clean : $(MAKE) -C c clean diff --git a/test/lib/c/11-prop-send-payload-format.c b/test/lib/c/11-prop-send-payload-format.c new file mode 100644 index 0000000000..198ef72fc5 --- /dev/null +++ b/test/lib/c/11-prop-send-payload-format.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include + +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); + }else{ + rc2 = mosquitto_property_add_byte(&proplist, MQTT_PROP_PAYLOAD_FORMAT_INDICATOR, 1); + mosquitto_publish_with_properties(mosq, &sent_mid, "prop/qos0", strlen("message"), "message", 0, false, proplist); + } +} + +void on_publish(struct mosquitto *mosq, void *obj, int mid) +{ + if(mid == sent_mid){ + mosquitto_disconnect(mosq); + run = 0; + }else{ + exit(1); + } +} + +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_publish_callback_set(mosq, on_publish); + tmp = MQTT_PROTOCOL_V5; + mosquitto_opts_set(mosq, MOSQ_OPT_PROTOCOL_VERSION, &tmp); + + rc = mosquitto_connect(mosq, "localhost", port, 60); + + while(run == -1){ + rc = mosquitto_loop(mosq, -1, 1); + } + + mosquitto_lib_cleanup(); + return run; +} diff --git a/test/lib/c/Makefile b/test/lib/c/Makefile index 7d936ff3cc..45a6c7e773 100644 --- a/test/lib/c/Makefile +++ b/test/lib/c/Makefile @@ -3,7 +3,7 @@ CFLAGS=-I../../../lib -Werror LIBS=../../../lib/libmosquitto.so.1 -all : 01 02 03 04 08 09 +all : 01 02 03 04 08 09 11 01-con-discon-success.test : 01-con-discon-success.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) @@ -86,6 +86,9 @@ all : 01 02 03 04 08 09 09-util-topic-tokenise.test : 09-util-topic-tokenise.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) +11-prop-send-payload-format.test : 11-prop-send-payload-format.c + $(CC) $< -o $@ $(CFLAGS) $(LIBS) + 01 : 01-con-discon-success.test 01-will-set.test 01-unpwd-set.test 01-will-unpwd-set.test 01-no-clean-session.test 01-keepalive-pingreq.test 02 : 02-subscribe-qos0.test 02-subscribe-qos1.test 02-subscribe-qos2.test 02-unsubscribe.test @@ -98,6 +101,8 @@ all : 01 02 03 04 08 09 09 : 09-util-topic-tokenise.test +11 : 11-prop-send-payload-format.test + reallyclean : clean -rm -f *.orig diff --git a/test/lib/ptest.py b/test/lib/ptest.py index c16079f906..82cf15d31a 100755 --- a/test/lib/ptest.py +++ b/test/lib/ptest.py @@ -31,6 +31,8 @@ ('./08-ssl-connect-cert-auth.py', 'c/08-ssl-connect-cert-auth.test'), ('./08-ssl-connect-no-auth.py', 'c/08-ssl-connect-no-auth.test'), ('./09-util-topic-tokenise.py', 'c/09-util-topic-tokenise.test'), + ('./09-util-utf8-validate.py', 'c/09-util-utf8-validate.test'), + ('./11-prop-send-payload-format.py', 'c/11/prop-send-payload-format.py'), ('./01-con-discon-success.py', 'cpp/01-con-discon-success.test'), ('./01-keepalive-pingreq.py', 'cpp/01-keepalive-pingreq.test'), diff --git a/test/mosq_test.py b/test/mosq_test.py index 85447d06a6..26fea5282d 100644 --- a/test/mosq_test.py +++ b/test/mosq_test.py @@ -78,6 +78,8 @@ def packet_matches(name, recvd, expected): print("Expected: "+to_string(expected)) except struct.error: print("Expected (not decoded, len=%d): %s" % (len(expected), expected)) + for i in range(0, len(expected)): + print('%c'%(expected[i]),) return 0 else: @@ -459,8 +461,11 @@ def gen_pingreq(): def gen_pingresp(): return struct.pack('!BB', 208, 0) -def gen_disconnect(): - return struct.pack('!BB', 224, 0) +def gen_disconnect(proto_ver=4): + if proto_ver == 5: + return struct.pack('!BBBB', 224, 2, 0, 0) + else: + return struct.pack('!BB', 224, 0) def pack_remaining_length(remaining_length): s = "" From 29cf4266d900ee1561cfdef8adbdbe1a2d45c600 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 9 Nov 2018 22:36:08 +0000 Subject: [PATCH 093/254] Remove old tests from ptest.py. --- test/lib/ptest.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/lib/ptest.py b/test/lib/ptest.py index 82cf15d31a..d3981a7c34 100755 --- a/test/lib/ptest.py +++ b/test/lib/ptest.py @@ -31,8 +31,7 @@ ('./08-ssl-connect-cert-auth.py', 'c/08-ssl-connect-cert-auth.test'), ('./08-ssl-connect-no-auth.py', 'c/08-ssl-connect-no-auth.test'), ('./09-util-topic-tokenise.py', 'c/09-util-topic-tokenise.test'), - ('./09-util-utf8-validate.py', 'c/09-util-utf8-validate.test'), - ('./11-prop-send-payload-format.py', 'c/11/prop-send-payload-format.py'), + ('./11-prop-send-payload-format.py', 'c/11-prop-send-payload-format.test'), ('./01-con-discon-success.py', 'cpp/01-con-discon-success.test'), ('./01-keepalive-pingreq.py', 'cpp/01-keepalive-pingreq.test'), From dd158ffeb317fae74963537e7ed4c314e3e3c2d9 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 21 Nov 2018 22:47:33 +0000 Subject: [PATCH 094/254] Split common publish code into separate file. --- client/CMakeLists.txt | 2 +- client/Makefile | 7 +- client/pub_client.c | 233 +++-------------------------------------- client/pub_shared.c | 238 ++++++++++++++++++++++++++++++++++++++++++ client/pub_shared.h | 41 ++++++++ 5 files changed, 302 insertions(+), 219 deletions(-) create mode 100644 client/pub_shared.c create mode 100644 client/pub_shared.h diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 39a12d1d3a..d53772ed71 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -8,7 +8,7 @@ if (${WITH_SRV} STREQUAL ON) add_definitions("-DWITH_SRV") endif (${WITH_SRV} STREQUAL ON) -add_executable(mosquitto_pub pub_client.c ${shared_src}) +add_executable(mosquitto_pub pub_client.c pub_shared.c ${shared_src}) add_executable(mosquitto_sub sub_client.c sub_client_output.c ${shared_src}) target_link_libraries(mosquitto_pub libmosquitto) diff --git a/client/Makefile b/client/Makefile index 4ffc46b153..39310b973f 100644 --- a/client/Makefile +++ b/client/Makefile @@ -8,13 +8,13 @@ static : static_pub static_sub # This makes mosquitto_pub/sub versions that are statically linked with # libmosquitto only. -static_pub : pub_client.o client_shared.o ../lib/libmosquitto.a +static_pub : pub_client.o pub_shared.o client_shared.o ../lib/libmosquitto.a ${CROSS_COMPILE}${CC} $^ -o mosquitto_pub ${CLIENT_LDFLAGS} -lssl -lcrypto -lpthread static_sub : sub_client.o sub_client_output.o client_shared.o ../lib/libmosquitto.a ${CROSS_COMPILE}${CC} $^ -o mosquitto_sub ${CLIENT_LDFLAGS} -lssl -lcrypto -lpthread -mosquitto_pub : pub_client.o client_shared.o client_props.o +mosquitto_pub : pub_client.o pub_shared.o client_shared.o client_props.o ${CROSS_COMPILE}${CC} $^ -o $@ ${CLIENT_LDFLAGS} mosquitto_sub : sub_client.o sub_client_output.o client_shared.o client_props.o @@ -23,6 +23,9 @@ mosquitto_sub : sub_client.o sub_client_output.o client_shared.o client_props.o pub_client.o : pub_client.c ../lib/libmosquitto.so.${SOVERSION} ${CROSS_COMPILE}${CC} -c $< -o $@ ${CLIENT_CFLAGS} +pub_shared.o : pub_shared.c ../lib/libmosquitto.so.${SOVERSION} + ${CROSS_COMPILE}${CC} -c $< -o $@ ${CLIENT_CFLAGS} + sub_client.o : sub_client.c ../lib/libmosquitto.so.${SOVERSION} ${CROSS_COMPILE}${CC} -c $< -o $@ ${CLIENT_CFLAGS} diff --git a/client/pub_client.c b/client/pub_client.c index 9b5291db55..3f95b74268 100644 --- a/client/pub_client.c +++ b/client/pub_client.c @@ -31,29 +31,10 @@ and the Eclipse Distribution License is available at #include #include "client_shared.h" - -#define STATUS_CONNECTING 0 -#define STATUS_CONNACK_RECVD 1 -#define STATUS_WAITING 2 -#define STATUS_DISCONNECTING 3 +#include "pub_shared.h" /* Global variables for use in callbacks. See sub_client.c for an example of * using a struct to hold variables for use in callbacks. */ -static char *topic = NULL; -static char *message = NULL; -static long msglen = 0; -static int qos = 0; -static int retain = 0; -static int mode = MSGMODE_NONE; -static int status = STATUS_CONNECTING; -static int mid_sent = 0; -static int last_mid = -1; -static int last_mid_sent = -1; -static bool connected = true; -static char *username = NULL; -static char *password = NULL; -static bool disconnect_sent = false; -static bool quiet = false; static struct mosq_config cfg; static bool first_publish = true; @@ -73,21 +54,21 @@ void my_connect_callback(struct mosquitto *mosq, void *obj, int result) int rc = MOSQ_ERR_SUCCESS; if(!result){ - switch(mode){ + switch(cfg.pub_mode){ case MSGMODE_CMD: case MSGMODE_FILE: case MSGMODE_STDIN_FILE: - rc = my_publish(mosq, &mid_sent, topic, msglen, message, qos, retain); + 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, topic, 0, NULL, qos, retain); + rc = my_publish(mosq, &mid_sent, cfg.topic, 0, NULL, cfg.qos, cfg.retain); break; case MSGMODE_STDIN_LINE: status = STATUS_CONNACK_RECVD; break; } if(rc){ - if(!quiet){ + if(!cfg.quiet){ switch(rc){ case MOSQ_ERR_INVAL: fprintf(stderr, "Error: Invalid input. Does your topic contain '+' or '#'?\n"); @@ -109,109 +90,12 @@ void my_connect_callback(struct mosquitto *mosq, void *obj, int result) mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); } }else{ - if(result && !quiet){ + if(result && !cfg.quiet){ fprintf(stderr, "%s\n", mosquitto_connack_string(result)); } } } -void my_disconnect_callback(struct mosquitto *mosq, void *obj, int rc) -{ - connected = false; -} - -void my_publish_callback(struct mosquitto *mosq, void *obj, int mid) -{ - last_mid_sent = mid; - if(mode == MSGMODE_STDIN_LINE){ - if(mid == last_mid){ - mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); - disconnect_sent = true; - } - }else if(disconnect_sent == false){ - mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); - disconnect_sent = true; - } -} - -void my_log_callback(struct mosquitto *mosq, void *obj, int level, const char *str) -{ - printf("%s\n", str); -} - -int load_stdin(void) -{ - long pos = 0, rlen; - char buf[1024]; - char *aux_message = NULL; - - mode = MSGMODE_STDIN_FILE; - - while(!feof(stdin)){ - rlen = fread(buf, 1, 1024, stdin); - aux_message = realloc(message, pos+rlen); - if(!aux_message){ - if(!quiet) fprintf(stderr, "Error: Out of memory.\n"); - free(message); - return 1; - } else - { - message = aux_message; - } - memcpy(&(message[pos]), buf, rlen); - pos += rlen; - } - msglen = pos; - - if(!msglen){ - if(!quiet) fprintf(stderr, "Error: Zero length input.\n"); - return 1; - } - - return 0; -} - -int load_file(const char *filename) -{ - long pos, rlen; - FILE *fptr = NULL; - - fptr = fopen(filename, "rb"); - if(!fptr){ - if(!quiet) fprintf(stderr, "Error: Unable to open file \"%s\".\n", filename); - return 1; - } - mode = MSGMODE_FILE; - fseek(fptr, 0, SEEK_END); - msglen = ftell(fptr); - if(msglen > 268435455){ - fclose(fptr); - if(!quiet) fprintf(stderr, "Error: File \"%s\" is too large (>268,435,455 bytes).\n", filename); - return 1; - }else if(msglen == 0){ - fclose(fptr); - if(!quiet) fprintf(stderr, "Error: File \"%s\" is empty.\n", filename); - return 1; - }else if(msglen < 0){ - fclose(fptr); - if(!quiet) fprintf(stderr, "Error: Unable to determine size of file \"%s\".\n", filename); - return 1; - } - fseek(fptr, 0, SEEK_SET); - message = malloc(msglen); - if(!message){ - fclose(fptr); - if(!quiet) fprintf(stderr, "Error: Out of memory.\n"); - return 1; - } - pos = 0; - while(pos < msglen){ - rlen = fread(&(message[pos]), sizeof(char), msglen-pos, fptr); - pos += rlen; - } - fclose(fptr); - return 0; -} void print_usage(void) { @@ -313,21 +197,11 @@ int main(int argc, char *argv[]) { struct mosquitto *mosq = NULL; int rc; - int rc2; - char *buf, *buf2; - int buf_len = 1024; - int buf_len_actual; - int read_len; - int pos; - - buf = malloc(buf_len); - if(!buf){ - fprintf(stderr, "Error: Out of memory.\n"); - return 1; - } mosquitto_lib_init(); + if(pub_shared_init()) return 1; + memset(&cfg, 0, sizeof(struct mosq_config)); rc = client_config_load(&cfg, CLIENT_PUB, argc, argv); if(rc){ @@ -340,16 +214,6 @@ int main(int argc, char *argv[]) goto cleanup; } - topic = cfg.topic; - message = cfg.message; - msglen = cfg.msglen; - qos = cfg.qos; - retain = cfg.retain; - mode = cfg.pub_mode; - username = cfg.username; - password = cfg.password; - quiet = cfg.quiet; - #ifndef WITH_THREADING if(cfg.pub_mode == MSGMODE_STDIN_LINE){ fprintf(stderr, "Error: '-l' mode not available, threading support has not been compiled in.\n"); @@ -369,7 +233,7 @@ int main(int argc, char *argv[]) } } - if(!topic || mode == MSGMODE_NONE){ + if(!cfg.topic || cfg.pub_mode == MSGMODE_NONE){ fprintf(stderr, "Error: Both topic and message must be supplied.\n"); print_usage(); goto cleanup; @@ -384,10 +248,10 @@ int main(int argc, char *argv[]) if(!mosq){ switch(errno){ case ENOMEM: - if(!quiet) fprintf(stderr, "Error: Out of memory.\n"); + if(!cfg.quiet) fprintf(stderr, "Error: Out of memory.\n"); break; case EINVAL: - if(!quiet) fprintf(stderr, "Error: Invalid id.\n"); + if(!cfg.quiet) fprintf(stderr, "Error: Invalid id.\n"); break; } goto cleanup; @@ -402,84 +266,21 @@ int main(int argc, char *argv[]) if(client_opts_set(mosq, &cfg)){ goto cleanup; } + rc = client_connect(mosq, &cfg); if(rc){ goto cleanup; } - if(mode == MSGMODE_STDIN_LINE){ - mosquitto_loop_start(mosq); - } - - do{ - if(mode == MSGMODE_STDIN_LINE){ - if(status == STATUS_CONNACK_RECVD){ - pos = 0; - read_len = buf_len; - while(fgets(&buf[pos], read_len, stdin)){ - buf_len_actual = strlen(buf); - if(buf[buf_len_actual-1] == '\n'){ - buf[buf_len_actual-1] = '\0'; - rc2 = my_publish(mosq, &mid_sent, topic, buf_len_actual-1, buf, qos, retain); - if(rc2){ - if(!quiet) fprintf(stderr, "Error: Publish returned %d, disconnecting.\n", rc2); - mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); - } - break; - }else{ - buf_len += 1024; - pos += 1023; - read_len = 1024; - buf2 = realloc(buf, buf_len); - if(!buf2){ - fprintf(stderr, "Error: Out of memory.\n"); - goto cleanup; - } - buf = buf2; - } - } - if(feof(stdin)){ - if(last_mid == -1){ - /* Empty file */ - mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); - disconnect_sent = true; - status = STATUS_DISCONNECTING; - }else{ - last_mid = mid_sent; - status = STATUS_WAITING; - } - } - }else if(status == STATUS_WAITING){ - if(last_mid_sent == last_mid && disconnect_sent == false){ - mosquitto_disconnect_with_properties(mosq, 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 = MOSQ_ERR_SUCCESS; - }else{ - rc = mosquitto_loop(mosq, -1, 1); - } - }while(rc == MOSQ_ERR_SUCCESS && connected); - - if(mode == MSGMODE_STDIN_LINE){ - mosquitto_loop_stop(mosq, false); - } + rc = pub_shared_loop(mosq); - if(message && mode == MSGMODE_FILE){ - free(message); + if(cfg.message && cfg.pub_mode == MSGMODE_FILE){ + free(cfg.message); } mosquitto_destroy(mosq); mosquitto_lib_cleanup(); client_config_cleanup(&cfg); - free(buf); + pub_shared_cleanup(); if(rc){ fprintf(stderr, "Error: %s\n", mosquitto_strerror(rc)); @@ -489,6 +290,6 @@ int main(int argc, char *argv[]) cleanup: mosquitto_lib_cleanup(); client_config_cleanup(&cfg); - free(buf); + pub_shared_cleanup(); return 1; } diff --git a/client/pub_shared.c b/client/pub_shared.c new file mode 100644 index 0000000000..26fcab91d9 --- /dev/null +++ b/client/pub_shared.c @@ -0,0 +1,238 @@ +/* +Copyright (c) 2009-2018 Roger Light + +All rights reserved. This program and the accompanying materials +are made available under the terms of the Eclipse Public License v1.0 +and Eclipse Distribution License v1.0 which accompany this distribution. + +The Eclipse Public License is available at + http://www.eclipse.org/legal/epl-v10.html +and the Eclipse Distribution License is available at + http://www.eclipse.org/org/documents/edl-v10.php. + +Contributors: + Roger Light - initial implementation and documentation. +*/ + +#include "config.h" + +#include +#include +#include +#include +#include +#ifndef WIN32 +#include +#else +#include +#include +#define snprintf sprintf_s +#endif + +#include +#include "client_shared.h" +#include "pub_shared.h" + +/* 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 = 0; +int status = STATUS_CONNECTING; +static int last_mid = -1; +static int last_mid_sent = -1; +static bool connected = true; +static bool disconnect_sent = false; +static struct mosq_config cfg; +static char *buf; +static int buf_len = 1024; + +void my_disconnect_callback(struct mosquitto *mosq, void *obj, int rc) +{ + connected = false; +} + +void my_publish_callback(struct mosquitto *mosq, void *obj, int mid) +{ + last_mid_sent = mid; + if(cfg.pub_mode == MSGMODE_STDIN_LINE){ + if(mid == last_mid){ + mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); + disconnect_sent = true; + } + }else if(disconnect_sent == false){ + mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); + disconnect_sent = true; + } +} + +void my_log_callback(struct mosquitto *mosq, void *obj, int level, const char *str) +{ + printf("%s\n", str); +} + +int load_stdin(void) +{ + long pos = 0, rlen; + char buf[1024]; + char *aux_message = NULL; + + cfg.pub_mode = MSGMODE_STDIN_FILE; + + while(!feof(stdin)){ + rlen = fread(buf, 1, 1024, stdin); + aux_message = realloc(cfg.message, pos+rlen); + if(!aux_message){ + if(!cfg.quiet) fprintf(stderr, "Error: Out of memory.\n"); + free(cfg.message); + return 1; + } else + { + cfg.message = aux_message; + } + memcpy(&(cfg.message[pos]), buf, rlen); + pos += rlen; + } + cfg.msglen = pos; + + if(!cfg.msglen){ + if(!cfg.quiet) fprintf(stderr, "Error: Zero length input.\n"); + return 1; + } + + return 0; +} + +int load_file(const char *filename) +{ + long pos, rlen; + FILE *fptr = NULL; + + fptr = fopen(filename, "rb"); + if(!fptr){ + if(!cfg.quiet) fprintf(stderr, "Error: Unable to open file \"%s\".\n", filename); + return 1; + } + cfg.pub_mode = MSGMODE_FILE; + fseek(fptr, 0, SEEK_END); + cfg.msglen = ftell(fptr); + if(cfg.msglen > 268435455){ + fclose(fptr); + if(!cfg.quiet) fprintf(stderr, "Error: File \"%s\" is too large (>268,435,455 bytes).\n", filename); + return 1; + }else if(cfg.msglen == 0){ + fclose(fptr); + if(!cfg.quiet) fprintf(stderr, "Error: File \"%s\" is empty.\n", filename); + return 1; + }else if(cfg.msglen < 0){ + fclose(fptr); + if(!cfg.quiet) fprintf(stderr, "Error: Unable to determine size of file \"%s\".\n", filename); + return 1; + } + fseek(fptr, 0, SEEK_SET); + cfg.message = malloc(cfg.msglen); + if(!cfg.message){ + fclose(fptr); + if(!cfg.quiet) fprintf(stderr, "Error: Out of memory.\n"); + return 1; + } + pos = 0; + while(pos < cfg.msglen){ + rlen = fread(&(cfg.message[pos]), sizeof(char), cfg.msglen-pos, fptr); + pos += rlen; + } + fclose(fptr); + return 0; +} + + +int pub_shared_init(void) +{ + buf = malloc(buf_len); + if(!buf){ + fprintf(stderr, "Error: Out of memory.\n"); + return 1; + } + return 0; +} + + +int pub_shared_loop(struct mosquitto *mosq) +{ + int read_len; + int pos; + int rc, rc2; + char *buf2; + int buf_len_actual; + + if(cfg.pub_mode == MSGMODE_STDIN_LINE){ + mosquitto_loop_start(mosq); + } + + do{ + if(cfg.pub_mode == MSGMODE_STDIN_LINE){ + if(status == STATUS_CONNACK_RECVD){ + pos = 0; + read_len = buf_len; + while(fgets(&buf[pos], read_len, stdin)){ + buf_len_actual = strlen(buf); + if(buf[buf_len_actual-1] == '\n'){ + buf[buf_len_actual-1] = '\0'; + rc2 = my_publish(mosq, &mid_sent, cfg.topic, buf_len_actual-1, buf, cfg.qos, cfg.retain); + if(rc2){ + if(!cfg.quiet) fprintf(stderr, "Error: Publish returned %d, disconnecting.\n", rc2); + mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); + } + break; + }else{ + buf_len += 1024; + pos += 1023; + read_len = 1024; + buf2 = realloc(buf, buf_len); + if(!buf2){ + fprintf(stderr, "Error: Out of memory.\n"); + return MOSQ_ERR_NOMEM; + } + buf = buf2; + } + } + if(feof(stdin)){ + if(last_mid == -1){ + /* Empty file */ + mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); + disconnect_sent = true; + status = STATUS_DISCONNECTING; + }else{ + last_mid = mid_sent; + status = STATUS_WAITING; + } + } + }else if(status == STATUS_WAITING){ + if(last_mid_sent == last_mid && disconnect_sent == false){ + mosquitto_disconnect_with_properties(mosq, 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 = MOSQ_ERR_SUCCESS; + }else{ + rc = mosquitto_loop(mosq, -1, 1); + } + }while(rc == MOSQ_ERR_SUCCESS && connected); + + if(cfg.pub_mode == MSGMODE_STDIN_LINE){ + mosquitto_loop_stop(mosq, false); + } + return 0; +} + + +void pub_shared_cleanup(void) +{ + free(buf); +} diff --git a/client/pub_shared.h b/client/pub_shared.h new file mode 100644 index 0000000000..f91a55fc4d --- /dev/null +++ b/client/pub_shared.h @@ -0,0 +1,41 @@ +/* +Copyright (c) 2009-2018 Roger Light + +All rights reserved. This program and the accompanying materials +are made available under the terms of the Eclipse Public License v1.0 +and Eclipse Distribution License v1.0 which accompany this distribution. + +The Eclipse Public License is available at + http://www.eclipse.org/legal/epl-v10.html +and the Eclipse Distribution License is available at + http://www.eclipse.org/org/documents/edl-v10.php. + +Contributors: + Roger Light - initial implementation and documentation. +*/ +#ifndef PUB_SHARED_H +#define PUB_SHARED_H + +#define STATUS_CONNECTING 0 +#define STATUS_CONNACK_RECVD 1 +#define STATUS_WAITING 2 +#define STATUS_DISCONNECTING 3 + +extern int mid_sent; +extern int status; + + +void my_connect_callback(struct mosquitto *mosq, void *obj, int result); +void my_disconnect_callback(struct mosquitto *mosq, void *obj, int rc); +void my_publish_callback(struct mosquitto *mosq, void *obj, int mid); +void my_log_callback(struct mosquitto *mosq, void *obj, int level, const char *str); +int load_stdin(void); +int load_file(const char *filename); + +int my_publish(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, void *payload, int qos, bool retain); + +int pub_shared_init(void); +int pub_shared_loop(struct mosquitto *mosq); +void pub_shared_cleanup(void); + +#endif From d64ce2e242852675590c9cf1349676d906cad682 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 22 Nov 2018 10:17:16 +0000 Subject: [PATCH 095/254] Make mosquitto_reason_string public. --- lib/linker.version | 1 + lib/mosquitto.h | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/lib/linker.version b/lib/linker.version index 06f6e40aac..5d7c943bda 100644 --- a/lib/linker.version +++ b/lib/linker.version @@ -119,6 +119,7 @@ MOSQ_1.6 { mosquitto_property_check_all; mosquitto_publish_v5_callback_set; mosquitto_publish_with_properties; + mosquitto_reason_string; mosquitto_string_to_command; mosquitto_string_to_property_info; mosquitto_subscribe_multiple; diff --git a/lib/mosquitto.h b/lib/mosquitto.h index ec392a0411..13af7e7afe 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -1906,6 +1906,19 @@ libmosq_EXPORT const char *mosquitto_strerror(int mosq_errno); */ libmosq_EXPORT const char *mosquitto_connack_string(int connack_code); +/* + * Function: mosquitto_reason_string + * + * Call to obtain a const string description of an MQTT reason code. + * + * Parameters: + * reason_code - an MQTT reason code. + * + * Returns: + * A constant string describing the reason. + */ +libmosq_EXPORT const char *mosquitto_reason_string(int reason_code); + /* Function: mosquitto_string_to_command * * Take a string input representing an MQTT command and convert it to the From 85d9cfa2fab75ac0a8549c65f5a2cd5c26701e8e Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 22 Nov 2018 14:43:35 +0000 Subject: [PATCH 096/254] Fix pub client stdin mode. --- client/pub_client.c | 1 - client/pub_shared.c | 14 +++++++++----- client/pub_shared.h | 1 + 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/client/pub_client.c b/client/pub_client.c index 3f95b74268..722308b674 100644 --- a/client/pub_client.c +++ b/client/pub_client.c @@ -35,7 +35,6 @@ and the Eclipse Distribution License is available at /* Global variables for use in callbacks. See sub_client.c for an example of * using a struct to hold variables for use in callbacks. */ -static struct mosq_config cfg; static bool first_publish = true; int my_publish(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, void *payload, int qos, bool retain) diff --git a/client/pub_shared.c b/client/pub_shared.c index 26fcab91d9..08f941bba0 100644 --- a/client/pub_shared.c +++ b/client/pub_shared.c @@ -37,12 +37,13 @@ and the Eclipse Distribution License is available at * using a struct to hold variables for use in callbacks. */ int mid_sent = 0; int status = STATUS_CONNECTING; +struct mosq_config cfg; + static int last_mid = -1; static int last_mid_sent = -1; static bool connected = true; static bool disconnect_sent = false; -static struct mosq_config cfg; -static char *buf; +static char *buf = NULL; static int buf_len = 1024; void my_disconnect_callback(struct mosquitto *mosq, void *obj, int rc) @@ -162,13 +163,16 @@ int pub_shared_loop(struct mosquitto *mosq) int rc, rc2; char *buf2; int buf_len_actual; + int mode; - if(cfg.pub_mode == MSGMODE_STDIN_LINE){ + mode = cfg.pub_mode; + + if(mode == MSGMODE_STDIN_LINE){ mosquitto_loop_start(mosq); } do{ - if(cfg.pub_mode == MSGMODE_STDIN_LINE){ + if(mode == MSGMODE_STDIN_LINE){ if(status == STATUS_CONNACK_RECVD){ pos = 0; read_len = buf_len; @@ -225,7 +229,7 @@ int pub_shared_loop(struct mosquitto *mosq) } }while(rc == MOSQ_ERR_SUCCESS && connected); - if(cfg.pub_mode == MSGMODE_STDIN_LINE){ + if(mode == MSGMODE_STDIN_LINE){ mosquitto_loop_stop(mosq, false); } return 0; diff --git a/client/pub_shared.h b/client/pub_shared.h index f91a55fc4d..64c02d2b7b 100644 --- a/client/pub_shared.h +++ b/client/pub_shared.h @@ -23,6 +23,7 @@ and the Eclipse Distribution License is available at extern int mid_sent; extern int status; +extern struct mosq_config cfg; void my_connect_callback(struct mosquitto *mosq, void *obj, int result); From 14c2f528cf4064353dd0efff967d6ba4cc302636 Mon Sep 17 00:00:00 2001 From: Roger Light Date: Thu, 22 Nov 2018 16:52:39 +0000 Subject: [PATCH 097/254] Add reason code to send__disconnect(). --- lib/connect.c | 2 +- lib/send_disconnect.c | 4 ++-- lib/send_mosq.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/connect.c b/lib/connect.c index f0f369148d..69e9821686 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -230,6 +230,6 @@ int mosquitto_disconnect_with_properties(struct mosquitto *mosq, const mosquitto pthread_mutex_unlock(&mosq->state_mutex); if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; - return send__disconnect(mosq, properties); + return send__disconnect(mosq, reason_code, properties); } diff --git a/lib/send_disconnect.c b/lib/send_disconnect.c index d29a153e69..120ef82fe4 100644 --- a/lib/send_disconnect.c +++ b/lib/send_disconnect.c @@ -32,7 +32,7 @@ and the Eclipse Distribution License is available at #include "send_mosq.h" -int send__disconnect(struct mosquitto *mosq, const mosquitto_property *properties) +int send__disconnect(struct mosquitto *mosq, uint8_t reason_code, const mosquitto_property *properties) { struct mosquitto__packet *packet = NULL; int rc; @@ -66,7 +66,7 @@ int send__disconnect(struct mosquitto *mosq, const mosquitto_property *propertie return rc; } if(mosq->protocol == mosq_p_mqtt5){ - packet__write_byte(packet, 0); + packet__write_byte(packet, reason_code); property__write_all(packet, properties); } diff --git a/lib/send_mosq.h b/lib/send_mosq.h index fdf3b7ea9c..c26615bed8 100644 --- a/lib/send_mosq.h +++ b/lib/send_mosq.h @@ -24,7 +24,7 @@ int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const mosquitto_property *properties); int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session, const mosquitto_property *properties); -int send__disconnect(struct mosquitto *mosq, const mosquitto_property *properties); +int send__disconnect(struct mosquitto *mosq, uint8_t reason_code, const mosquitto_property *properties); int send__pingreq(struct mosquitto *mosq); int send__pingresp(struct mosquitto *mosq); int send__puback(struct mosquitto *mosq, uint16_t mid); From 3cb8a52ef3da567a001e9227ed04d68b1b64b093 Mon Sep 17 00:00:00 2001 From: Roger Light Date: Thu, 22 Nov 2018 16:56:17 +0000 Subject: [PATCH 098/254] Add reason code to mosquitto_disconnect_with_properties() --- client/pub_client.c | 2 +- client/pub_shared.c | 11 ++++++----- client/sub_client.c | 11 ++++++----- lib/connect.c | 4 ++-- lib/mosquitto.h | 3 ++- 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/client/pub_client.c b/client/pub_client.c index 722308b674..7211b4f0af 100644 --- a/client/pub_client.c +++ b/client/pub_client.c @@ -86,7 +86,7 @@ void my_connect_callback(struct mosquitto *mosq, void *obj, int result) break; } } - mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); + mosquitto_disconnect_with_properties(mosq, 0, cfg.disconnect_props); } }else{ if(result && !cfg.quiet){ diff --git a/client/pub_shared.c b/client/pub_shared.c index 08f941bba0..83a1ffee30 100644 --- a/client/pub_shared.c +++ b/client/pub_shared.c @@ -30,6 +30,7 @@ and the Eclipse Distribution License is available at #endif #include +#include #include "client_shared.h" #include "pub_shared.h" @@ -56,11 +57,11 @@ void my_publish_callback(struct mosquitto *mosq, void *obj, int mid) last_mid_sent = mid; if(cfg.pub_mode == MSGMODE_STDIN_LINE){ if(mid == last_mid){ - mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); + mosquitto_disconnect_with_properties(mosq, 0, cfg.disconnect_props); disconnect_sent = true; } }else if(disconnect_sent == false){ - mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); + mosquitto_disconnect_with_properties(mosq, 0, cfg.disconnect_props); disconnect_sent = true; } } @@ -183,7 +184,7 @@ int pub_shared_loop(struct mosquitto *mosq) rc2 = my_publish(mosq, &mid_sent, cfg.topic, buf_len_actual-1, buf, cfg.qos, cfg.retain); if(rc2){ if(!cfg.quiet) fprintf(stderr, "Error: Publish returned %d, disconnecting.\n", rc2); - mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); + mosquitto_disconnect_with_properties(mosq, MQTT_RC_DISCONNECT_WITH_WILL_MSG, cfg.disconnect_props); } break; }else{ @@ -201,7 +202,7 @@ int pub_shared_loop(struct mosquitto *mosq) if(feof(stdin)){ if(last_mid == -1){ /* Empty file */ - mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); + mosquitto_disconnect_with_properties(mosq, 0, cfg.disconnect_props); disconnect_sent = true; status = STATUS_DISCONNECTING; }else{ @@ -211,7 +212,7 @@ int pub_shared_loop(struct mosquitto *mosq) } }else if(status == STATUS_WAITING){ if(last_mid_sent == last_mid && disconnect_sent == false){ - mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); + mosquitto_disconnect_with_properties(mosq, 0, cfg.disconnect_props); disconnect_sent = true; } #ifdef WIN32 diff --git a/client/sub_client.c b/client/sub_client.c index 8a9cf3a9a2..473c58c314 100644 --- a/client/sub_client.c +++ b/client/sub_client.c @@ -32,6 +32,7 @@ and the Eclipse Distribution License is available at #endif #include +#include #include "client_shared.h" static struct mosq_config cfg; @@ -44,7 +45,7 @@ void my_signal_handler(int signum) { if(signum == SIGALRM){ process_messages = false; - mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); + mosquitto_disconnect_with_properties(mosq, MQTT_RC_DISCONNECT_WITH_WILL_MSG, cfg.disconnect_props); } } #endif @@ -61,7 +62,7 @@ void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquit if(cfg.retained_only && !message->retain && process_messages){ process_messages = false; - mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); + mosquitto_disconnect_with_properties(mosq, 0, cfg.disconnect_props); return; } @@ -79,7 +80,7 @@ void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquit msg_count++; if(cfg.msg_count == msg_count){ process_messages = false; - mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); + mosquitto_disconnect_with_properties(mosq, 0, cfg.disconnect_props); } } } @@ -98,7 +99,7 @@ void my_connect_callback(struct mosquitto *mosq, void *obj, int result, int flag if(result && !cfg.quiet){ fprintf(stderr, "%s\n", mosquitto_connack_string(result)); } - mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); + mosquitto_disconnect_with_properties(mosq, 0, cfg.disconnect_props); } } @@ -113,7 +114,7 @@ void my_subscribe_callback(struct mosquitto *mosq, void *obj, int mid, int qos_c if(!cfg.quiet) printf("\n"); if(cfg.exit_after_sub){ - mosquitto_disconnect_with_properties(mosq, cfg.disconnect_props); + mosquitto_disconnect_with_properties(mosq, 0, cfg.disconnect_props); } } diff --git a/lib/connect.c b/lib/connect.c index 69e9821686..016bc73d46 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -212,10 +212,10 @@ static int mosquitto__reconnect(struct mosquitto *mosq, bool blocking, const mos int mosquitto_disconnect(struct mosquitto *mosq) { - return mosquitto_disconnect_with_properties(mosq, NULL); + return mosquitto_disconnect_with_properties(mosq, 0, NULL); } -int mosquitto_disconnect_with_properties(struct mosquitto *mosq, const mosquitto_property *properties) +int mosquitto_disconnect_with_properties(struct mosquitto *mosq, int reason_code, const mosquitto_property *properties) { int rc; if(!mosq) return MOSQ_ERR_INVAL; diff --git a/lib/mosquitto.h b/lib/mosquitto.h index 13af7e7afe..7ffbc16cd2 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -685,6 +685,7 @@ libmosq_EXPORT int mosquitto_disconnect(struct mosquitto *mosq); * * Parameters: * mosq - a valid mosquitto instance. + * reason_code - the disconnect reason code. * properties - a valid mosquitto_property list, or NULL. * * Returns: @@ -694,7 +695,7 @@ libmosq_EXPORT int mosquitto_disconnect(struct mosquitto *mosq); * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. * MOSQ_ERR_PROTOCOL - if any property is invalid for use with DISCONNECT. */ -libmosq_EXPORT int mosquitto_disconnect_with_properties(struct mosquitto *mosq, const mosquitto_property *properties); +libmosq_EXPORT int mosquitto_disconnect_with_properties(struct mosquitto *mosq, int reason_code, const mosquitto_property *properties); /* ====================================================================== From f7dc097f8231e9e6e72f1c0f8e1cfc6c454c5031 Mon Sep 17 00:00:00 2001 From: Roger Light Date: Thu, 22 Nov 2018 17:31:17 +0000 Subject: [PATCH 099/254] Move client disconnect code to own function. --- lib/connect.c | 39 +++++++++++++++++++++++++++++++++++++++ lib/mosquitto_internal.h | 2 ++ lib/packet_mosq.c | 37 +------------------------------------ 3 files changed, 42 insertions(+), 36 deletions(-) diff --git a/lib/connect.c b/lib/connect.c index 016bc73d46..6035f58243 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -233,3 +233,42 @@ int mosquitto_disconnect_with_properties(struct mosquitto *mosq, int reason_code return send__disconnect(mosq, reason_code, properties); } + +void do_client_disconnect(struct mosquitto *mosq, int reason_code) +{ + pthread_mutex_lock(&mosq->state_mutex); + mosq->state = mosq_cs_disconnecting; + pthread_mutex_unlock(&mosq->state_mutex); + + net__socket_close(mosq); + + /* Free data and reset values */ + pthread_mutex_lock(&mosq->out_packet_mutex); + mosq->current_out_packet = mosq->out_packet; + if(mosq->out_packet){ + mosq->out_packet = mosq->out_packet->next; + if(!mosq->out_packet){ + mosq->out_packet_last = NULL; + } + } + pthread_mutex_unlock(&mosq->out_packet_mutex); + + pthread_mutex_lock(&mosq->msgtime_mutex); + mosq->next_msg_out = mosquitto_time() + mosq->keepalive; + pthread_mutex_unlock(&mosq->msgtime_mutex); + + pthread_mutex_lock(&mosq->callback_mutex); + if(mosq->on_disconnect){ + mosq->in_callback = true; + mosq->on_disconnect(mosq, mosq->userdata, reason_code); + mosq->in_callback = false; + } + if(mosq->on_disconnect_v5){ + mosq->in_callback = true; + mosq->on_disconnect_v5(mosq, mosq->userdata, reason_code, NULL); + mosq->in_callback = false; + } + pthread_mutex_unlock(&mosq->callback_mutex); + pthread_mutex_unlock(&mosq->current_out_packet_mutex); +} + diff --git a/lib/mosquitto_internal.h b/lib/mosquitto_internal.h index acc1d21ecd..f1a64e2d3e 100644 --- a/lib/mosquitto_internal.h +++ b/lib/mosquitto_internal.h @@ -296,5 +296,7 @@ struct mosquitto { #define STREMPTY(str) (str[0] == '\0') +void do_client_disconnect(struct mosquitto *mosq, int reason_code); + #endif diff --git a/lib/packet_mosq.c b/lib/packet_mosq.c index ce61cb5026..c7a332f04c 100644 --- a/lib/packet_mosq.c +++ b/lib/packet_mosq.c @@ -225,44 +225,9 @@ int packet__write(struct mosquitto *mosq) } pthread_mutex_unlock(&mosq->callback_mutex); }else if(((packet->command)&0xF0) == CMD_DISCONNECT){ - /* FIXME what cleanup needs doing here? - * incoming/outgoing messages? */ - net__socket_close(mosq); - - /* Start of duplicate, possibly unnecessary code. - * This does leave things in a consistent state at least. */ - /* Free data and reset values */ - pthread_mutex_lock(&mosq->out_packet_mutex); - mosq->current_out_packet = mosq->out_packet; - if(mosq->out_packet){ - mosq->out_packet = mosq->out_packet->next; - if(!mosq->out_packet){ - mosq->out_packet_last = NULL; - } - } - pthread_mutex_unlock(&mosq->out_packet_mutex); - + do_client_disconnect(mosq, MOSQ_ERR_SUCCESS); packet__cleanup(packet); mosquitto__free(packet); - - pthread_mutex_lock(&mosq->msgtime_mutex); - mosq->next_msg_out = mosquitto_time() + mosq->keepalive; - pthread_mutex_unlock(&mosq->msgtime_mutex); - /* End of duplicate, possibly unnecessary code */ - - pthread_mutex_lock(&mosq->callback_mutex); - if(mosq->on_disconnect){ - mosq->in_callback = true; - mosq->on_disconnect(mosq, mosq->userdata, MOSQ_ERR_SUCCESS); - mosq->in_callback = false; - } - if(mosq->on_disconnect_v5){ - mosq->in_callback = true; - mosq->on_disconnect_v5(mosq, mosq->userdata, MOSQ_ERR_SUCCESS, NULL); - mosq->in_callback = false; - } - pthread_mutex_unlock(&mosq->callback_mutex); - pthread_mutex_unlock(&mosq->current_out_packet_mutex); return MOSQ_ERR_SUCCESS; #endif } From 6ca746695fc7c5ebee73fce04b727cd7fcf0f27e Mon Sep 17 00:00:00 2001 From: Roger Light Date: Thu, 22 Nov 2018 17:32:43 +0000 Subject: [PATCH 100/254] Pass db to send__connack() to give it access to config. --- src/handle_connect.c | 34 ++++++++++++++++----------------- src/mosquitto_broker_internal.h | 2 +- src/send_connack.c | 9 +++++---- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/handle_connect.c b/src/handle_connect.c index a6f1ae78b1..a109187e80 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -179,7 +179,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) log__printf(NULL, MOSQ_LOG_INFO, "Invalid protocol version %d in CONNECT from %s.", protocol_version, context->address); } - send__connack(context, 0, CONNACK_REFUSED_PROTOCOL_VERSION); + send__connack(db, context, 0, CONNACK_REFUSED_PROTOCOL_VERSION); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } @@ -194,7 +194,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) log__printf(NULL, MOSQ_LOG_INFO, "Invalid protocol version %d in CONNECT from %s.", protocol_version, context->address); } - send__connack(context, 0, CONNACK_REFUSED_PROTOCOL_VERSION); + send__connack(db, context, 0, CONNACK_REFUSED_PROTOCOL_VERSION); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } @@ -255,7 +255,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) if(slen == 0){ if(context->protocol == mosq_p_mqtt31){ - send__connack(context, 0, CONNACK_REFUSED_IDENTIFIER_REJECTED); + send__connack(db, context, 0, CONNACK_REFUSED_IDENTIFIER_REJECTED); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; }else{ /* mqtt311/mqtt5 */ @@ -269,7 +269,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) allow_zero_length_clientid = db->config->security_options.allow_zero_length_clientid; } if(clean_session == 0 || allow_zero_length_clientid == false){ - send__connack(context, 0, CONNACK_REFUSED_IDENTIFIER_REJECTED); + send__connack(db, context, 0, CONNACK_REFUSED_IDENTIFIER_REJECTED); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; }else{ @@ -289,7 +289,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) /* clientid_prefixes check */ if(db->config->clientid_prefixes){ if(strncmp(db->config->clientid_prefixes, client_id, strlen(db->config->clientid_prefixes))){ - send__connack(context, 0, CONNACK_REFUSED_NOT_AUTHORIZED); + send__connack(db, context, 0, CONNACK_REFUSED_NOT_AUTHORIZED); rc = 1; goto handle_connect_error; } @@ -415,7 +415,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) password = NULL; if(!context->ssl){ - send__connack(context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); + send__connack(db, context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); rc = 1; goto handle_connect_error; } @@ -423,7 +423,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) if(context->listener->psk_hint){ /* Client should have provided an identity to get this far. */ if(!context->username){ - send__connack(context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); + send__connack(db, context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); rc = 1; goto handle_connect_error; } @@ -431,20 +431,20 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) #endif /* WITH_TLS_PSK */ client_cert = SSL_get_peer_certificate(context->ssl); if(!client_cert){ - send__connack(context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); + send__connack(db, context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); rc = 1; goto handle_connect_error; } name = X509_get_subject_name(client_cert); if(!name){ - send__connack(context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); + send__connack(db, context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); rc = 1; goto handle_connect_error; } if (context->listener->use_identity_as_username) { //use_identity_as_username i = X509_NAME_get_index_by_NID(name, NID_commonName, -1); if(i == -1){ - send__connack(context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); + send__connack(db, context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); rc = 1; goto handle_connect_error; } @@ -452,19 +452,19 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) if(name_entry){ name_asn1 = X509_NAME_ENTRY_get_data(name_entry); if (name_asn1 == NULL) { - send__connack(context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); + send__connack(db, context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); rc = 1; goto handle_connect_error; } context->username = mosquitto__strdup((char *) ASN1_STRING_data(name_asn1)); if(!context->username){ - send__connack(context, 0, CONNACK_REFUSED_SERVER_UNAVAILABLE); + send__connack(db, context, 0, CONNACK_REFUSED_SERVER_UNAVAILABLE); rc = MOSQ_ERR_NOMEM; goto handle_connect_error; } /* Make sure there isn't an embedded NUL character in the CN */ if ((size_t)ASN1_STRING_length(name_asn1) != strlen(context->username)) { - send__connack(context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); + send__connack(db, context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); rc = 1; goto handle_connect_error; } @@ -508,7 +508,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) case MOSQ_ERR_SUCCESS: break; case MOSQ_ERR_AUTH: - send__connack(context, 0, CONNACK_REFUSED_NOT_AUTHORIZED); + send__connack(db, context, 0, CONNACK_REFUSED_NOT_AUTHORIZED); context__disconnect(db, context); rc = 1; goto handle_connect_error; @@ -529,7 +529,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) if((db->config->per_listener_settings && context->listener->security_options.allow_anonymous == false) || (!db->config->per_listener_settings && db->config->security_options.allow_anonymous == false)){ - send__connack(context, 0, CONNACK_REFUSED_NOT_AUTHORIZED); + send__connack(db, context, 0, CONNACK_REFUSED_NOT_AUTHORIZED); rc = 1; goto handle_connect_error; } @@ -547,7 +547,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) goto handle_connect_error; } }else{ - send__connack(context, 0, CONNACK_REFUSED_NOT_AUTHORIZED); + send__connack(db, context, 0, CONNACK_REFUSED_NOT_AUTHORIZED); rc = 1; goto handle_connect_error; } @@ -700,7 +700,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) } #endif context->state = mosq_cs_connected; - return send__connack(context, connect_ack, CONNACK_ACCEPTED); + return send__connack(db, context, connect_ack, CONNACK_ACCEPTED); handle_connect_error: mosquitto__free(client_id); diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index 06f3d2f631..7351e0d875 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -511,7 +511,7 @@ int restore_privileges(void); /* ============================================================ * Server send functions * ============================================================ */ -int send__connack(struct mosquitto *context, int ack, int result); +int send__connack(struct mosquitto_db *db, struct mosquitto *context, int ack, int reason_code); int send__suback(struct mosquitto *context, uint16_t mid, uint32_t payloadlen, const void *payload); int send__unsuback(struct mosquitto *context, uint16_t mid, const mosquitto_property *properties); diff --git a/src/send_connack.c b/src/send_connack.c index ac39b63645..c674548eed 100644 --- a/src/send_connack.c +++ b/src/send_connack.c @@ -23,7 +23,7 @@ and the Eclipse Distribution License is available at #include "property_mosq.h" #include "util_mosq.h" -int send__connack(struct mosquitto *context, int ack, int result) +int send__connack(struct mosquitto_db *db, struct mosquitto *context, int ack, int reason_code) { struct mosquitto__packet *packet = NULL; int rc; @@ -32,9 +32,9 @@ int send__connack(struct mosquitto *context, int ack, int result) if(context){ if(context->id){ - log__printf(NULL, MOSQ_LOG_DEBUG, "Sending CONNACK to %s (%d, %d)", context->id, ack, result); + log__printf(NULL, MOSQ_LOG_DEBUG, "Sending CONNACK to %s (%d, %d)", context->id, ack, reason_code); }else{ - log__printf(NULL, MOSQ_LOG_DEBUG, "Sending CONNACK to %s (%d, %d)", context->address, ack, result); + log__printf(NULL, MOSQ_LOG_DEBUG, "Sending CONNACK to %s (%d, %d)", context->address, ack, reason_code); } } @@ -54,10 +54,11 @@ int send__connack(struct mosquitto *context, int ack, int result) return rc; } packet__write_byte(packet, ack); - packet__write_byte(packet, result); + packet__write_byte(packet, reason_code); if(context->protocol == mosq_p_mqtt5){ property__write_all(packet, properties); } + mosquitto_property_free_all(&properties); return packet__queue(context, packet); } From 47129e395ed4ea5f45734a430f06812010cd7f27 Mon Sep 17 00:00:00 2001 From: Roger Light Date: Thu, 22 Nov 2018 17:34:42 +0000 Subject: [PATCH 101/254] Use v5 callback in pub client. --- client/pub_client.c | 2 +- client/pub_shared.c | 2 +- client/pub_shared.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/pub_client.c b/client/pub_client.c index 7211b4f0af..bc44af4162 100644 --- a/client/pub_client.c +++ b/client/pub_client.c @@ -259,7 +259,7 @@ int main(int argc, char *argv[]) mosquitto_log_callback_set(mosq, my_log_callback); } mosquitto_connect_callback_set(mosq, my_connect_callback); - mosquitto_disconnect_callback_set(mosq, my_disconnect_callback); + mosquitto_disconnect_v5_callback_set(mosq, my_disconnect_callback); mosquitto_publish_callback_set(mosq, my_publish_callback); if(client_opts_set(mosq, &cfg)){ diff --git a/client/pub_shared.c b/client/pub_shared.c index 83a1ffee30..98b54942e0 100644 --- a/client/pub_shared.c +++ b/client/pub_shared.c @@ -47,7 +47,7 @@ static bool disconnect_sent = false; static char *buf = NULL; static int buf_len = 1024; -void my_disconnect_callback(struct mosquitto *mosq, void *obj, int rc) +void my_disconnect_callback(struct mosquitto *mosq, void *obj, int rc, const mosquitto_property *properties) { connected = false; } diff --git a/client/pub_shared.h b/client/pub_shared.h index 64c02d2b7b..feaa22ebb8 100644 --- a/client/pub_shared.h +++ b/client/pub_shared.h @@ -27,7 +27,7 @@ extern struct mosq_config cfg; void my_connect_callback(struct mosquitto *mosq, void *obj, int result); -void my_disconnect_callback(struct mosquitto *mosq, void *obj, int rc); +void my_disconnect_callback(struct mosquitto *mosq, void *obj, int rc, const mosquitto_property *properties); void my_publish_callback(struct mosquitto *mosq, void *obj, int mid); void my_log_callback(struct mosquitto *mosq, void *obj, int level, const char *str); int load_stdin(void); From 236e96716153ad963b56e0d1ae86fac71dbdf087 Mon Sep 17 00:00:00 2001 From: Roger Light Date: Thu, 22 Nov 2018 18:07:52 +0000 Subject: [PATCH 102/254] Pass properties when disconnecting clients. --- lib/CMakeLists.txt | 1 + lib/connect.c | 4 ++-- lib/mosquitto_internal.h | 2 +- lib/packet_mosq.c | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index dbbf2ca636..da5164800a 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -37,6 +37,7 @@ set(C_SRC connect.c handle_auth.c handle_connack.c + handle_disconnect.c handle_ping.c handle_pubackcomp.c handle_publish.c diff --git a/lib/connect.c b/lib/connect.c index 6035f58243..2bb1f6f9f6 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -234,7 +234,7 @@ int mosquitto_disconnect_with_properties(struct mosquitto *mosq, int reason_code } -void do_client_disconnect(struct mosquitto *mosq, int reason_code) +void do_client_disconnect(struct mosquitto *mosq, int reason_code, const mosquitto_property *properties) { pthread_mutex_lock(&mosq->state_mutex); mosq->state = mosq_cs_disconnecting; @@ -265,7 +265,7 @@ void do_client_disconnect(struct mosquitto *mosq, int reason_code) } if(mosq->on_disconnect_v5){ mosq->in_callback = true; - mosq->on_disconnect_v5(mosq, mosq->userdata, reason_code, NULL); + mosq->on_disconnect_v5(mosq, mosq->userdata, reason_code, properties); mosq->in_callback = false; } pthread_mutex_unlock(&mosq->callback_mutex); diff --git a/lib/mosquitto_internal.h b/lib/mosquitto_internal.h index f1a64e2d3e..fe0a6e24fa 100644 --- a/lib/mosquitto_internal.h +++ b/lib/mosquitto_internal.h @@ -296,7 +296,7 @@ struct mosquitto { #define STREMPTY(str) (str[0] == '\0') -void do_client_disconnect(struct mosquitto *mosq, int reason_code); +void do_client_disconnect(struct mosquitto *mosq, int reason_code, const mosquitto_property *properties); #endif diff --git a/lib/packet_mosq.c b/lib/packet_mosq.c index c7a332f04c..b22fdc8aed 100644 --- a/lib/packet_mosq.c +++ b/lib/packet_mosq.c @@ -225,7 +225,7 @@ int packet__write(struct mosquitto *mosq) } pthread_mutex_unlock(&mosq->callback_mutex); }else if(((packet->command)&0xF0) == CMD_DISCONNECT){ - do_client_disconnect(mosq, MOSQ_ERR_SUCCESS); + do_client_disconnect(mosq, MOSQ_ERR_SUCCESS, NULL); packet__cleanup(packet); mosquitto__free(packet); return MOSQ_ERR_SUCCESS; From f809ecbcbebb5e92c88a5cfd5728c90de58c4b02 Mon Sep 17 00:00:00 2001 From: Roger Light Date: Thu, 22 Nov 2018 18:13:18 +0000 Subject: [PATCH 103/254] Add DISCONNECT handling to library. --- lib/Makefile | 4 +++ lib/handle_disconnect.c | 58 +++++++++++++++++++++++++++++++++++++++++ lib/read_handle.c | 2 ++ lib/read_handle.h | 1 + 4 files changed, 65 insertions(+) create mode 100644 lib/handle_disconnect.c diff --git a/lib/Makefile b/lib/Makefile index 9dc330c4a4..8e310e6119 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -8,6 +8,7 @@ MOSQ_OBJS=mosquitto.o \ connect.o \ handle_auth.o \ handle_connack.o \ + handle_disconnect.o \ handle_ping.o \ handle_pubackcomp.o \ handle_publish.o \ @@ -101,6 +102,9 @@ handle_auth.o : handle_auth.c read_handle.h handle_connack.o : handle_connack.c read_handle.h ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ +handle_disconnect.o : handle_disconnect.c read_handle.h + ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ + handle_publish.o : handle_publish.c read_handle.h ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ diff --git a/lib/handle_disconnect.c b/lib/handle_disconnect.c new file mode 100644 index 0000000000..2f3bb58ac1 --- /dev/null +++ b/lib/handle_disconnect.c @@ -0,0 +1,58 @@ +/* +Copyright (c) 2009-2018 Roger Light + +All rights reserved. This program and the accompanying materials +are made available under the terms of the Eclipse Public License v1.0 +and Eclipse Distribution License v1.0 which accompany this distribution. + +The Eclipse Public License is available at + http://www.eclipse.org/legal/epl-v10.html +and the Eclipse Distribution License is available at + http://www.eclipse.org/org/documents/edl-v10.php. + +Contributors: + Roger Light - initial implementation and documentation. +*/ + +#include "config.h" + +#include +#include + +#include "logging_mosq.h" +#include "mqtt_protocol.h" +#include "memory_mosq.h" +#include "net_mosq.h" +#include "packet_mosq.h" +#include "property_mosq.h" +#include "send_mosq.h" +#include "util_mosq.h" + +int handle__disconnect(struct mosquitto *mosq) +{ + int rc; + uint8_t reason_code; + mosquitto_property *properties = NULL; + + if(!mosq){ + return MOSQ_ERR_INVAL; + } + + rc = packet__read_byte(&mosq->in_packet, &reason_code); + if(rc) return rc; + + if(mosq->protocol == mosq_p_mqtt5){ + rc = property__read_all(CMD_DISCONNECT, &mosq->in_packet, &properties); + if(rc) return rc; + mosquitto_property_free_all(&properties); + } + + log__printf(mosq, MOSQ_LOG_DEBUG, "Received DISCONNECT (%d)", reason_code); + + do_client_disconnect(mosq, reason_code, properties); + + mosquitto_property_free_all(&properties); + + return MOSQ_ERR_SUCCESS; +} + diff --git a/lib/read_handle.c b/lib/read_handle.c index 1da41aa79a..991a7dbcf4 100644 --- a/lib/read_handle.c +++ b/lib/read_handle.c @@ -57,6 +57,8 @@ int handle__packet(struct mosquitto *mosq) return handle__suback(mosq); case CMD_UNSUBACK: return handle__unsuback(mosq); + case CMD_DISCONNECT: + return handle__disconnect(mosq); case CMD_AUTH: return handle__auth(mosq); default: diff --git a/lib/read_handle.h b/lib/read_handle.h index 8bf20b5f11..e0e17c945b 100644 --- a/lib/read_handle.h +++ b/lib/read_handle.h @@ -26,6 +26,7 @@ int handle__pubackcomp(struct mosquitto_db *db, struct mosquitto *mosq, const ch #else int handle__packet(struct mosquitto *mosq); int handle__connack(struct mosquitto *mosq); +int handle__disconnect(struct mosquitto *mosq); int handle__pubackcomp(struct mosquitto *mosq, const char *type); int handle__publish(struct mosquitto *mosq); int handle__auth(struct mosquitto *mosq); From 36e8659762815eb0dfd9bc8ce6bf4099fa1d8948 Mon Sep 17 00:00:00 2001 From: Roger Light Date: Thu, 22 Nov 2018 18:14:12 +0000 Subject: [PATCH 104/254] Only keep reading from stdin if we are connected. --- client/pub_shared.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/pub_shared.c b/client/pub_shared.c index 98b54942e0..bcfc2b5343 100644 --- a/client/pub_shared.c +++ b/client/pub_shared.c @@ -177,7 +177,7 @@ int pub_shared_loop(struct mosquitto *mosq) if(status == STATUS_CONNACK_RECVD){ pos = 0; read_len = buf_len; - while(fgets(&buf[pos], read_len, stdin)){ + while(connected && fgets(&buf[pos], read_len, stdin)){ buf_len_actual = strlen(buf); if(buf[buf_len_actual-1] == '\n'){ buf[buf_len_actual-1] = '\0'; From 9560c5bac7ae2c4309f93a53d19a27675d29a06b Mon Sep 17 00:00:00 2001 From: Roger Light Date: Thu, 22 Nov 2018 18:15:02 +0000 Subject: [PATCH 105/254] Add retain_available support. --- man/mosquitto.conf.5.xml | 10 ++++++++++ mosquitto.conf | 6 ++++++ src/conf.c | 3 +++ src/database.c | 4 ++++ src/handle_connect.c | 8 ++++++++ src/handle_publish.c | 7 +++++++ src/mosquitto_broker_internal.h | 1 + src/send_connack.c | 7 +++++++ 8 files changed, 46 insertions(+) diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml index a6bf0c99a2..fa9d1e86b8 100644 --- a/man/mosquitto.conf.5.xml +++ b/man/mosquitto.conf.5.xml @@ -628,6 +628,16 @@ Reloaded on reload signal. + + [ true | false ] + + If set to false, then retained messages are not + supported. Clients that send a message with the retain + bit will be disconnected if this option is set to + false. Defaults to true. + Reloaded on reload signal. + + [ true | false ] diff --git a/mosquitto.conf b/mosquitto.conf index 96450050d9..fa332a24eb 100644 --- a/mosquitto.conf +++ b/mosquitto.conf @@ -149,6 +149,12 @@ #per_listener_settings false +# Set to false to disable retained message support. If a client publishes a +# message with the retain bit set, it will be disconnected if this is set to +# false. +#retain_available true + + # ================================================================= # Default listener # ================================================================= diff --git a/src/conf.c b/src/conf.c index 6b6f243407..20609e07bb 100644 --- a/src/conf.c +++ b/src/conf.c @@ -219,6 +219,7 @@ static void config__init_reload(struct mosquitto_db *db, struct mosquitto__confi config->persistence_file = NULL; config->persistent_client_expiration = 0; config->queue_qos0_messages = false; + config->retain_available = true; config->set_tcp_nodelay = false; config->sys_interval = 10; config->upgrade_outgoing_qos = false; @@ -1729,6 +1730,8 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct #else log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif + }else if(!strcmp(token, "retain_available")){ + if(conf__parse_bool(&token, token, &config->retain_available, saveptr)) return MOSQ_ERR_INVAL; }else if(!strcmp(token, "retry_interval")){ log__printf(NULL, MOSQ_LOG_WARNING, "Warning: The retry_interval option is no longer available."); }else if(!strcmp(token, "round_robin")){ diff --git a/src/database.c b/src/database.c index 3de5728936..eb5547f7b2 100644 --- a/src/database.c +++ b/src/database.c @@ -575,6 +575,10 @@ int db__messages_easy_queue(struct mosquitto_db *db, struct mosquitto *context, topic_heap = mosquitto__strdup(topic); if(!topic_heap) return MOSQ_ERR_INVAL; + if(db->config->retain_available == false){ + retain = 0; + } + if(UHPA_ALLOC(payload_uhpa, payloadlen) == 0){ mosquitto__free(topic_heap); return MOSQ_ERR_NOMEM; diff --git a/src/handle_connect.c b/src/handle_connect.c index a109187e80..0e87303bf6 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -236,6 +236,14 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) password_flag = connect_flags & 0x40; username_flag = connect_flags & 0x80; + if(will && will_retain && db->config->retain_available == false){ + if(protocol_version == mosq_p_mqtt5){ + send__connack(db, context, 0, MQTT_RC_RETAIN_NOT_SUPPORTED); + } + rc = 1; + goto handle_connect_error; + } + if(packet__read_uint16(&context->in_packet, &(context->keepalive))){ rc = 1; goto handle_connect_error; diff --git a/src/handle_publish.c b/src/handle_publish.c index 31b1df5b34..8cb1144996 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -68,6 +68,13 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) } retain = (header & 0x01); + if(retain && db->config->retain_available == false){ + if(context->protocol == mosq_p_mqtt5){ + send__disconnect(context, MQTT_RC_RETAIN_NOT_SUPPORTED, NULL); + } + return 1; + } + if(packet__read_string(&context->in_packet, &topic, &slen)) return 1; if(!slen){ /* Invalid publish topic, disconnect client. */ diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index 7351e0d875..694bd649d9 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -268,6 +268,7 @@ struct mosquitto__config { char *pid_file; bool queue_qos0_messages; bool per_listener_settings; + bool retain_available; bool set_tcp_nodelay; int sys_interval; bool upgrade_outgoing_qos; diff --git a/src/send_connack.c b/src/send_connack.c index c674548eed..629dca6431 100644 --- a/src/send_connack.c +++ b/src/send_connack.c @@ -44,6 +44,13 @@ int send__connack(struct mosquitto_db *db, struct mosquitto *context, int ack, i packet->command = CMD_CONNACK; packet->remaining_length = 2; if(context->protocol == mosq_p_mqtt5){ + if(reason_code < 128 && db->config->retain_available == false){ + rc = mosquitto_property_add_byte(&properties, MQTT_PROP_RETAIN_AVAILABLE, 0); + if(rc){ + mosquitto__free(packet); + return rc; + } + } proplen = property__get_length_all(properties); varbytes = packet__varint_bytes(proplen); packet->remaining_length += proplen + varbytes; From a9d19d09119cf09117ef7eb4a98397941f23760d Mon Sep 17 00:00:00 2001 From: Roger Light Date: Thu, 22 Nov 2018 18:22:31 +0000 Subject: [PATCH 106/254] Use MQTT 5 reason strings where appropriate in clients. --- client/pub_client.c | 6 +++++- client/sub_client.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/client/pub_client.c b/client/pub_client.c index bc44af4162..80609f8458 100644 --- a/client/pub_client.c +++ b/client/pub_client.c @@ -90,7 +90,11 @@ void my_connect_callback(struct mosquitto *mosq, void *obj, int result) } }else{ if(result && !cfg.quiet){ - fprintf(stderr, "%s\n", mosquitto_connack_string(result)); + if(cfg.protocol_version == MQTT_PROTOCOL_V5){ + fprintf(stderr, "%s\n", mosquitto_reason_string(result)); + }else{ + fprintf(stderr, "%s\n", mosquitto_connack_string(result)); + } } } } diff --git a/client/sub_client.c b/client/sub_client.c index 473c58c314..36ec4a0cfb 100644 --- a/client/sub_client.c +++ b/client/sub_client.c @@ -97,7 +97,11 @@ void my_connect_callback(struct mosquitto *mosq, void *obj, int result, int flag } }else{ if(result && !cfg.quiet){ - fprintf(stderr, "%s\n", mosquitto_connack_string(result)); + if(cfg.protocol_version == MQTT_PROTOCOL_V5){ + fprintf(stderr, "%s\n", mosquitto_reason_string(result)); + }else{ + fprintf(stderr, "%s\n", mosquitto_connack_string(result)); + } } mosquitto_disconnect_with_properties(mosq, 0, cfg.disconnect_props); } From 17d213b79a5340b5bd653a6c6bc8ab3714791ea2 Mon Sep 17 00:00:00 2001 From: Roger Light Date: Thu, 22 Nov 2018 18:25:16 +0000 Subject: [PATCH 107/254] Declare lack of support for shared subs and sub IDs. --- src/send_connack.c | 12 ++++++++++++ test/mosq_test.py | 8 +++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/send_connack.c b/src/send_connack.c index 629dca6431..0891af6056 100644 --- a/src/send_connack.c +++ b/src/send_connack.c @@ -51,6 +51,18 @@ int send__connack(struct mosquitto_db *db, struct mosquitto *context, int ack, i return rc; } } + /* FIXME - disable support until available */ + rc = mosquitto_property_add_byte(&properties, MQTT_PROP_SHARED_SUB_AVAILABLE, 0); + if(rc){ + mosquitto__free(packet); + return rc; + } + rc = mosquitto_property_add_byte(&properties, MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE, 0); + if(rc){ + mosquitto__free(packet); + return rc; + } + proplen = property__get_length_all(properties); varbytes = packet__varint_bytes(proplen); packet->remaining_length += proplen + varbytes; diff --git a/test/mosq_test.py b/test/mosq_test.py index 26fea5282d..a975d833f4 100644 --- a/test/mosq_test.py +++ b/test/mosq_test.py @@ -6,6 +6,8 @@ import sys import time +import mqtt5_props + def start_broker(filename, cmd=None, port=0, use_conf=False): delay = 0.1 @@ -359,7 +361,11 @@ def gen_connect(client_id, clean_session=True, keepalive=60, username=None, pass def gen_connack(resv=0, rc=0, proto_ver=4): if proto_ver == 5: - packet = struct.pack('!BBBBB', 32, 3, resv, rc, 0); + props = mqtt5_props.gen_byte_prop(mqtt5_props.PROP_SHARED_SUB_AVAILABLE, 0) + props += mqtt5_props.gen_byte_prop(mqtt5_props.PROP_SUBSCRIPTION_ID_AVAILABLE, 0) + props = mqtt5_props.prop_finalise(props) + + packet = struct.pack('!BBBB', 32, 2+len(props), resv, rc) + props else: packet = struct.pack('!BBBB', 32, 2, resv, rc); From 0123ff1efeb619938c2f88586e179335cfed6549 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 22 Nov 2018 18:55:04 +0000 Subject: [PATCH 108/254] Rename *_with_properties() -> *_v5(). --- client/client_shared.c | 6 ++--- client/pub_client.c | 6 ++--- client/pub_shared.c | 10 ++++---- client/sub_client.c | 12 +++++----- lib/actions.c | 12 +++++----- lib/connect.c | 8 +++---- lib/linker.version | 12 +++++----- lib/mosquitto.h | 24 +++++++++---------- lib/options.c | 4 ++-- test/lib/c/03-request-response-1.c | 2 +- test/lib/c/03-request-response-2.c | 2 +- .../lib/c/03-request-response-correlation-1.c | 2 +- test/lib/c/11-prop-send-payload-format.c | 2 +- 13 files changed, 51 insertions(+), 51 deletions(-) diff --git a/client/client_shared.c b/client/client_shared.c index fb1ba31000..13972770be 100644 --- a/client/client_shared.c +++ b/client/client_shared.c @@ -944,7 +944,7 @@ int client_opts_set(struct mosquitto *mosq, struct mosq_config *cfg) mosquitto_opts_set(mosq, MOSQ_OPT_PROTOCOL_VERSION, &(cfg->protocol_version)); - if(cfg->will_topic && mosquitto_will_set_with_properties(mosq, cfg->will_topic, + if(cfg->will_topic && mosquitto_will_set_v5(mosq, cfg->will_topic, cfg->will_payloadlen, cfg->will_payload, cfg->will_qos, cfg->will_retain, cfg->will_props)){ @@ -1058,10 +1058,10 @@ int client_connect(struct mosquitto *mosq, struct mosq_config *cfg) if(cfg->use_srv){ rc = mosquitto_connect_srv(mosq, cfg->host, cfg->keepalive, cfg->bind_address); }else{ - rc = mosquitto_connect_bind_with_properties(mosq, cfg->host, port, cfg->keepalive, cfg->bind_address, cfg->connect_props); + rc = mosquitto_connect_bind_v5(mosq, cfg->host, port, cfg->keepalive, cfg->bind_address, cfg->connect_props); } #else - rc = mosquitto_connect_bind_with_properties(mosq, cfg->host, port, cfg->keepalive, cfg->bind_address, cfg->connect_props); + rc = mosquitto_connect_bind_v5(mosq, cfg->host, port, cfg->keepalive, cfg->bind_address, cfg->connect_props); #endif if(rc>0){ if(!cfg->quiet){ diff --git a/client/pub_client.c b/client/pub_client.c index 80609f8458..139bb3aaaf 100644 --- a/client/pub_client.c +++ b/client/pub_client.c @@ -40,10 +40,10 @@ static bool first_publish = true; int my_publish(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, void *payload, int qos, bool retain) { if(cfg.protocol_version == MQTT_PROTOCOL_V5 && cfg.have_topic_alias && first_publish == false){ - return mosquitto_publish_with_properties(mosq, mid, NULL, payloadlen, payload, qos, retain, cfg.publish_props); + return mosquitto_publish_v5(mosq, mid, NULL, payloadlen, payload, qos, retain, cfg.publish_props); }else{ first_publish = false; - return mosquitto_publish_with_properties(mosq, mid, topic, payloadlen, payload, qos, retain, cfg.publish_props); + return mosquitto_publish_v5(mosq, mid, topic, payloadlen, payload, qos, retain, cfg.publish_props); } } @@ -86,7 +86,7 @@ void my_connect_callback(struct mosquitto *mosq, void *obj, int result) break; } } - mosquitto_disconnect_with_properties(mosq, 0, cfg.disconnect_props); + mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props); } }else{ if(result && !cfg.quiet){ diff --git a/client/pub_shared.c b/client/pub_shared.c index bcfc2b5343..9f10d5ec99 100644 --- a/client/pub_shared.c +++ b/client/pub_shared.c @@ -57,11 +57,11 @@ void my_publish_callback(struct mosquitto *mosq, void *obj, int mid) last_mid_sent = mid; if(cfg.pub_mode == MSGMODE_STDIN_LINE){ if(mid == last_mid){ - mosquitto_disconnect_with_properties(mosq, 0, cfg.disconnect_props); + mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props); disconnect_sent = true; } }else if(disconnect_sent == false){ - mosquitto_disconnect_with_properties(mosq, 0, cfg.disconnect_props); + mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props); disconnect_sent = true; } } @@ -184,7 +184,7 @@ int pub_shared_loop(struct mosquitto *mosq) rc2 = my_publish(mosq, &mid_sent, cfg.topic, buf_len_actual-1, buf, cfg.qos, cfg.retain); if(rc2){ if(!cfg.quiet) fprintf(stderr, "Error: Publish returned %d, disconnecting.\n", rc2); - mosquitto_disconnect_with_properties(mosq, MQTT_RC_DISCONNECT_WITH_WILL_MSG, cfg.disconnect_props); + mosquitto_disconnect_v5(mosq, MQTT_RC_DISCONNECT_WITH_WILL_MSG, cfg.disconnect_props); } break; }else{ @@ -202,7 +202,7 @@ int pub_shared_loop(struct mosquitto *mosq) if(feof(stdin)){ if(last_mid == -1){ /* Empty file */ - mosquitto_disconnect_with_properties(mosq, 0, cfg.disconnect_props); + mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props); disconnect_sent = true; status = STATUS_DISCONNECTING; }else{ @@ -212,7 +212,7 @@ int pub_shared_loop(struct mosquitto *mosq) } }else if(status == STATUS_WAITING){ if(last_mid_sent == last_mid && disconnect_sent == false){ - mosquitto_disconnect_with_properties(mosq, 0, cfg.disconnect_props); + mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props); disconnect_sent = true; } #ifdef WIN32 diff --git a/client/sub_client.c b/client/sub_client.c index 36ec4a0cfb..cd297b0b32 100644 --- a/client/sub_client.c +++ b/client/sub_client.c @@ -45,7 +45,7 @@ void my_signal_handler(int signum) { if(signum == SIGALRM){ process_messages = false; - mosquitto_disconnect_with_properties(mosq, MQTT_RC_DISCONNECT_WITH_WILL_MSG, cfg.disconnect_props); + mosquitto_disconnect_v5(mosq, MQTT_RC_DISCONNECT_WITH_WILL_MSG, cfg.disconnect_props); } } #endif @@ -62,7 +62,7 @@ void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquit if(cfg.retained_only && !message->retain && process_messages){ process_messages = false; - mosquitto_disconnect_with_properties(mosq, 0, cfg.disconnect_props); + mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props); return; } @@ -80,7 +80,7 @@ void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquit msg_count++; if(cfg.msg_count == msg_count){ process_messages = false; - mosquitto_disconnect_with_properties(mosq, 0, cfg.disconnect_props); + mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props); } } } @@ -93,7 +93,7 @@ void my_connect_callback(struct mosquitto *mosq, void *obj, int result, int flag mosquitto_subscribe_multiple(mosq, NULL, cfg.topic_count, cfg.topics, cfg.qos, cfg.subscribe_props); for(i=0; i by adding the bind_address parameter. Use this function @@ -491,7 +491,7 @@ libmosq_EXPORT int mosquitto_connect_bind(struct mosquitto *mosq, const char *ho * See Also: * , , */ -libmosq_EXPORT int mosquitto_connect_bind_with_properties(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address, const mosquitto_property *properties); +libmosq_EXPORT int mosquitto_connect_bind_v5(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address, const mosquitto_property *properties); /* * Function: mosquitto_connect_async @@ -675,7 +675,7 @@ libmosq_EXPORT int mosquitto_reconnect_async(struct mosquitto *mosq); libmosq_EXPORT int mosquitto_disconnect(struct mosquitto *mosq); /* - * Function: mosquitto_disconnect_with_properties + * Function: mosquitto_disconnect_v5 * * Disconnect from the broker, with attached MQTT properties. * @@ -695,7 +695,7 @@ libmosq_EXPORT int mosquitto_disconnect(struct mosquitto *mosq); * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. * MOSQ_ERR_PROTOCOL - if any property is invalid for use with DISCONNECT. */ -libmosq_EXPORT int mosquitto_disconnect_with_properties(struct mosquitto *mosq, int reason_code, const mosquitto_property *properties); +libmosq_EXPORT int mosquitto_disconnect_v5(struct mosquitto *mosq, int reason_code, const mosquitto_property *properties); /* ====================================================================== @@ -743,7 +743,7 @@ libmosq_EXPORT int mosquitto_publish(struct mosquitto *mosq, int *mid, const cha /* - * Function: mosquitto_publish_with_properties + * Function: mosquitto_publish_v5 * * Publish a message on a given topic, with attached MQTT properties. * @@ -784,7 +784,7 @@ libmosq_EXPORT int mosquitto_publish(struct mosquitto *mosq, int *mid, const cha * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. * MOSQ_ERR_PROTOCOL - if any property is invalid for use with PUBLISH. */ -libmosq_EXPORT int mosquitto_publish_with_properties( +libmosq_EXPORT int mosquitto_publish_v5( struct mosquitto *mosq, int *mid, const char *topic, @@ -819,7 +819,7 @@ libmosq_EXPORT int mosquitto_publish_with_properties( libmosq_EXPORT int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const char *sub, int qos); /* - * Function: mosquitto_subscribe_with_properties + * Function: mosquitto_subscribe_v5 * * Subscribe to a topic, with attached MQTT properties. * @@ -849,7 +849,7 @@ libmosq_EXPORT int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const c * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. * MOSQ_ERR_PROTOCOL - if any property is invalid for use with SUBSCRIBE. */ -libmosq_EXPORT int mosquitto_subscribe_with_properties(struct mosquitto *mosq, int *mid, const char *sub, int qos, const mosquitto_property *properties); +libmosq_EXPORT int mosquitto_subscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, int qos, const mosquitto_property *properties); /* * Function: mosquitto_subscribe_multiple @@ -904,7 +904,7 @@ int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count libmosq_EXPORT int mosquitto_unsubscribe(struct mosquitto *mosq, int *mid, const char *sub); /* - * Function: mosquitto_unsubscribe_with_properties + * Function: mosquitto_unsubscribe_v5 * * Unsubscribe from a topic, with attached MQTT properties. * @@ -927,7 +927,7 @@ libmosq_EXPORT int mosquitto_unsubscribe(struct mosquitto *mosq, int *mid, const * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. * MOSQ_ERR_PROTOCOL - if any property is invalid for use with UNSUBSCRIBE. */ -libmosq_EXPORT int mosquitto_unsubscribe_with_properties(struct mosquitto *mosq, int *mid, const char *sub, const mosquitto_property *properties); +libmosq_EXPORT int mosquitto_unsubscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, const mosquitto_property *properties); /* ====================================================================== diff --git a/lib/options.c b/lib/options.c index 4a66f30902..7f18993e6b 100644 --- a/lib/options.c +++ b/lib/options.c @@ -32,11 +32,11 @@ and the Eclipse Distribution License is available at int mosquitto_will_set(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain) { - return mosquitto_will_set_with_properties(mosq, topic, payloadlen, payload, qos, retain, NULL); + return mosquitto_will_set_v5(mosq, topic, payloadlen, payload, qos, retain, NULL); } -int mosquitto_will_set_with_properties(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain, mosquitto_property *properties) +int mosquitto_will_set_v5(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain, mosquitto_property *properties) { int rc; diff --git a/test/lib/c/03-request-response-1.c b/test/lib/c/03-request-response-1.c index 5c7b5bf5ca..1cdd4079df 100644 --- a/test/lib/c/03-request-response-1.c +++ b/test/lib/c/03-request-response-1.c @@ -21,7 +21,7 @@ void on_subscribe(struct mosquitto *mosq, void *obj, int mid, int qos_count, con { mosquitto_property *props = NULL; mosquitto_property_add_string(&props, MQTT_PROP_RESPONSE_TOPIC, "response/topic"); - mosquitto_publish_with_properties(mosq, NULL, "request/topic", 6, "action", 0, 0, props); + mosquitto_publish_v5(mosq, NULL, "request/topic", 6, "action", 0, 0, props); mosquitto_property_free_all(&props); } diff --git a/test/lib/c/03-request-response-2.c b/test/lib/c/03-request-response-2.c index 8763496f56..0f16f1efdf 100644 --- a/test/lib/c/03-request-response-2.c +++ b/test/lib/c/03-request-response-2.c @@ -28,7 +28,7 @@ void on_message_v5(struct mosquitto *mosq, void *obj, const struct mosquitto_mes if(p_resp){ p_corr = mosquitto_property_get_property(props, MQTT_PROP_CORRELATION_DATA, false); if(mosquitto_property_read_string(p_resp, &resp_topic) == MOSQ_ERR_SUCCESS){ - rc = mosquitto_publish_with_properties(mosq, NULL, resp_topic, strlen("a response"), "a response", 0, false, p_corr); + rc = mosquitto_publish_v5(mosq, NULL, resp_topic, strlen("a response"), "a response", 0, false, p_corr); free(resp_topic); } } diff --git a/test/lib/c/03-request-response-correlation-1.c b/test/lib/c/03-request-response-correlation-1.c index 7724525644..35190af5e3 100644 --- a/test/lib/c/03-request-response-correlation-1.c +++ b/test/lib/c/03-request-response-correlation-1.c @@ -22,7 +22,7 @@ void on_subscribe(struct mosquitto *mosq, void *obj, int mid, int qos_count, con mosquitto_property *props = NULL; mosquitto_property_add_string(&props, MQTT_PROP_RESPONSE_TOPIC, "response/topic"); mosquitto_property_add_binary(&props, MQTT_PROP_CORRELATION_DATA, "corridor", 8); - mosquitto_publish_with_properties(mosq, NULL, "request/topic", 6, "action", 0, 0, props); + mosquitto_publish_v5(mosq, NULL, "request/topic", 6, "action", 0, 0, props); mosquitto_property_free_all(&props); } diff --git a/test/lib/c/11-prop-send-payload-format.c b/test/lib/c/11-prop-send-payload-format.c index 198ef72fc5..516d86d414 100644 --- a/test/lib/c/11-prop-send-payload-format.c +++ b/test/lib/c/11-prop-send-payload-format.c @@ -17,7 +17,7 @@ void on_connect(struct mosquitto *mosq, void *obj, int rc) exit(1); }else{ rc2 = mosquitto_property_add_byte(&proplist, MQTT_PROP_PAYLOAD_FORMAT_INDICATOR, 1); - mosquitto_publish_with_properties(mosq, &sent_mid, "prop/qos0", strlen("message"), "message", 0, false, proplist); + mosquitto_publish_v5(mosq, &sent_mid, "prop/qos0", strlen("message"), "message", 0, false, proplist); } } From 3647dc357ae5571461c43e6191fc5bca2dea6e83 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 22 Nov 2018 21:32:49 +0000 Subject: [PATCH 109/254] Test for retain_available=false. --- .../broker/03-publish-qos1-retain-disabled.py | 55 +++++++++++++++++++ test/broker/Makefile | 1 + test/broker/ptest.py | 1 + test/mosq_test.py | 14 ++--- 4 files changed, 64 insertions(+), 7 deletions(-) create mode 100755 test/broker/03-publish-qos1-retain-disabled.py diff --git a/test/broker/03-publish-qos1-retain-disabled.py b/test/broker/03-publish-qos1-retain-disabled.py new file mode 100755 index 0000000000..58ebf10e8c --- /dev/null +++ b/test/broker/03-publish-qos1-retain-disabled.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python + +# Test whether a PUBLISH with a retain set when retains are disabled results in +# the correct DISCONNECT. + +import inspect, os, sys +# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder +cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) +if cmd_subfolder not in sys.path: + sys.path.insert(0, cmd_subfolder) + +import mosq_test +import mqtt5_props + +def write_config(filename, port): + with open(filename, 'w') as f: + f.write("port %d\n" % (port)) + f.write("retain_available false\n") + +port = mosq_test.get_port() +conf_file = os.path.basename(__file__).replace('.py', '.conf') +write_config(conf_file, port) + +rc = 1 +mid = 1 +keepalive = 60 +connect_packet = mosq_test.gen_connect("pub-qos1-test", keepalive=keepalive, proto_ver=5) + +props = mqtt5_props.gen_byte_prop(mqtt5_props.PROP_RETAIN_AVAILABLE, 0) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5, properties=props) + +publish_packet = mosq_test.gen_publish("pub/qos1/test", qos=1, mid=mid, payload="message", retain=True, proto_ver=5) +puback_packet = mosq_test.gen_puback(mid, proto_ver=5) + +disconnect_packet = mosq_test.gen_disconnect(reason_code=154, proto_ver=5) + +broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port) + +try: + sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port) + mosq_test.do_send_receive(sock, publish_packet, disconnect_packet, "disconnect") + + rc = 0 + + sock.close() +finally: + os.remove(conf_file) + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index be9cb84b86..2d5237900b 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -69,6 +69,7 @@ endif #./03-publish-qos1-queued-bytes.py ./03-publish-invalid-utf8.py ./03-publish-dollar.py + ./03-publish-qos1-retain-disabled.py 04 : ./04-retain-qos0.py diff --git a/test/broker/ptest.py b/test/broker/ptest.py index 920dee7b13..7dfbaed5cf 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -51,6 +51,7 @@ #(1, './03-publish-qos1-queued-bytes.py'), (1, './03-publish-invalid-utf8.py'), (1, './03-publish-dollar.py'), + (1, './03-publish-qos1-retain-disabled.py'), (1, './04-retain-qos0.py'), (1, './04-retain-qos0-fresh.py'), diff --git a/test/mosq_test.py b/test/mosq_test.py index a975d833f4..c263cc3165 100644 --- a/test/mosq_test.py +++ b/test/mosq_test.py @@ -359,13 +359,13 @@ def gen_connect(client_id, clean_session=True, keepalive=60, username=None, pass packet = packet + struct.pack("!H"+str(len(password))+"s", len(password), password) return packet -def gen_connack(resv=0, rc=0, proto_ver=4): +def gen_connack(resv=0, rc=0, proto_ver=4, properties=None): if proto_ver == 5: - props = mqtt5_props.gen_byte_prop(mqtt5_props.PROP_SHARED_SUB_AVAILABLE, 0) - props += mqtt5_props.gen_byte_prop(mqtt5_props.PROP_SUBSCRIPTION_ID_AVAILABLE, 0) - props = mqtt5_props.prop_finalise(props) + properties += mqtt5_props.gen_byte_prop(mqtt5_props.PROP_SHARED_SUB_AVAILABLE, 0) + properties += mqtt5_props.gen_byte_prop(mqtt5_props.PROP_SUBSCRIPTION_ID_AVAILABLE, 0) + properties = mqtt5_props.prop_finalise(properties) - packet = struct.pack('!BBBB', 32, 2+len(props), resv, rc) + props + packet = struct.pack('!BBBB', 32, 2+len(properties), resv, rc) + properties else: packet = struct.pack('!BBBB', 32, 2, resv, rc); @@ -467,9 +467,9 @@ def gen_pingreq(): def gen_pingresp(): return struct.pack('!BB', 208, 0) -def gen_disconnect(proto_ver=4): +def gen_disconnect(reason_code=0, proto_ver=4): if proto_ver == 5: - return struct.pack('!BBBB', 224, 2, 0, 0) + return struct.pack('!BBBB', 224, 2, reason_code, 0) else: return struct.pack('!BB', 224, 0) From 1241f68ff5e8693413d71bb528810b87cae1f875 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 27 Nov 2018 09:58:39 +0000 Subject: [PATCH 110/254] Macro update --- src/websockets.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/websockets.c b/src/websockets.c index 7c0dca329c..4815fbd5ac 100644 --- a/src/websockets.c +++ b/src/websockets.c @@ -310,7 +310,7 @@ static int callback_mqtt(struct libwebsocket_context *context, #ifdef WITH_SYS_TREE g_msgs_sent++; - if(((packet->command)&0xF6) == PUBLISH){ + if(((packet->command)&0xF6) == CMD_PUBLISH){ g_pub_msgs_sent++; } #endif @@ -350,7 +350,7 @@ static int callback_mqtt(struct libwebsocket_context *context, mosq->in_packet.command = buf[pos]; pos++; /* Clients must send CONNECT as their first command. */ - if(mosq->state == mosq_cs_new && (mosq->in_packet.command&0xF0) != CONNECT){ + if(mosq->state == mosq_cs_new && (mosq->in_packet.command&0xF0) != CMD_CONNECT){ return -1; } } @@ -401,7 +401,7 @@ static int callback_mqtt(struct libwebsocket_context *context, #ifdef WITH_SYS_TREE G_MSGS_RECEIVED_INC(1); - if(((mosq->in_packet.command)&0xF5) == PUBLISH){ + if(((mosq->in_packet.command)&0xF5) == CMD_PUBLISH){ G_PUB_MSGS_RECEIVED_INC(1); } #endif From c31aae25a8a36345158d7e231b5aa723b006aaa2 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 27 Nov 2018 10:01:56 +0000 Subject: [PATCH 111/254] Fix v5 tests with no CONNECT properties. --- test/mosq_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/mosq_test.py b/test/mosq_test.py index c263cc3165..f2c7d3b7ed 100644 --- a/test/mosq_test.py +++ b/test/mosq_test.py @@ -359,7 +359,7 @@ def gen_connect(client_id, clean_session=True, keepalive=60, username=None, pass packet = packet + struct.pack("!H"+str(len(password))+"s", len(password), password) return packet -def gen_connack(resv=0, rc=0, proto_ver=4, properties=None): +def gen_connack(resv=0, rc=0, proto_ver=4, properties=""): if proto_ver == 5: properties += mqtt5_props.gen_byte_prop(mqtt5_props.PROP_SHARED_SUB_AVAILABLE, 0) properties += mqtt5_props.gen_byte_prop(mqtt5_props.PROP_SUBSCRIPTION_ID_AVAILABLE, 0) From 54db895cb35ef6cdef0137af0429956383f9ebb1 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 27 Nov 2018 10:02:10 +0000 Subject: [PATCH 112/254] Rename clean_session to clean_start for v5. --- lib/connect.c | 2 +- lib/mosquitto.c | 12 ++++++------ lib/mosquitto_internal.h | 2 +- lib/socks_mosq.c | 2 +- src/bridge.c | 16 ++++++++-------- src/conf.c | 2 +- src/context.c | 6 +++--- src/handle_connect.c | 26 +++++++++++++------------- src/loop.c | 8 ++++---- src/mosquitto_broker_internal.h | 2 +- src/persist.c | 6 +++--- src/plugin.c | 2 +- 12 files changed, 43 insertions(+), 43 deletions(-) diff --git a/lib/connect.c b/lib/connect.c index f0b78753d5..6fbc776e08 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -205,7 +205,7 @@ static int mosquitto__reconnect(struct mosquitto *mosq, bool blocking, const mos }else #endif { - return send__connect(mosq, mosq->keepalive, mosq->clean_session, properties); + return send__connect(mosq, mosq->keepalive, mosq->clean_start, properties); } } diff --git a/lib/mosquitto.c b/lib/mosquitto.c index be449fbe03..688312d3f7 100644 --- a/lib/mosquitto.c +++ b/lib/mosquitto.c @@ -64,12 +64,12 @@ int mosquitto_lib_cleanup(void) return MOSQ_ERR_SUCCESS; } -struct mosquitto *mosquitto_new(const char *id, bool clean_session, void *userdata) +struct mosquitto *mosquitto_new(const char *id, bool clean_start, void *userdata) { struct mosquitto *mosq = NULL; int rc; - if(clean_session == false && id == NULL){ + if(clean_start == false && id == NULL){ errno = EINVAL; return NULL; } @@ -86,7 +86,7 @@ struct mosquitto *mosquitto_new(const char *id, bool clean_session, void *userda #ifdef WITH_THREADING mosq->thread_id = pthread_self(); #endif - rc = mosquitto_reinitialise(mosq, id, clean_session, userdata); + rc = mosquitto_reinitialise(mosq, id, clean_start, userdata); if(rc){ mosquitto_destroy(mosq); if(rc == MOSQ_ERR_INVAL){ @@ -102,13 +102,13 @@ struct mosquitto *mosquitto_new(const char *id, bool clean_session, void *userda return mosq; } -int mosquitto_reinitialise(struct mosquitto *mosq, const char *id, bool clean_session, void *userdata) +int mosquitto_reinitialise(struct mosquitto *mosq, const char *id, bool clean_start, void *userdata) { int i; if(!mosq) return MOSQ_ERR_INVAL; - if(clean_session == false && id == NULL){ + if(clean_start == false && id == NULL){ return MOSQ_ERR_INVAL; } @@ -125,7 +125,7 @@ int mosquitto_reinitialise(struct mosquitto *mosq, const char *id, bool clean_se mosq->sockpairR = INVALID_SOCKET; mosq->sockpairW = INVALID_SOCKET; mosq->keepalive = 60; - mosq->clean_session = clean_session; + mosq->clean_start = clean_start; if(id){ if(STREMPTY(id)){ return MOSQ_ERR_INVAL; diff --git a/lib/mosquitto_internal.h b/lib/mosquitto_internal.h index fe0a6e24fa..1ca5f3c39e 100644 --- a/lib/mosquitto_internal.h +++ b/lib/mosquitto_internal.h @@ -208,7 +208,7 @@ struct mosquitto { pthread_mutex_t mid_mutex; pthread_t thread_id; #endif - bool clean_session; + bool clean_start; #ifdef WITH_BROKER char *old_id; /* for when a duplicate client connects, but we still want to know what the id was */ diff --git a/lib/socks_mosq.c b/lib/socks_mosq.c index a3cfc015d3..5f43d16aa7 100644 --- a/lib/socks_mosq.c +++ b/lib/socks_mosq.c @@ -417,7 +417,7 @@ int socks5__read(struct mosquitto *mosq) /* Auth passed */ packet__cleanup(&mosq->in_packet); mosq->state = mosq_cs_new; - return send__connect(mosq, mosq->keepalive, mosq->clean_session, NULL); + return send__connect(mosq, mosq->keepalive, mosq->clean_start, NULL); }else{ i = mosq->in_packet.payload[1]; packet__cleanup(&mosq->in_packet); diff --git a/src/bridge.c b/src/bridge.c index 2446184d90..59e7b51641 100644 --- a/src/bridge.c +++ b/src/bridge.c @@ -124,18 +124,18 @@ int bridge__connect_step1(struct mosquitto_db *db, struct mosquitto *context) context->last_msg_in = mosquitto_time(); context->next_msg_out = mosquitto_time() + context->bridge->keepalive; context->keepalive = context->bridge->keepalive; - context->clean_session = context->bridge->clean_session; + context->clean_start = context->bridge->clean_start; context->in_packet.payload = NULL; context->ping_t = 0; context->bridge->lazy_reconnect = false; bridge__packet_cleanup(context); db__message_reconnect_reset(db, context); - if(context->clean_session){ + if(context->clean_start){ db__messages_delete(db, context); } - /* Delete all local subscriptions even for clean_session==false. We don't + /* Delete all local subscriptions even for clean_start==false. We don't * remove any messages and the next loop carries out the resubscription * anyway. This means any unwanted subs will be removed. */ @@ -256,7 +256,7 @@ int bridge__connect_step3(struct mosquitto_db *db, struct mosquitto *context) context->bridge->primary_retry = mosquitto_time() + 5; } - rc = send__connect(context, context->keepalive, context->clean_session, NULL); + rc = send__connect(context, context->keepalive, context->clean_start, NULL); if(rc == MOSQ_ERR_SUCCESS){ return MOSQ_ERR_SUCCESS; }else if(rc == MOSQ_ERR_ERRNO && errno == ENOTCONN){ @@ -290,18 +290,18 @@ int bridge__connect(struct mosquitto_db *db, struct mosquitto *context) context->last_msg_in = mosquitto_time(); context->next_msg_out = mosquitto_time() + context->bridge->keepalive; context->keepalive = context->bridge->keepalive; - context->clean_session = context->bridge->clean_session; + context->clean_start = context->bridge->clean_start; context->in_packet.payload = NULL; context->ping_t = 0; context->bridge->lazy_reconnect = false; bridge__packet_cleanup(context); db__message_reconnect_reset(db, context); - if(context->clean_session){ + if(context->clean_start){ db__messages_delete(db, context); } - /* Delete all local subscriptions even for clean_session==false. We don't + /* Delete all local subscriptions even for clean_start==false. We don't * remove any messages and the next loop carries out the resubscription * anyway. This means any unwanted subs will be removed. */ @@ -375,7 +375,7 @@ int bridge__connect(struct mosquitto_db *db, struct mosquitto *context) HASH_ADD(hh_sock, db->contexts_by_sock, sock, sizeof(context->sock), context); - rc2 = send__connect(context, context->keepalive, context->clean_session, NULL); + rc2 = send__connect(context, context->keepalive, context->clean_start, NULL); if(rc2 == MOSQ_ERR_SUCCESS){ return rc; }else if(rc2 == MOSQ_ERR_ERRNO && errno == ENOTCONN){ diff --git a/src/conf.c b/src/conf.c index 20609e07bb..00d30b2ebf 100644 --- a/src/conf.c +++ b/src/conf.c @@ -1112,7 +1112,7 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } - if(conf__parse_bool(&token, "cleansession", &cur_bridge->clean_session, saveptr)) return MOSQ_ERR_INVAL; + if(conf__parse_bool(&token, "cleansession", &cur_bridge->clean_start, saveptr)) return MOSQ_ERR_INVAL; #else log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif diff --git a/src/context.c b/src/context.c index a78ea1e170..164969dbef 100644 --- a/src/context.c +++ b/src/context.c @@ -41,7 +41,7 @@ struct mosquitto *context__init(struct mosquitto_db *db, mosq_sock_t sock) context->last_msg_in = mosquitto_time(); context->next_msg_out = mosquitto_time() + 60; context->keepalive = 60; /* Default to 60s */ - context->clean_session = true; + context->clean_start = true; context->disconnect_t = 0; context->id = NULL; context->last_mid = 0; @@ -144,7 +144,7 @@ void context__cleanup(struct mosquitto_db *db, struct mosquitto *context, bool d context->password = NULL; net__socket_close(db, context); - if((do_free || context->clean_session) && db){ + if((do_free || context->clean_start) && db){ sub__clean_session(db, context); db__messages_delete(db, context); } @@ -178,7 +178,7 @@ void context__cleanup(struct mosquitto_db *db, struct mosquitto *context, bool d context->out_packet = context->out_packet->next; mosquitto__free(packet); } - if(do_free || context->clean_session){ + if(do_free || context->clean_start){ msg = context->inflight_msgs; while(msg){ next = msg->next; diff --git a/src/handle_connect.c b/src/handle_connect.c index 0e87303bf6..e0b50f7d3d 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -120,7 +120,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) char *will_topic_mount; uint16_t will_payloadlen; struct mosquitto_message_all *will_struct = NULL; - uint8_t will, will_retain, will_qos, clean_session; + uint8_t will, will_retain, will_qos, clean_start; uint8_t username_flag, password_flag; char *username = NULL, *password = NULL; int rc; @@ -223,7 +223,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) } } - clean_session = (connect_flags & 0x02) >> 1; + clean_start = (connect_flags & 0x02) >> 1; will = connect_flags & 0x04; will_qos = (connect_flags & 0x18) >> 3; if(will_qos == 3){ @@ -276,7 +276,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) }else{ allow_zero_length_clientid = db->config->security_options.allow_zero_length_clientid; } - if(clean_session == 0 || allow_zero_length_clientid == false){ + if(clean_start == 0 || allow_zero_length_clientid == false){ send__connack(db, context, 0, CONNACK_REFUSED_IDENTIFIER_REJECTED); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; @@ -577,14 +577,14 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) } if(context->protocol == mosq_p_mqtt311 || context->protocol == mosq_p_mqtt5){ - if(clean_session == 0){ + if(clean_start == 0){ connect_ack |= 0x01; } } - context->clean_session = clean_session; + context->clean_start = clean_start; - if(context->clean_session == false && found_context->clean_session == false){ + if(context->clean_start == false && found_context->clean_start == false){ if(found_context->inflight_msgs || found_context->queued_msgs){ context->inflight_msgs = found_context->inflight_msgs; context->queued_msgs = found_context->queued_msgs; @@ -611,7 +611,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) } } - found_context->clean_session = true; + found_context->clean_start = true; found_context->state = mosq_cs_duplicate; do_disconnect(db, found_context); } @@ -664,15 +664,15 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) if(db->config->connection_messages == true){ if(context->is_bridge){ if(context->username){ - log__printf(NULL, MOSQ_LOG_NOTICE, "New bridge connected from %s as %s (c%d, k%d, u'%s').", context->address, client_id, clean_session, context->keepalive, context->username); + log__printf(NULL, MOSQ_LOG_NOTICE, "New bridge connected from %s as %s (c%d, k%d, u'%s').", context->address, client_id, clean_start, context->keepalive, context->username); }else{ - log__printf(NULL, MOSQ_LOG_NOTICE, "New bridge connected from %s as %s (c%d, k%d).", context->address, client_id, clean_session, context->keepalive); + log__printf(NULL, MOSQ_LOG_NOTICE, "New bridge connected from %s as %s (c%d, k%d).", context->address, client_id, clean_start, context->keepalive); } }else{ if(context->username){ - log__printf(NULL, MOSQ_LOG_NOTICE, "New client connected from %s as %s (c%d, k%d, u'%s').", context->address, client_id, clean_session, context->keepalive, context->username); + log__printf(NULL, MOSQ_LOG_NOTICE, "New client connected from %s as %s (c%d, k%d, u'%s').", context->address, client_id, clean_start, context->keepalive, context->username); }else{ - log__printf(NULL, MOSQ_LOG_NOTICE, "New client connected from %s as %s (p%d, c%d, k%d).", context->address, client_id, context->protocol, clean_session, context->keepalive); + log__printf(NULL, MOSQ_LOG_NOTICE, "New client connected from %s as %s (p%d, c%d, k%d).", context->address, client_id, context->protocol, clean_start, context->keepalive); } } @@ -690,7 +690,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) context->id = client_id; client_id = NULL; - context->clean_session = clean_session; + context->clean_start = clean_start; context->ping_t = 0; context->is_dropping = false; if((protocol_version&0x80) == 0x80){ @@ -703,7 +703,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) HASH_ADD_KEYPTR(hh_id, db->contexts_by_id, context->id, strlen(context->id), context); #ifdef WITH_PERSISTENCE - if(!clean_session){ + if(!clean_start){ db->persistence_changes++; } #endif diff --git a/src/loop.c b/src/loop.c index 9714720976..dd6b21394c 100644 --- a/src/loop.c +++ b/src/loop.c @@ -466,7 +466,7 @@ int mosquitto_main_loop(struct mosquitto_db *db, mosq_sock_t *listensock, int li now_time = time(NULL); if(db->config->persistent_client_expiration > 0 && now_time > expiration_check_time){ HASH_ITER(hh_id, db->contexts_by_id, context, ctxt_tmp){ - if(context->sock == INVALID_SOCKET && context->clean_session == 0){ + if(context->sock == INVALID_SOCKET && context->clean_start == 0){ /* This is a persistent client, check to see if the * last time it connected was longer than * persistent_client_expiration seconds ago. If so, @@ -480,7 +480,7 @@ int mosquitto_main_loop(struct mosquitto_db *db, mosq_sock_t *listensock, int li } log__printf(NULL, MOSQ_LOG_NOTICE, "Expiring persistent client %s due to timeout.", id); G_CLIENTS_EXPIRED_INC(); - context->clean_session = true; + context->clean_start = true; context->state = mosq_cs_expiring; do_disconnect(db, context); } @@ -665,9 +665,9 @@ void do_disconnect(struct mosquitto_db *db, struct mosquitto *context) #endif context__disconnect(db, context); #ifdef WITH_BRIDGE - if(context->clean_session && !context->bridge){ + if(context->clean_start && !context->bridge){ #else - if(context->clean_session){ + if(context->clean_start){ #endif context__add_to_disused(db, context); if(context->id){ diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index 694bd649d9..9c4439d365 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -435,7 +435,7 @@ struct mosquitto__bridge{ bool round_robin; bool try_private; bool try_private_accepted; - bool clean_session; + bool clean_start; int keepalive; struct mosquitto__bridge_topic *topics; int topic_count; diff --git a/src/persist.c b/src/persist.c index c434a41e0f..d105c41325 100644 --- a/src/persist.c +++ b/src/persist.c @@ -55,7 +55,7 @@ static struct mosquitto *persist__find_or_add_context(struct mosquitto_db *db, c return NULL; } - context->clean_session = false; + context->clean_start = false; HASH_ADD_KEYPTR(hh_id, db->contexts_by_id, context->id, strlen(context->id), context); } @@ -234,7 +234,7 @@ static int persist__client_write(struct mosquitto_db *db, FILE *db_fptr) assert(db_fptr); HASH_ITER(hh_id, db->contexts_by_id, context, ctxt_tmp){ - if(context && context->clean_session == false){ + if(context && context->clean_start == false){ length = htonl(2+strlen(context->id) + sizeof(uint16_t) + sizeof(time_t)); i16temp = htons(DB_CHUNK_CLIENT); @@ -287,7 +287,7 @@ static int persist__subs_retain_write(struct mosquitto_db *db, FILE *db_fptr, st sub = node->subs; while(sub){ - if(sub->context->clean_session == false){ + if(sub->context->clean_start == false){ length = htonl(2+strlen(sub->context->id) + 2+strlen(thistopic) + sizeof(uint8_t)); i16temp = htons(DB_CHUNK_SUB); diff --git a/src/plugin.c b/src/plugin.c index 3365bfbf66..fd387869f6 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -32,7 +32,7 @@ const char *mosquitto_client_address(const struct mosquitto *client) bool mosquitto_client_clean_session(const struct mosquitto *client) { - return client->clean_session; + return client->clean_start; } From 34e7da426c47f48e38cdc963d6d6ba437b708d22 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 27 Nov 2018 11:26:21 +0000 Subject: [PATCH 113/254] Use test helper for importing modules. --- test/broker/01-connect-anon-denied.py | 8 +------- test/broker/01-connect-invalid-id-0-311.py | 8 +------- test/broker/01-connect-invalid-id-0.py | 8 +------- test/broker/01-connect-invalid-id-missing.py | 8 +------- test/broker/01-connect-invalid-id-utf8.py | 10 +--------- test/broker/01-connect-invalid-protonum.py | 8 +------- test/broker/01-connect-invalid-reserved.py | 8 +------- test/broker/01-connect-success-v5.py | 9 +-------- test/broker/01-connect-success.py | 9 +-------- test/broker/01-connect-uname-invalid-utf8.py | 10 +--------- test/broker/01-connect-uname-no-flag.py | 9 +-------- .../broker/01-connect-uname-no-password-denied.py | 8 +------- test/broker/01-connect-uname-password-denied.py | 8 +------- .../01-connect-uname-password-success-no-tls.py | 8 +------- test/broker/01-connect-uname-password-success.py | 8 +------- test/broker/01-connect-uname-pwd-no-flag.py | 9 +-------- test/broker/02-subhier-crash.py | 9 +-------- test/broker/02-subpub-qos0-payload-format-v5.py | 9 +-------- test/broker/02-subpub-qos0-v5.py | 8 +------- test/broker/02-subpub-qos0.py | 8 +------- test/broker/02-subpub-qos1-v5.py | 8 +------- test/broker/02-subpub-qos1.py | 8 +------- test/broker/02-subpub-qos2-v5.py | 8 +------- test/broker/02-subpub-qos2.py | 8 +------- test/broker/02-subscribe-invalid-utf8.py | 10 +--------- test/broker/02-subscribe-persistence-flipflop.py | 9 +-------- test/broker/02-subscribe-qos0.py | 9 +-------- test/broker/02-subscribe-qos1.py | 8 +------- test/broker/02-subscribe-qos2.py | 8 +------- test/broker/02-unsubscribe-invalid-no-topic.py | 10 +--------- test/broker/02-unsubscribe-qos0.py | 8 +------- test/broker/02-unsubscribe-qos1.py | 8 +------- test/broker/02-unsubscribe-qos2-v5.py | 8 +------- test/broker/02-unsubscribe-qos2.py | 8 +------- test/broker/03-pattern-matching-helper.py | 8 +------- test/broker/03-pattern-matching.py | 11 +---------- .../03-publish-b2c-disconnect-qos1-helper.py | 8 +------- test/broker/03-publish-b2c-disconnect-qos1.py | 11 +---------- .../03-publish-b2c-disconnect-qos2-helper.py | 8 +------- test/broker/03-publish-b2c-disconnect-qos2.py | 10 +--------- test/broker/03-publish-b2c-timeout-qos1-helper.py | 8 +------- test/broker/03-publish-b2c-timeout-qos1.py | 10 +--------- test/broker/03-publish-b2c-timeout-qos2-helper.py | 8 +------- test/broker/03-publish-b2c-timeout-qos2.py | 10 +--------- test/broker/03-publish-c2b-disconnect-qos2.py | 8 +------- test/broker/03-publish-c2b-timeout-qos2.py | 8 +------- test/broker/03-publish-dollar.py | 8 +------- test/broker/03-publish-invalid-utf8.py | 10 +--------- test/broker/03-publish-qos1-queued-bytes.py | 8 +------- test/broker/03-publish-qos1-retain-disabled.py | 9 +-------- test/broker/03-publish-qos1.py | 8 +------- test/broker/03-publish-qos2.py | 8 +------- test/broker/04-retain-qos0-clear.py | 10 +--------- test/broker/04-retain-qos0-fresh.py | 8 +------- test/broker/04-retain-qos0-repeated.py | 8 +------- test/broker/04-retain-qos0.py | 8 +------- test/broker/04-retain-qos1-qos0.py | 8 +------- test/broker/04-retain-upgrade-outgoing-qos.py | 8 +------- test/broker/05-clean-session-qos1-helper.py | 8 +------- test/broker/05-clean-session-qos1.py | 10 +--------- test/broker/06-bridge-b2br-disconnect-qos1.py | 10 +--------- test/broker/06-bridge-b2br-disconnect-qos2.py | 10 +--------- test/broker/06-bridge-b2br-remapping.py | 10 +--------- .../06-bridge-br2b-disconnect-qos1-helper.py | 8 +------- test/broker/06-bridge-br2b-disconnect-qos1.py | 11 +---------- .../06-bridge-br2b-disconnect-qos2-helper.py | 8 +------- test/broker/06-bridge-br2b-disconnect-qos2.py | 11 +---------- test/broker/06-bridge-br2b-remapping.py | 10 +--------- test/broker/06-bridge-fail-persist-resend-qos1.py | 12 +----------- test/broker/06-bridge-fail-persist-resend-qos2.py | 12 +----------- test/broker/06-bridge-per-listener-settings.py | 10 +--------- .../06-bridge-reconnect-local-out-helper.py | 8 +------- test/broker/06-bridge-reconnect-local-out.py | 11 +---------- test/broker/07-will-invalid-utf8.py | 10 +--------- test/broker/07-will-no-flag.py | 9 +-------- test/broker/07-will-null-helper.py | 8 +------- test/broker/07-will-null-topic.py | 8 +------- test/broker/07-will-null.py | 9 +-------- test/broker/07-will-qos0-helper.py | 8 +------- test/broker/07-will-qos0.py | 10 +--------- test/broker/08-ssl-bridge-helper.py | 8 +------- test/broker/08-ssl-bridge.py | 12 +----------- test/broker/08-ssl-connect-cert-auth-crl.py | 12 +----------- test/broker/08-ssl-connect-cert-auth-expired.py | 13 +------------ test/broker/08-ssl-connect-cert-auth-revoked.py | 13 +------------ test/broker/08-ssl-connect-cert-auth-without.py | 14 +------------- test/broker/08-ssl-connect-cert-auth.py | 12 +----------- test/broker/08-ssl-connect-identity.py | 14 ++------------ test/broker/08-ssl-connect-no-auth-wrong-ca.py | 13 +------------ test/broker/08-ssl-connect-no-auth.py | 12 +----------- test/broker/08-ssl-connect-no-identity.py | 14 ++------------ test/broker/08-tls-psk-bridge.py | 14 +------------- test/broker/08-tls-psk-pub.py | 12 +----------- test/broker/09-plugin-auth-acl-sub.py | 8 +------- test/broker/09-plugin-auth-context-params.py | 8 +------- test/broker/09-plugin-auth-defer-unpwd-fail.py | 8 +------- test/broker/09-plugin-auth-defer-unpwd-success.py | 8 +------- test/broker/09-plugin-auth-msg-params.py | 8 +------- test/broker/09-plugin-auth-unpwd-fail.py | 8 +------- test/broker/09-plugin-auth-unpwd-success.py | 8 +------- test/broker/09-plugin-auth-v2-unpwd-fail.py | 8 +------- test/broker/09-plugin-auth-v2-unpwd-success.py | 8 +------- test/broker/10-listener-mount-point-helper.py | 8 +------- test/broker/10-listener-mount-point.py | 10 +--------- test/broker/11-persistent-subscription.py | 8 +------- test/broker/mosq_test_helper.py | 15 +++++++++++++++ test/lib/01-con-discon-success.py | 12 +----------- test/lib/01-keepalive-pingreq.py | 13 +------------ test/lib/01-no-clean-session.py | 12 +----------- test/lib/01-unpwd-set.py | 12 +----------- test/lib/01-will-set.py | 12 +----------- test/lib/01-will-unpwd-set.py | 12 +----------- test/lib/02-subscribe-qos0.py | 12 +----------- test/lib/02-subscribe-qos1.py | 12 +----------- test/lib/02-subscribe-qos2.py | 12 +----------- test/lib/02-unsubscribe.py | 12 +----------- test/lib/03-publish-b2c-qos1.py | 13 +------------ test/lib/03-publish-b2c-qos2.py | 13 +------------ test/lib/03-publish-c2b-qos1-disconnect.py | 12 +----------- test/lib/03-publish-c2b-qos1-timeout.py | 12 +----------- test/lib/03-publish-c2b-qos2-disconnect.py | 12 +----------- test/lib/03-publish-c2b-qos2-timeout.py | 12 +----------- test/lib/03-publish-c2b-qos2.py | 12 +----------- test/lib/03-publish-qos0-no-payload.py | 12 +----------- test/lib/03-publish-qos0.py | 12 +----------- test/lib/03-request-response-correlation.py | 13 +------------ test/lib/03-request-response.py | 13 +------------ test/lib/04-retain-qos0.py | 12 +----------- test/lib/08-ssl-bad-cacert.py | 11 +---------- test/lib/08-ssl-connect-cert-auth-enc.py | 13 +------------ test/lib/08-ssl-connect-cert-auth.py | 13 +------------ test/lib/08-ssl-connect-no-auth.py | 13 +------------ test/lib/08-ssl-fake-cacert.py | 14 +------------- test/lib/09-util-topic-tokenise.py | 10 +--------- test/lib/11-prop-send-payload-format.py | 13 +------------ test/lib/mosq_test_helper.py | 15 +++++++++++++++ 136 files changed, 166 insertions(+), 1189 deletions(-) create mode 100644 test/broker/mosq_test_helper.py create mode 100644 test/lib/mosq_test_helper.py diff --git a/test/broker/01-connect-anon-denied.py b/test/broker/01-connect-anon-denied.py index b2c761f509..8df8518dc1 100755 --- a/test/broker/01-connect-anon-denied.py +++ b/test/broker/01-connect-anon-denied.py @@ -2,13 +2,7 @@ # Test whether an anonymous connection is correctly denied. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port): with open(filename, 'w') as f: diff --git a/test/broker/01-connect-invalid-id-0-311.py b/test/broker/01-connect-invalid-id-0-311.py index 4730c3b15e..41a87701bc 100755 --- a/test/broker/01-connect-invalid-id-0-311.py +++ b/test/broker/01-connect-invalid-id-0-311.py @@ -2,13 +2,7 @@ # Test whether a CONNECT with a zero length client id results in the correct CONNACK packet. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 10 diff --git a/test/broker/01-connect-invalid-id-0.py b/test/broker/01-connect-invalid-id-0.py index bed2d24180..fff5d7afee 100755 --- a/test/broker/01-connect-invalid-id-0.py +++ b/test/broker/01-connect-invalid-id-0.py @@ -2,13 +2,7 @@ # Test whether a CONNECT with a zero length client id results in the correct CONNACK packet. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 10 diff --git a/test/broker/01-connect-invalid-id-missing.py b/test/broker/01-connect-invalid-id-missing.py index 279b9f502e..32188a12fe 100755 --- a/test/broker/01-connect-invalid-id-missing.py +++ b/test/broker/01-connect-invalid-id-missing.py @@ -2,13 +2,7 @@ # Test whether a CONNECT with a zero length client id results in the correct CONNACK packet. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 10 diff --git a/test/broker/01-connect-invalid-id-utf8.py b/test/broker/01-connect-invalid-id-utf8.py index adb5a3046b..99ba1494a5 100755 --- a/test/broker/01-connect-invalid-id-utf8.py +++ b/test/broker/01-connect-invalid-id-utf8.py @@ -2,15 +2,7 @@ # Test whether a client id with invalid UTF-8 fails. -import time -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import struct -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 60 diff --git a/test/broker/01-connect-invalid-protonum.py b/test/broker/01-connect-invalid-protonum.py index 58ca63110d..72b2ae902d 100755 --- a/test/broker/01-connect-invalid-protonum.py +++ b/test/broker/01-connect-invalid-protonum.py @@ -2,13 +2,7 @@ # Test whether a CONNECT with an invalid protocol number results in the correct CONNACK packet. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 10 diff --git a/test/broker/01-connect-invalid-reserved.py b/test/broker/01-connect-invalid-reserved.py index 1245805edd..c98869bfe3 100755 --- a/test/broker/01-connect-invalid-reserved.py +++ b/test/broker/01-connect-invalid-reserved.py @@ -2,13 +2,7 @@ # Test whether a CONNECT with reserved set to 1 results in a disconnect. MQTT-3.1.2-3 -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 10 diff --git a/test/broker/01-connect-success-v5.py b/test/broker/01-connect-success-v5.py index 4d5201a18c..6533ce652d 100755 --- a/test/broker/01-connect-success-v5.py +++ b/test/broker/01-connect-success-v5.py @@ -2,14 +2,7 @@ # Test whether a valid CONNECT results in the correct CONNACK packet for MQTT v5. -import inspect, os, sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 10 diff --git a/test/broker/01-connect-success.py b/test/broker/01-connect-success.py index 45b39d9d5d..4d3959e135 100755 --- a/test/broker/01-connect-success.py +++ b/test/broker/01-connect-success.py @@ -2,14 +2,7 @@ # Test whether a valid CONNECT results in the correct CONNACK packet. -import inspect, os, sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 10 diff --git a/test/broker/01-connect-uname-invalid-utf8.py b/test/broker/01-connect-uname-invalid-utf8.py index 0ddb44ea2a..21313789a2 100755 --- a/test/broker/01-connect-uname-invalid-utf8.py +++ b/test/broker/01-connect-uname-invalid-utf8.py @@ -2,15 +2,7 @@ # Test whether a username with invalid UTF-8 fails. -import time -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import struct -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 60 diff --git a/test/broker/01-connect-uname-no-flag.py b/test/broker/01-connect-uname-no-flag.py index 8eb626a47c..a546792735 100755 --- a/test/broker/01-connect-uname-no-flag.py +++ b/test/broker/01-connect-uname-no-flag.py @@ -3,14 +3,7 @@ # Test whether a connection is disconnected if it provides a username but the # username flag is 0. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import struct -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 10 diff --git a/test/broker/01-connect-uname-no-password-denied.py b/test/broker/01-connect-uname-no-password-denied.py index 9951f488a0..46885910c1 100755 --- a/test/broker/01-connect-uname-no-password-denied.py +++ b/test/broker/01-connect-uname-no-password-denied.py @@ -3,13 +3,7 @@ # Test whether a connection is denied if it provides just a username when it # needs a username and password. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port): with open(filename, 'w') as f: diff --git a/test/broker/01-connect-uname-password-denied.py b/test/broker/01-connect-uname-password-denied.py index 1c9236f65f..4ee7665273 100755 --- a/test/broker/01-connect-uname-password-denied.py +++ b/test/broker/01-connect-uname-password-denied.py @@ -3,13 +3,7 @@ # Test whether a connection is denied if it provides a correct username but # incorrect password. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port): with open(filename, 'w') as f: diff --git a/test/broker/01-connect-uname-password-success-no-tls.py b/test/broker/01-connect-uname-password-success-no-tls.py index 2f168e7021..93de845eb1 100755 --- a/test/broker/01-connect-uname-password-success-no-tls.py +++ b/test/broker/01-connect-uname-password-success-no-tls.py @@ -3,13 +3,7 @@ # Test whether a connection is denied if it provides a correct username but # incorrect password. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port): with open(filename, 'w') as f: diff --git a/test/broker/01-connect-uname-password-success.py b/test/broker/01-connect-uname-password-success.py index 2f168e7021..93de845eb1 100755 --- a/test/broker/01-connect-uname-password-success.py +++ b/test/broker/01-connect-uname-password-success.py @@ -3,13 +3,7 @@ # Test whether a connection is denied if it provides a correct username but # incorrect password. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port): with open(filename, 'w') as f: diff --git a/test/broker/01-connect-uname-pwd-no-flag.py b/test/broker/01-connect-uname-pwd-no-flag.py index 5ece7beb07..f09f690e8f 100755 --- a/test/broker/01-connect-uname-pwd-no-flag.py +++ b/test/broker/01-connect-uname-pwd-no-flag.py @@ -3,14 +3,7 @@ # Test whether a connection is disconnected if it provides a password but the # password flag is 0. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import struct -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 10 diff --git a/test/broker/02-subhier-crash.py b/test/broker/02-subhier-crash.py index b72605c049..b6cd0f9a11 100755 --- a/test/broker/02-subhier-crash.py +++ b/test/broker/02-subhier-crash.py @@ -2,14 +2,7 @@ # Test related to https://github.com/eclipse/mosquitto/issues/505 -import time -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 60 diff --git a/test/broker/02-subpub-qos0-payload-format-v5.py b/test/broker/02-subpub-qos0-payload-format-v5.py index 5c9670a704..8fa7aae256 100755 --- a/test/broker/02-subpub-qos0-payload-format-v5.py +++ b/test/broker/02-subpub-qos0-payload-format-v5.py @@ -4,14 +4,7 @@ # Does the Payload Format Indicator property get sent through? # MQTT v5 -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test -import mqtt5_props +from mosq_test_helper import * rc = 1 mid = 53 diff --git a/test/broker/02-subpub-qos0-v5.py b/test/broker/02-subpub-qos0-v5.py index ef3c900943..debb06f6c8 100755 --- a/test/broker/02-subpub-qos0-v5.py +++ b/test/broker/02-subpub-qos0-v5.py @@ -3,13 +3,7 @@ # Test whether a client subscribed to a topic receives its own message sent to that topic. # MQTT v5 -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 mid = 53 diff --git a/test/broker/02-subpub-qos0.py b/test/broker/02-subpub-qos0.py index 00cdb1767d..803dcb90bf 100755 --- a/test/broker/02-subpub-qos0.py +++ b/test/broker/02-subpub-qos0.py @@ -2,13 +2,7 @@ # Test whether a client subscribed to a topic receives its own message sent to that topic. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 mid = 53 diff --git a/test/broker/02-subpub-qos1-v5.py b/test/broker/02-subpub-qos1-v5.py index 2d08f43d0d..cf87a989ed 100755 --- a/test/broker/02-subpub-qos1-v5.py +++ b/test/broker/02-subpub-qos1-v5.py @@ -3,13 +3,7 @@ # Test whether a client subscribed to a topic receives its own message sent to that topic. # MQTT v5 -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 mid = 530 diff --git a/test/broker/02-subpub-qos1.py b/test/broker/02-subpub-qos1.py index c4a86599ae..ca78af11a5 100755 --- a/test/broker/02-subpub-qos1.py +++ b/test/broker/02-subpub-qos1.py @@ -2,13 +2,7 @@ # Test whether a client subscribed to a topic receives its own message sent to that topic. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 mid = 530 diff --git a/test/broker/02-subpub-qos2-v5.py b/test/broker/02-subpub-qos2-v5.py index 796ed82127..32feaed725 100755 --- a/test/broker/02-subpub-qos2-v5.py +++ b/test/broker/02-subpub-qos2-v5.py @@ -3,13 +3,7 @@ # Test whether a client subscribed to a topic receives its own message sent to that topic. # MQTT v5 -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 mid = 530 diff --git a/test/broker/02-subpub-qos2.py b/test/broker/02-subpub-qos2.py index 610e7c577d..f9f941beb8 100755 --- a/test/broker/02-subpub-qos2.py +++ b/test/broker/02-subpub-qos2.py @@ -2,13 +2,7 @@ # Test whether a client subscribed to a topic receives its own message sent to that topic. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 mid = 530 diff --git a/test/broker/02-subscribe-invalid-utf8.py b/test/broker/02-subscribe-invalid-utf8.py index 00bed94b22..f9ae5b3933 100755 --- a/test/broker/02-subscribe-invalid-utf8.py +++ b/test/broker/02-subscribe-invalid-utf8.py @@ -2,15 +2,7 @@ # Test whether a SUBSCRIBE to a topic with an invalid UTF-8 topic fails -import time -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import struct -import mosq_test +from mosq_test_helper import * rc = 1 mid = 53 diff --git a/test/broker/02-subscribe-persistence-flipflop.py b/test/broker/02-subscribe-persistence-flipflop.py index 36b9109951..26a627ceb3 100755 --- a/test/broker/02-subscribe-persistence-flipflop.py +++ b/test/broker/02-subscribe-persistence-flipflop.py @@ -22,14 +22,7 @@ # # sub does not receive the message - -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 60 diff --git a/test/broker/02-subscribe-qos0.py b/test/broker/02-subscribe-qos0.py index a3ec5803e3..434a87042b 100755 --- a/test/broker/02-subscribe-qos0.py +++ b/test/broker/02-subscribe-qos0.py @@ -2,14 +2,7 @@ # Test whether a SUBSCRIBE to a topic with QoS 0 results in the correct SUBACK packet. -import time -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 mid = 53 diff --git a/test/broker/02-subscribe-qos1.py b/test/broker/02-subscribe-qos1.py index 03b326f31f..a15290ee82 100755 --- a/test/broker/02-subscribe-qos1.py +++ b/test/broker/02-subscribe-qos1.py @@ -2,13 +2,7 @@ # Test whether a SUBSCRIBE to a topic with QoS 1 results in the correct SUBACK packet. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 mid = 79 diff --git a/test/broker/02-subscribe-qos2.py b/test/broker/02-subscribe-qos2.py index c3e3425673..9931583c79 100755 --- a/test/broker/02-subscribe-qos2.py +++ b/test/broker/02-subscribe-qos2.py @@ -2,13 +2,7 @@ # Test whether a SUBSCRIBE to a topic with QoS 2 results in the correct SUBACK packet. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 mid = 3 diff --git a/test/broker/02-unsubscribe-invalid-no-topic.py b/test/broker/02-unsubscribe-invalid-no-topic.py index b5a341524a..3cc1f40117 100755 --- a/test/broker/02-unsubscribe-invalid-no-topic.py +++ b/test/broker/02-unsubscribe-invalid-no-topic.py @@ -2,20 +2,12 @@ # Test whether a UNSUBSCRIBE with no topic results in a disconnect. MQTT-3.10.3-2 -import inspect, os, sys -import struct +from mosq_test_helper import * def gen_unsubscribe_invalid_no_topic(mid): pack_format = "!BBH" return struct.pack(pack_format, 162, 2, mid) -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test - rc = 1 mid = 3 keepalive = 60 diff --git a/test/broker/02-unsubscribe-qos0.py b/test/broker/02-unsubscribe-qos0.py index 99b85a948e..0d824bd319 100755 --- a/test/broker/02-unsubscribe-qos0.py +++ b/test/broker/02-unsubscribe-qos0.py @@ -3,13 +3,7 @@ # Test whether a UNSUBSCRIBE to a topic with QoS 0 results in the correct UNSUBACK packet. # This doesn't assume a subscription exists. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 mid = 53 diff --git a/test/broker/02-unsubscribe-qos1.py b/test/broker/02-unsubscribe-qos1.py index 45dfdf5f3e..4fd25d6930 100755 --- a/test/broker/02-unsubscribe-qos1.py +++ b/test/broker/02-unsubscribe-qos1.py @@ -2,13 +2,7 @@ # Test whether a SUBSCRIBE to a topic with QoS 1 results in the correct SUBACK packet. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 mid = 79 diff --git a/test/broker/02-unsubscribe-qos2-v5.py b/test/broker/02-unsubscribe-qos2-v5.py index 64d71963ba..a05a153915 100755 --- a/test/broker/02-unsubscribe-qos2-v5.py +++ b/test/broker/02-unsubscribe-qos2-v5.py @@ -3,13 +3,7 @@ # Test whether a SUBSCRIBE to a topic with QoS 2 results in the correct SUBACK packet. # MQTT 5 -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 mid = 3 diff --git a/test/broker/02-unsubscribe-qos2.py b/test/broker/02-unsubscribe-qos2.py index e4767518e1..2262c1955c 100755 --- a/test/broker/02-unsubscribe-qos2.py +++ b/test/broker/02-unsubscribe-qos2.py @@ -2,13 +2,7 @@ # Test whether a SUBSCRIBE to a topic with QoS 2 results in the correct SUBACK packet. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 mid = 3 diff --git a/test/broker/03-pattern-matching-helper.py b/test/broker/03-pattern-matching-helper.py index c7dc05615f..6a1f416839 100755 --- a/test/broker/03-pattern-matching-helper.py +++ b/test/broker/03-pattern-matching-helper.py @@ -1,12 +1,6 @@ #!/usr/bin/env python -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = int(sys.argv[2]) diff --git a/test/broker/03-pattern-matching.py b/test/broker/03-pattern-matching.py index 02754fa483..31d43edd19 100755 --- a/test/broker/03-pattern-matching.py +++ b/test/broker/03-pattern-matching.py @@ -1,15 +1,6 @@ #!/usr/bin/env python -import subprocess -import time - -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def pattern_test(sub_topic, pub_topic): rc = 1 diff --git a/test/broker/03-publish-b2c-disconnect-qos1-helper.py b/test/broker/03-publish-b2c-disconnect-qos1-helper.py index f6c9766f12..f86ed17556 100755 --- a/test/broker/03-publish-b2c-disconnect-qos1-helper.py +++ b/test/broker/03-publish-b2c-disconnect-qos1-helper.py @@ -1,12 +1,6 @@ #!/usr/bin/env python -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_port() diff --git a/test/broker/03-publish-b2c-disconnect-qos1.py b/test/broker/03-publish-b2c-disconnect-qos1.py index 14e1ed17e7..d171346bda 100755 --- a/test/broker/03-publish-b2c-disconnect-qos1.py +++ b/test/broker/03-publish-b2c-disconnect-qos1.py @@ -1,15 +1,6 @@ #!/usr/bin/env python -import subprocess -import socket - -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_port() diff --git a/test/broker/03-publish-b2c-disconnect-qos2-helper.py b/test/broker/03-publish-b2c-disconnect-qos2-helper.py index aa99fd4d31..f0c0dccecb 100755 --- a/test/broker/03-publish-b2c-disconnect-qos2-helper.py +++ b/test/broker/03-publish-b2c-disconnect-qos2-helper.py @@ -2,13 +2,7 @@ # Test whether a PUBLISH to a topic with QoS 2 results in the correct packet flow. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_port() diff --git a/test/broker/03-publish-b2c-disconnect-qos2.py b/test/broker/03-publish-b2c-disconnect-qos2.py index 8d40f5ae3c..dda48cc2a2 100755 --- a/test/broker/03-publish-b2c-disconnect-qos2.py +++ b/test/broker/03-publish-b2c-disconnect-qos2.py @@ -1,14 +1,6 @@ #!/usr/bin/env python -import subprocess - -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 mid = 3265 diff --git a/test/broker/03-publish-b2c-timeout-qos1-helper.py b/test/broker/03-publish-b2c-timeout-qos1-helper.py index 5ed91aba38..a1d4c82987 100755 --- a/test/broker/03-publish-b2c-timeout-qos1-helper.py +++ b/test/broker/03-publish-b2c-timeout-qos1-helper.py @@ -2,13 +2,7 @@ # Test whether a PUBLISH to a topic with QoS 2 results in the correct packet flow. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 60 diff --git a/test/broker/03-publish-b2c-timeout-qos1.py b/test/broker/03-publish-b2c-timeout-qos1.py index a08dd44b1b..f5aae3bbd1 100755 --- a/test/broker/03-publish-b2c-timeout-qos1.py +++ b/test/broker/03-publish-b2c-timeout-qos1.py @@ -2,15 +2,7 @@ # Test whether a SUBSCRIBE to a topic with QoS 2 results in the correct SUBACK packet. -import subprocess - -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 mid = 3265 diff --git a/test/broker/03-publish-b2c-timeout-qos2-helper.py b/test/broker/03-publish-b2c-timeout-qos2-helper.py index a6e3f7898d..66d5384ff6 100755 --- a/test/broker/03-publish-b2c-timeout-qos2-helper.py +++ b/test/broker/03-publish-b2c-timeout-qos2-helper.py @@ -2,13 +2,7 @@ # Test whether a PUBLISH to a topic with QoS 2 results in the correct packet flow. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 60 diff --git a/test/broker/03-publish-b2c-timeout-qos2.py b/test/broker/03-publish-b2c-timeout-qos2.py index aceef579da..295b1e209b 100755 --- a/test/broker/03-publish-b2c-timeout-qos2.py +++ b/test/broker/03-publish-b2c-timeout-qos2.py @@ -2,15 +2,7 @@ # Test whether a SUBSCRIBE to a topic with QoS 2 results in the correct SUBACK packet. -import subprocess - -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 mid = 3265 diff --git a/test/broker/03-publish-c2b-disconnect-qos2.py b/test/broker/03-publish-c2b-disconnect-qos2.py index 057690fc16..02dc238ba0 100755 --- a/test/broker/03-publish-c2b-disconnect-qos2.py +++ b/test/broker/03-publish-c2b-disconnect-qos2.py @@ -1,12 +1,6 @@ #!/usr/bin/env python -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 mid = 3265 diff --git a/test/broker/03-publish-c2b-timeout-qos2.py b/test/broker/03-publish-c2b-timeout-qos2.py index 2c7f6f79ba..c5e3e8dfaa 100755 --- a/test/broker/03-publish-c2b-timeout-qos2.py +++ b/test/broker/03-publish-c2b-timeout-qos2.py @@ -4,13 +4,7 @@ # flow. This test introduces delays into the flow in order to force the broker # to send duplicate PUBREC and PUBCOMP messages. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 600 diff --git a/test/broker/03-publish-dollar.py b/test/broker/03-publish-dollar.py index 4b2d3787ee..35b716cf06 100755 --- a/test/broker/03-publish-dollar.py +++ b/test/broker/03-publish-dollar.py @@ -2,13 +2,7 @@ # Test whether a PUBLISH to a topic starting with $ succeeds -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 mid = 19 diff --git a/test/broker/03-publish-invalid-utf8.py b/test/broker/03-publish-invalid-utf8.py index 811b356a6d..fb3788b1f5 100755 --- a/test/broker/03-publish-invalid-utf8.py +++ b/test/broker/03-publish-invalid-utf8.py @@ -2,15 +2,7 @@ # Test whether a PUBLISH to a topic with an invalid UTF-8 topic fails -import time -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import struct -import mosq_test +from mosq_test_helper import * rc = 1 mid = 53 diff --git a/test/broker/03-publish-qos1-queued-bytes.py b/test/broker/03-publish-qos1-queued-bytes.py index e2f4c32df8..f57e381f87 100755 --- a/test/broker/03-publish-qos1-queued-bytes.py +++ b/test/broker/03-publish-qos1-queued-bytes.py @@ -17,13 +17,7 @@ exit(0) -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 diff --git a/test/broker/03-publish-qos1-retain-disabled.py b/test/broker/03-publish-qos1-retain-disabled.py index 58ebf10e8c..bb86fe61e0 100755 --- a/test/broker/03-publish-qos1-retain-disabled.py +++ b/test/broker/03-publish-qos1-retain-disabled.py @@ -3,14 +3,7 @@ # Test whether a PUBLISH with a retain set when retains are disabled results in # the correct DISCONNECT. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test -import mqtt5_props +from mosq_test_helper import * def write_config(filename, port): with open(filename, 'w') as f: diff --git a/test/broker/03-publish-qos1.py b/test/broker/03-publish-qos1.py index 5bcebd4702..dabf33581c 100755 --- a/test/broker/03-publish-qos1.py +++ b/test/broker/03-publish-qos1.py @@ -2,13 +2,7 @@ # Test whether a PUBLISH to a topic with QoS 1 results in the correct PUBACK packet. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 mid = 19 diff --git a/test/broker/03-publish-qos2.py b/test/broker/03-publish-qos2.py index c6ae3c695d..2a8ebd4721 100755 --- a/test/broker/03-publish-qos2.py +++ b/test/broker/03-publish-qos2.py @@ -2,13 +2,7 @@ # Test whether a PUBLISH to a topic with QoS 2 results in the correct packet flow. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 60 diff --git a/test/broker/04-retain-qos0-clear.py b/test/broker/04-retain-qos0-clear.py index 90cdf6c3f5..ea6d122ce2 100755 --- a/test/broker/04-retain-qos0-clear.py +++ b/test/broker/04-retain-qos0-clear.py @@ -3,15 +3,7 @@ # Test whether a retained PUBLISH is cleared when a zero length retained # message is published to a topic. -import socket - -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 60 diff --git a/test/broker/04-retain-qos0-fresh.py b/test/broker/04-retain-qos0-fresh.py index c2445b82db..41f21a2656 100755 --- a/test/broker/04-retain-qos0-fresh.py +++ b/test/broker/04-retain-qos0-fresh.py @@ -3,13 +3,7 @@ # Test whether a retained PUBLISH to a topic with QoS 0 is sent with # retain=false to an already subscribed client. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 60 diff --git a/test/broker/04-retain-qos0-repeated.py b/test/broker/04-retain-qos0-repeated.py index 7276248a24..54fc0e9e3d 100755 --- a/test/broker/04-retain-qos0-repeated.py +++ b/test/broker/04-retain-qos0-repeated.py @@ -3,13 +3,7 @@ # Test whether a retained PUBLISH to a topic with QoS 0 is actually retained # and delivered when multiple sub/unsub operations are carried out. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 60 diff --git a/test/broker/04-retain-qos0.py b/test/broker/04-retain-qos0.py index 2d6986718c..d6b2190225 100755 --- a/test/broker/04-retain-qos0.py +++ b/test/broker/04-retain-qos0.py @@ -2,13 +2,7 @@ # Test whether a retained PUBLISH to a topic with QoS 0 is actually retained. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 60 diff --git a/test/broker/04-retain-qos1-qos0.py b/test/broker/04-retain-qos1-qos0.py index dd45265229..3fa96a080a 100755 --- a/test/broker/04-retain-qos1-qos0.py +++ b/test/broker/04-retain-qos1-qos0.py @@ -4,13 +4,7 @@ # Subscription is made with QoS 0 so the retained message should also have QoS # 0. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 60 diff --git a/test/broker/04-retain-upgrade-outgoing-qos.py b/test/broker/04-retain-upgrade-outgoing-qos.py index 597e9828be..bccff1d729 100755 --- a/test/broker/04-retain-upgrade-outgoing-qos.py +++ b/test/broker/04-retain-upgrade-outgoing-qos.py @@ -3,13 +3,7 @@ # Test whether a retained PUBLISH to a topic with QoS 0 is sent with subscriber QoS # when upgrade_outgoing_qos is true -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port): with open(filename, 'w') as f: diff --git a/test/broker/05-clean-session-qos1-helper.py b/test/broker/05-clean-session-qos1-helper.py index c1e624442a..28abd80360 100755 --- a/test/broker/05-clean-session-qos1-helper.py +++ b/test/broker/05-clean-session-qos1-helper.py @@ -2,13 +2,7 @@ # Test whether a clean session client has a QoS 1 message queued for it. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 60 diff --git a/test/broker/05-clean-session-qos1.py b/test/broker/05-clean-session-qos1.py index 7ae6cdc814..22f5603e77 100755 --- a/test/broker/05-clean-session-qos1.py +++ b/test/broker/05-clean-session-qos1.py @@ -2,15 +2,7 @@ # Test whether a clean session client has a QoS 1 message queued for it. -import subprocess - -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 mid = 109 diff --git a/test/broker/06-bridge-b2br-disconnect-qos1.py b/test/broker/06-bridge-b2br-disconnect-qos1.py index 91c7fe6c35..e742bd73cc 100755 --- a/test/broker/06-bridge-b2br-disconnect-qos1.py +++ b/test/broker/06-bridge-b2br-disconnect-qos1.py @@ -2,15 +2,7 @@ # Does a bridge resend a QoS=1 message correctly after a disconnect? -import socket - -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port1, port2): with open(filename, 'w') as f: diff --git a/test/broker/06-bridge-b2br-disconnect-qos2.py b/test/broker/06-bridge-b2br-disconnect-qos2.py index 11f1970082..38c86c2317 100755 --- a/test/broker/06-bridge-b2br-disconnect-qos2.py +++ b/test/broker/06-bridge-b2br-disconnect-qos2.py @@ -2,15 +2,7 @@ # Does a bridge resend a QoS=1 message correctly after a disconnect? -import socket - -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port1, port2): with open(filename, 'w') as f: diff --git a/test/broker/06-bridge-b2br-remapping.py b/test/broker/06-bridge-b2br-remapping.py index 4c344354e2..3d81e0c2f6 100755 --- a/test/broker/06-bridge-b2br-remapping.py +++ b/test/broker/06-bridge-b2br-remapping.py @@ -2,15 +2,7 @@ # Test remapping of topic name for incoming message -import socket - -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port1, port2): with open(filename, 'w') as f: diff --git a/test/broker/06-bridge-br2b-disconnect-qos1-helper.py b/test/broker/06-bridge-br2b-disconnect-qos1-helper.py index f010cd337b..0e50f9ef83 100755 --- a/test/broker/06-bridge-br2b-disconnect-qos1-helper.py +++ b/test/broker/06-bridge-br2b-disconnect-qos1-helper.py @@ -1,12 +1,6 @@ #!/usr/bin/env python -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_port() diff --git a/test/broker/06-bridge-br2b-disconnect-qos1.py b/test/broker/06-bridge-br2b-disconnect-qos1.py index ae43970abc..00fdba0fee 100755 --- a/test/broker/06-bridge-br2b-disconnect-qos1.py +++ b/test/broker/06-bridge-br2b-disconnect-qos1.py @@ -2,16 +2,7 @@ # Does a bridge resend a QoS=1 message correctly after a disconnect? -import subprocess -import socket - -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port1, port2): with open(filename, 'w') as f: diff --git a/test/broker/06-bridge-br2b-disconnect-qos2-helper.py b/test/broker/06-bridge-br2b-disconnect-qos2-helper.py index 80b12e17b6..bcb28d43ac 100755 --- a/test/broker/06-bridge-br2b-disconnect-qos2-helper.py +++ b/test/broker/06-bridge-br2b-disconnect-qos2-helper.py @@ -1,12 +1,6 @@ #!/usr/bin/env python -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_port() diff --git a/test/broker/06-bridge-br2b-disconnect-qos2.py b/test/broker/06-bridge-br2b-disconnect-qos2.py index 24610aba4d..d746928819 100755 --- a/test/broker/06-bridge-br2b-disconnect-qos2.py +++ b/test/broker/06-bridge-br2b-disconnect-qos2.py @@ -2,16 +2,7 @@ # Does a bridge resend a QoS=1 message correctly after a disconnect? -import subprocess -import socket - -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port1, port2): with open(filename, 'w') as f: diff --git a/test/broker/06-bridge-br2b-remapping.py b/test/broker/06-bridge-br2b-remapping.py index 51ddf2bb21..716b2e5a11 100755 --- a/test/broker/06-bridge-br2b-remapping.py +++ b/test/broker/06-bridge-br2b-remapping.py @@ -2,15 +2,7 @@ # Test remapping of topic name for outgoing message -import socket - -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port1, port2): with open(filename, 'w') as f: diff --git a/test/broker/06-bridge-fail-persist-resend-qos1.py b/test/broker/06-bridge-fail-persist-resend-qos1.py index f288561d52..ece86f9905 100755 --- a/test/broker/06-bridge-fail-persist-resend-qos1.py +++ b/test/broker/06-bridge-fail-persist-resend-qos1.py @@ -2,17 +2,7 @@ # Test whether a bridge can cope with an unknown PUBACK -import socket -import subprocess -import time - -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port1, port2): with open(filename, 'w') as f: diff --git a/test/broker/06-bridge-fail-persist-resend-qos2.py b/test/broker/06-bridge-fail-persist-resend-qos2.py index 1d1aad1dda..7c2df3e223 100755 --- a/test/broker/06-bridge-fail-persist-resend-qos2.py +++ b/test/broker/06-bridge-fail-persist-resend-qos2.py @@ -2,17 +2,7 @@ # Test whether a bridge can cope with an unknown PUBACK -import socket -import subprocess -import time - -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port1, port2): with open(filename, 'w') as f: diff --git a/test/broker/06-bridge-per-listener-settings.py b/test/broker/06-bridge-per-listener-settings.py index 06758a7598..4e6e90ad5d 100755 --- a/test/broker/06-bridge-per-listener-settings.py +++ b/test/broker/06-bridge-per-listener-settings.py @@ -2,15 +2,7 @@ # Test remapping of topic name for incoming message -import socket - -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port1, port2, port3): with open(filename, 'w') as f: diff --git a/test/broker/06-bridge-reconnect-local-out-helper.py b/test/broker/06-bridge-reconnect-local-out-helper.py index cf46147b0d..66eb425dbf 100755 --- a/test/broker/06-bridge-reconnect-local-out-helper.py +++ b/test/broker/06-bridge-reconnect-local-out-helper.py @@ -1,12 +1,6 @@ #!/usr/bin/env python -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_port() diff --git a/test/broker/06-bridge-reconnect-local-out.py b/test/broker/06-bridge-reconnect-local-out.py index 9edde871e5..0b043e5229 100755 --- a/test/broker/06-bridge-reconnect-local-out.py +++ b/test/broker/06-bridge-reconnect-local-out.py @@ -3,16 +3,7 @@ # Test whether a bridge topics work correctly after reconnection. # Important point here is that persistence is enabled. -import subprocess -import time - -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port1, port2): with open(filename, 'w') as f: diff --git a/test/broker/07-will-invalid-utf8.py b/test/broker/07-will-invalid-utf8.py index b3059e6cb3..c4c1f1a211 100755 --- a/test/broker/07-will-invalid-utf8.py +++ b/test/broker/07-will-invalid-utf8.py @@ -2,15 +2,7 @@ # Test whether a will topic with invalid UTF-8 fails -import time -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import struct -import mosq_test +from mosq_test_helper import * rc = 1 mid = 53 diff --git a/test/broker/07-will-no-flag.py b/test/broker/07-will-no-flag.py index e233323128..0b4960e58f 100755 --- a/test/broker/07-will-no-flag.py +++ b/test/broker/07-will-no-flag.py @@ -3,14 +3,7 @@ # Test whether a connection is disconnected if it sets the will flag but does # not provide a will payload. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import struct -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 10 diff --git a/test/broker/07-will-null-helper.py b/test/broker/07-will-null-helper.py index 9ea56e5992..2500185e27 100755 --- a/test/broker/07-will-null-helper.py +++ b/test/broker/07-will-null-helper.py @@ -2,13 +2,7 @@ # Connect a client with a will, then disconnect without DISCONNECT. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 60 diff --git a/test/broker/07-will-null-topic.py b/test/broker/07-will-null-topic.py index 69c5dcbc24..b9c15943f4 100755 --- a/test/broker/07-will-null-topic.py +++ b/test/broker/07-will-null-topic.py @@ -2,13 +2,7 @@ import struct -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 60 diff --git a/test/broker/07-will-null.py b/test/broker/07-will-null.py index 0a76fdca0e..50c00d4e35 100755 --- a/test/broker/07-will-null.py +++ b/test/broker/07-will-null.py @@ -2,14 +2,7 @@ # Test whether a client will is transmitted correctly with a null character in the middle. -import subprocess -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 mid = 53 diff --git a/test/broker/07-will-qos0-helper.py b/test/broker/07-will-qos0-helper.py index e6c46eb732..f9d42c6496 100755 --- a/test/broker/07-will-qos0-helper.py +++ b/test/broker/07-will-qos0-helper.py @@ -2,13 +2,7 @@ # Connect a client with a will, then disconnect without DISCONNECT. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 keepalive = 60 diff --git a/test/broker/07-will-qos0.py b/test/broker/07-will-qos0.py index 4c7ef7d46e..990e40b452 100755 --- a/test/broker/07-will-qos0.py +++ b/test/broker/07-will-qos0.py @@ -2,15 +2,7 @@ # Test whether a client will is transmitted correctly. -import subprocess - -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * rc = 1 mid = 53 diff --git a/test/broker/08-ssl-bridge-helper.py b/test/broker/08-ssl-bridge-helper.py index e67c398bf5..9ca462f4dd 100755 --- a/test/broker/08-ssl-bridge-helper.py +++ b/test/broker/08-ssl-bridge-helper.py @@ -1,12 +1,6 @@ #!/usr/bin/env python -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_port() diff --git a/test/broker/08-ssl-bridge.py b/test/broker/08-ssl-bridge.py index d84bc5b6f7..cb997371b7 100755 --- a/test/broker/08-ssl-bridge.py +++ b/test/broker/08-ssl-bridge.py @@ -1,16 +1,6 @@ #!/usr/bin/env python -import subprocess -import socket -import ssl - -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port1, port2): with open(filename, 'w') as f: diff --git a/test/broker/08-ssl-connect-cert-auth-crl.py b/test/broker/08-ssl-connect-cert-auth-crl.py index 492b7d8d22..b68bee058e 100755 --- a/test/broker/08-ssl-connect-cert-auth-crl.py +++ b/test/broker/08-ssl-connect-cert-auth-crl.py @@ -1,21 +1,11 @@ #!/usr/bin/env python -import socket -import ssl -import sys +from mosq_test_helper import * if sys.version < '2.7': print("WARNING: SSL not supported on Python 2.6") exit(0) -import inspect, os -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test - def write_config(filename, port1, port2): with open(filename, 'w') as f: f.write("port %d\n" % (port2)) diff --git a/test/broker/08-ssl-connect-cert-auth-expired.py b/test/broker/08-ssl-connect-cert-auth-expired.py index 4de5970535..bfa5bc11c7 100755 --- a/test/broker/08-ssl-connect-cert-auth-expired.py +++ b/test/broker/08-ssl-connect-cert-auth-expired.py @@ -3,23 +3,12 @@ # Test whether a valid CONNECT results in the correct CONNACK packet using an # SSL connection with client certificates required. -import socket -import ssl -import sys -import time +from mosq_test_helper import * if sys.version < '2.7': print("WARNING: SSL not supported on Python 2.6") exit(0) -import inspect, os -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test - def write_config(filename, port1, port2): with open(filename, 'w') as f: f.write("port %d\n" % (port2)) diff --git a/test/broker/08-ssl-connect-cert-auth-revoked.py b/test/broker/08-ssl-connect-cert-auth-revoked.py index 76b6bfbe08..60d08305d0 100755 --- a/test/broker/08-ssl-connect-cert-auth-revoked.py +++ b/test/broker/08-ssl-connect-cert-auth-revoked.py @@ -1,22 +1,11 @@ #!/usr/bin/env python -import socket -import ssl -import sys -import time +from mosq_test_helper import * if sys.version < '2.7': print("WARNING: SSL not supported on Python 2.6") exit(0) -import inspect, os -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test - def write_config(filename, port1, port2): with open(filename, 'w') as f: f.write("port %d\n" % (port2)) diff --git a/test/broker/08-ssl-connect-cert-auth-without.py b/test/broker/08-ssl-connect-cert-auth-without.py index 2f7dbf83a8..7df9a3b2c9 100755 --- a/test/broker/08-ssl-connect-cert-auth-without.py +++ b/test/broker/08-ssl-connect-cert-auth-without.py @@ -2,24 +2,12 @@ # Test whether a client can connect without an SSL certificate if one is required. -import errno -import socket -import ssl -import sys -import time +from mosq_test_helper import * if sys.version < '2.7': print("WARNING: SSL not supported on Python 2.6") exit(0) -import inspect, os -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test - def write_config(filename, port1, port2): with open(filename, 'w') as f: f.write("port %d\n" % (port2)) diff --git a/test/broker/08-ssl-connect-cert-auth.py b/test/broker/08-ssl-connect-cert-auth.py index 04ca171c9b..1f0872d319 100755 --- a/test/broker/08-ssl-connect-cert-auth.py +++ b/test/broker/08-ssl-connect-cert-auth.py @@ -2,22 +2,12 @@ # Test whether a valid CONNECT results in the correct CONNACK packet using an SSL connection. -import socket -import ssl -import sys +from mosq_test_helper import * if sys.version < '2.7': print("WARNING: SSL not supported on Python 2.6") exit(0) -import inspect, os -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test - def write_config(filename, port1, port2): with open(filename, 'w') as f: f.write("port %d\n" % (port2)) diff --git a/test/broker/08-ssl-connect-identity.py b/test/broker/08-ssl-connect-identity.py index b73c2d12dd..4b7dd2806c 100755 --- a/test/broker/08-ssl-connect-identity.py +++ b/test/broker/08-ssl-connect-identity.py @@ -1,23 +1,13 @@ #!/usr/bin/env python # Client connects with a certificate to a server that has use_identity_as_username=true. Shouldn't be rejected. -import socket -import ssl -import sys -import time + +from mosq_test_helper import * if sys.version < '2.7': print("WARNING: SSL not supported on Python 2.6") exit(0) -import inspect, os -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test - def write_config(filename, port1, port2): with open(filename, 'w') as f: f.write("port %d\n" % (port2)) diff --git a/test/broker/08-ssl-connect-no-auth-wrong-ca.py b/test/broker/08-ssl-connect-no-auth-wrong-ca.py index 9f84a28c41..f8cb88e949 100755 --- a/test/broker/08-ssl-connect-no-auth-wrong-ca.py +++ b/test/broker/08-ssl-connect-no-auth-wrong-ca.py @@ -2,23 +2,12 @@ # Test whether a valid CONNECT results in the correct CONNACK packet using an SSL connection. -import socket -import ssl -import sys -import time +from mosq_test_helper import * if sys.version < '2.7': print("WARNING: SSL not supported on Python 2.6") exit(0) -import inspect, os -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test - def write_config(filename, port1, port2): with open(filename, 'w') as f: f.write("port %d\n" % (port2)) diff --git a/test/broker/08-ssl-connect-no-auth.py b/test/broker/08-ssl-connect-no-auth.py index 67c3a87779..ee0acb0ac7 100755 --- a/test/broker/08-ssl-connect-no-auth.py +++ b/test/broker/08-ssl-connect-no-auth.py @@ -2,22 +2,12 @@ # Test whether a valid CONNECT results in the correct CONNACK packet using an SSL connection. -import socket -import ssl -import sys +from mosq_test_helper import * if sys.version < '2.7': print("WARNING: SSL not supported on Python 2.6") exit(0) -import inspect, os -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test - def write_config(filename, port1, port2): with open(filename, 'w') as f: f.write("port %d\n" % (port2)) diff --git a/test/broker/08-ssl-connect-no-identity.py b/test/broker/08-ssl-connect-no-identity.py index 70a0a27cdc..6f65fd0c4e 100755 --- a/test/broker/08-ssl-connect-no-identity.py +++ b/test/broker/08-ssl-connect-no-identity.py @@ -1,23 +1,13 @@ #!/usr/bin/env python # Client connects without a certificate to a server that has use_identity_as_username=true. Should be rejected. -import socket -import ssl -import sys -import time + +from mosq_test_helper import * if sys.version < '2.7': print("WARNING: SSL not supported on Python 2.6") exit(0) -import inspect, os -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test - def write_config(filename, port1, port2): with open(filename, 'w') as f: f.write("port %d\n" % (port2)) diff --git a/test/broker/08-tls-psk-bridge.py b/test/broker/08-tls-psk-bridge.py index b0d2cfb9e8..8a184a2708 100755 --- a/test/broker/08-tls-psk-bridge.py +++ b/test/broker/08-tls-psk-bridge.py @@ -1,23 +1,11 @@ #!/usr/bin/env python -import subprocess -import ssl -import sys -import time +from mosq_test_helper import * if sys.version < '2.7': print("WARNING: SSL not supported on Python 2.6") exit(0) - -import inspect, os -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test - def write_config1(filename, port1, port2): with open(filename, 'w') as f: f.write("allow_anonymous true\n") diff --git a/test/broker/08-tls-psk-pub.py b/test/broker/08-tls-psk-pub.py index 34994416be..383014a642 100755 --- a/test/broker/08-tls-psk-pub.py +++ b/test/broker/08-tls-psk-pub.py @@ -1,22 +1,12 @@ #!/usr/bin/env python -import subprocess -import ssl -import sys +from mosq_test_helper import * if sys.version < '2.7': print("WARNING: SSL not supported on Python 2.6") exit(0) -import inspect, os -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test - def write_config(filename, port1, port2): with open(filename, 'w') as f: f.write("allow_anonymous true\n") diff --git a/test/broker/09-plugin-auth-acl-sub.py b/test/broker/09-plugin-auth-acl-sub.py index 838705bbe1..111d547754 100755 --- a/test/broker/09-plugin-auth-acl-sub.py +++ b/test/broker/09-plugin-auth-acl-sub.py @@ -2,13 +2,7 @@ # Test topic subscription. All topic are allowed but not using wildcard in subscribe. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port): with open(filename, 'w') as f: diff --git a/test/broker/09-plugin-auth-context-params.py b/test/broker/09-plugin-auth-context-params.py index bedbec397d..bb780d64b2 100755 --- a/test/broker/09-plugin-auth-context-params.py +++ b/test/broker/09-plugin-auth-context-params.py @@ -2,13 +2,7 @@ # Test whether message parameters are passed to the plugin acl check function. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port): with open(filename, 'w') as f: diff --git a/test/broker/09-plugin-auth-defer-unpwd-fail.py b/test/broker/09-plugin-auth-defer-unpwd-fail.py index 0cc78aa400..07521a873e 100755 --- a/test/broker/09-plugin-auth-defer-unpwd-fail.py +++ b/test/broker/09-plugin-auth-defer-unpwd-fail.py @@ -2,13 +2,7 @@ # Test whether a connection fail when using a auth_plugin that defer authentication. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port): with open(filename, 'w') as f: diff --git a/test/broker/09-plugin-auth-defer-unpwd-success.py b/test/broker/09-plugin-auth-defer-unpwd-success.py index 3aa9046828..77bf0d72dd 100755 --- a/test/broker/09-plugin-auth-defer-unpwd-success.py +++ b/test/broker/09-plugin-auth-defer-unpwd-success.py @@ -3,13 +3,7 @@ # Test whether a connection is successful with correct username and password # when using a two auth_plugin (first will defer, second will accept). -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port): with open(filename, 'w') as f: diff --git a/test/broker/09-plugin-auth-msg-params.py b/test/broker/09-plugin-auth-msg-params.py index 5aa008e156..38a4ecc696 100755 --- a/test/broker/09-plugin-auth-msg-params.py +++ b/test/broker/09-plugin-auth-msg-params.py @@ -2,13 +2,7 @@ # Test whether message parameters are passed to the plugin acl check function. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port): with open(filename, 'w') as f: diff --git a/test/broker/09-plugin-auth-unpwd-fail.py b/test/broker/09-plugin-auth-unpwd-fail.py index a9b32a834d..8e50fca3d0 100755 --- a/test/broker/09-plugin-auth-unpwd-fail.py +++ b/test/broker/09-plugin-auth-unpwd-fail.py @@ -3,13 +3,7 @@ # Test whether a connection is successful with correct username and password # when using a simple auth_plugin. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port): with open(filename, 'w') as f: diff --git a/test/broker/09-plugin-auth-unpwd-success.py b/test/broker/09-plugin-auth-unpwd-success.py index cff805f5ad..27908509ab 100755 --- a/test/broker/09-plugin-auth-unpwd-success.py +++ b/test/broker/09-plugin-auth-unpwd-success.py @@ -3,13 +3,7 @@ # Test whether a connection is successful with correct username and password # when using a simple auth_plugin. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port): with open(filename, 'w') as f: diff --git a/test/broker/09-plugin-auth-v2-unpwd-fail.py b/test/broker/09-plugin-auth-v2-unpwd-fail.py index a24bb8a7c9..658379171b 100755 --- a/test/broker/09-plugin-auth-v2-unpwd-fail.py +++ b/test/broker/09-plugin-auth-v2-unpwd-fail.py @@ -3,13 +3,7 @@ # Test whether a connection is successful with correct username and password # when using a simple auth_plugin. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port): with open(filename, 'w') as f: diff --git a/test/broker/09-plugin-auth-v2-unpwd-success.py b/test/broker/09-plugin-auth-v2-unpwd-success.py index 7133a6913b..3cc6d7b96a 100755 --- a/test/broker/09-plugin-auth-v2-unpwd-success.py +++ b/test/broker/09-plugin-auth-v2-unpwd-success.py @@ -3,13 +3,7 @@ # Test whether a connection is successful with correct username and password # when using a simple auth_plugin. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port): with open(filename, 'w') as f: diff --git a/test/broker/10-listener-mount-point-helper.py b/test/broker/10-listener-mount-point-helper.py index 602bc4a5ea..a6a9125934 100755 --- a/test/broker/10-listener-mount-point-helper.py +++ b/test/broker/10-listener-mount-point-helper.py @@ -1,12 +1,6 @@ #!/usr/bin/env python -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_port() diff --git a/test/broker/10-listener-mount-point.py b/test/broker/10-listener-mount-point.py index 47fd076614..f190770b5e 100755 --- a/test/broker/10-listener-mount-point.py +++ b/test/broker/10-listener-mount-point.py @@ -1,14 +1,6 @@ #!/usr/bin/env python -import subprocess - -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port1, port2): with open(filename, 'w') as f: diff --git a/test/broker/11-persistent-subscription.py b/test/broker/11-persistent-subscription.py index 492dcfccd0..ff1328fcde 100755 --- a/test/broker/11-persistent-subscription.py +++ b/test/broker/11-persistent-subscription.py @@ -2,13 +2,7 @@ # Test whether a client subscribed to a topic receives its own message sent to that topic. -import inspect, os, sys -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * def write_config(filename, port): with open(filename, 'w') as f: diff --git a/test/broker/mosq_test_helper.py b/test/broker/mosq_test_helper.py new file mode 100644 index 0000000000..0e861dba07 --- /dev/null +++ b/test/broker/mosq_test_helper.py @@ -0,0 +1,15 @@ +import inspect, os, sys + +# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder +cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) +if cmd_subfolder not in sys.path: + sys.path.insert(0, cmd_subfolder) + +import mosq_test +import mqtt5_props + +import socket +import ssl +import struct +import subprocess +import time diff --git a/test/lib/01-con-discon-success.py b/test/lib/01-con-discon-success.py index bb5f4ce2b5..6838c58761 100755 --- a/test/lib/01-con-discon-success.py +++ b/test/lib/01-con-discon-success.py @@ -8,17 +8,7 @@ # the CONNACK and verifying that rc=0, the client should send a DISCONNECT # message. If rc!=0, the client should exit with an error. -import inspect -import os -import socket -import sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/01-keepalive-pingreq.py b/test/lib/01-keepalive-pingreq.py index 8e95b5dbd4..59129cfed4 100755 --- a/test/lib/01-keepalive-pingreq.py +++ b/test/lib/01-keepalive-pingreq.py @@ -7,18 +7,7 @@ # The client should send a PINGREQ message after the appropriate amount of time # (4 seconds after no traffic). -import inspect -import os -import socket -import sys -import time - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/01-no-clean-session.py b/test/lib/01-no-clean-session.py index d5f46eb313..481b119004 100755 --- a/test/lib/01-no-clean-session.py +++ b/test/lib/01-no-clean-session.py @@ -5,17 +5,7 @@ # The client should connect to port 1888 with keepalive=60, clean session not # set, and client id 01-no-clean-session. -import inspect -import os -import socket -import sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/01-unpwd-set.py b/test/lib/01-unpwd-set.py index 454e417ac5..6dd0d4d5f2 100755 --- a/test/lib/01-unpwd-set.py +++ b/test/lib/01-unpwd-set.py @@ -5,17 +5,7 @@ # The client should connect to port 1888 with keepalive=60, clean session set, # client id 01-unpwd-set, username set to uname and password set to ;'[08gn=# -import inspect -import os -import socket -import sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/01-will-set.py b/test/lib/01-will-set.py index 63a8e2ea5d..c43f1f0802 100755 --- a/test/lib/01-will-set.py +++ b/test/lib/01-will-set.py @@ -7,17 +7,7 @@ # client id 01-will-set will topic set to topic/on/unexpected/disconnect , will # payload set to "will message", will qos set to 1 and will retain set. -import inspect -import os -import socket -import sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/01-will-unpwd-set.py b/test/lib/01-will-unpwd-set.py index 2a64bef785..e913237613 100755 --- a/test/lib/01-will-unpwd-set.py +++ b/test/lib/01-will-unpwd-set.py @@ -7,17 +7,7 @@ # set to "will message", will qos=2, will retain not set, username set to # "oibvvwqw" and password set to "#'^2hg9a&nm38*us". -import inspect -import os -import socket -import sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/02-subscribe-qos0.py b/test/lib/02-subscribe-qos0.py index f5f60d2fa7..737efa7770 100755 --- a/test/lib/02-subscribe-qos0.py +++ b/test/lib/02-subscribe-qos0.py @@ -12,17 +12,7 @@ # SUBACK message with the accepted QoS set to 0. On receiving the SUBACK # message, the client should send a DISCONNECT message. -import inspect -import os -import socket -import sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/02-subscribe-qos1.py b/test/lib/02-subscribe-qos1.py index 68ffa39dfb..5201bf0e09 100755 --- a/test/lib/02-subscribe-qos1.py +++ b/test/lib/02-subscribe-qos1.py @@ -12,17 +12,7 @@ # SUBACK message with the accepted QoS set to 1. On receiving the SUBACK # message, the client should send a DISCONNECT message. -import inspect -import os -import socket -import sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/02-subscribe-qos2.py b/test/lib/02-subscribe-qos2.py index 9a2864a51a..180c3b9d58 100755 --- a/test/lib/02-subscribe-qos2.py +++ b/test/lib/02-subscribe-qos2.py @@ -12,17 +12,7 @@ # SUBACK message with the accepted QoS set to 2. On receiving the SUBACK # message, the client should send a DISCONNECT message. -import inspect -import os -import socket -import sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/02-unsubscribe.py b/test/lib/02-unsubscribe.py index 8d9560cf40..abffc00a5a 100755 --- a/test/lib/02-unsubscribe.py +++ b/test/lib/02-unsubscribe.py @@ -2,17 +2,7 @@ # Test whether a client sends a correct UNSUBSCRIBE packet. -import inspect -import os -import socket -import sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/03-publish-b2c-qos1.py b/test/lib/03-publish-b2c-qos1.py index 4d6c475a3b..942ca4f740 100755 --- a/test/lib/03-publish-b2c-qos1.py +++ b/test/lib/03-publish-b2c-qos1.py @@ -11,18 +11,7 @@ # should handle this as per the spec by sending a PUBACK message. # The client should then exit with return code==0. -import inspect -import os -import socket -import sys -import time - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/03-publish-b2c-qos2.py b/test/lib/03-publish-b2c-qos2.py index a970ed55e7..8600c187da 100755 --- a/test/lib/03-publish-b2c-qos2.py +++ b/test/lib/03-publish-b2c-qos2.py @@ -16,18 +16,7 @@ # PUBREL message. The client should respond to this with the correct PUBCOMP # message and then exit with return code=0. -import inspect -import os -import socket -import sys -import time - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/03-publish-c2b-qos1-disconnect.py b/test/lib/03-publish-c2b-qos1-disconnect.py index 2111ae7cf6..87aa79ba9d 100755 --- a/test/lib/03-publish-c2b-qos1-disconnect.py +++ b/test/lib/03-publish-c2b-qos1-disconnect.py @@ -2,17 +2,7 @@ # Test whether a client sends a correct PUBLISH to a topic with QoS 1, then responds correctly to a disconnect. -import inspect -import os -import socket -import sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/03-publish-c2b-qos1-timeout.py b/test/lib/03-publish-c2b-qos1-timeout.py index 7cea7005c0..104961aa45 100755 --- a/test/lib/03-publish-c2b-qos1-timeout.py +++ b/test/lib/03-publish-c2b-qos1-timeout.py @@ -16,17 +16,7 @@ # PUBACK response. On receiving the correct PUBACK response, the client should # send a DISCONNECT message. -import inspect -import os -import socket -import sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/03-publish-c2b-qos2-disconnect.py b/test/lib/03-publish-c2b-qos2-disconnect.py index c9a5d526bd..dbd843db3c 100755 --- a/test/lib/03-publish-c2b-qos2-disconnect.py +++ b/test/lib/03-publish-c2b-qos2-disconnect.py @@ -2,17 +2,7 @@ # Test whether a client sends a correct PUBLISH to a topic with QoS 2 and responds to a disconnect. -import inspect -import os -import socket -import sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/03-publish-c2b-qos2-timeout.py b/test/lib/03-publish-c2b-qos2-timeout.py index 37031a9a0c..6831342310 100755 --- a/test/lib/03-publish-c2b-qos2-timeout.py +++ b/test/lib/03-publish-c2b-qos2-timeout.py @@ -20,17 +20,7 @@ # the test will send the correct PUBCOMP response. On receiving the correct # PUBCOMP response, the client should send a DISCONNECT message. -import inspect -import os -import socket -import sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/03-publish-c2b-qos2.py b/test/lib/03-publish-c2b-qos2.py index b27b6a065a..3a52b7677b 100755 --- a/test/lib/03-publish-c2b-qos2.py +++ b/test/lib/03-publish-c2b-qos2.py @@ -20,17 +20,7 @@ # the test will send the correct PUBCOMP response. On receiving the correct # PUBCOMP response, the client should send a DISCONNECT message. -import inspect -import os -import socket -import sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/03-publish-qos0-no-payload.py b/test/lib/03-publish-qos0-no-payload.py index b2185639b8..4a851d6296 100755 --- a/test/lib/03-publish-qos0-no-payload.py +++ b/test/lib/03-publish-qos0-no-payload.py @@ -10,17 +10,7 @@ # rc!=0, the client should exit with an error. # After sending the PUBLISH message, the client should send a DISCONNECT message. -import inspect -import os -import socket -import sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/03-publish-qos0.py b/test/lib/03-publish-qos0.py index 3f7adc9b80..dff2cb817c 100755 --- a/test/lib/03-publish-qos0.py +++ b/test/lib/03-publish-qos0.py @@ -10,17 +10,7 @@ # client should exit with an error. # After sending the PUBLISH message, the client should send a DISCONNECT message. -import inspect -import os -import socket -import sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/03-request-response-correlation.py b/test/lib/03-request-response-correlation.py index 43b055a18e..b1ed9ccd58 100755 --- a/test/lib/03-request-response-correlation.py +++ b/test/lib/03-request-response-correlation.py @@ -1,17 +1,6 @@ #!/usr/bin/env python -import inspect -import os -import socket -import sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test -import mqtt5_props +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/03-request-response.py b/test/lib/03-request-response.py index 6ff0486134..229bc8f9d5 100755 --- a/test/lib/03-request-response.py +++ b/test/lib/03-request-response.py @@ -1,17 +1,6 @@ #!/usr/bin/env python -import inspect -import os -import socket -import sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test -import mqtt5_props +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/04-retain-qos0.py b/test/lib/04-retain-qos0.py index cb495df183..485d771229 100755 --- a/test/lib/04-retain-qos0.py +++ b/test/lib/04-retain-qos0.py @@ -2,17 +2,7 @@ # Test whether a client sends a correct retained PUBLISH to a topic with QoS 0. -import inspect -import os -import socket -import sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/08-ssl-bad-cacert.py b/test/lib/08-ssl-bad-cacert.py index 20dc6fede8..025f66b960 100755 --- a/test/lib/08-ssl-bad-cacert.py +++ b/test/lib/08-ssl-bad-cacert.py @@ -1,15 +1,6 @@ #!/usr/bin/env python -import inspect -import os -import sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * if sys.version < '2.7': print("WARNING: SSL not supported on Python 2.6") diff --git a/test/lib/08-ssl-connect-cert-auth-enc.py b/test/lib/08-ssl-connect-cert-auth-enc.py index d49540fae7..2d321fc42a 100755 --- a/test/lib/08-ssl-connect-cert-auth-enc.py +++ b/test/lib/08-ssl-connect-cert-auth-enc.py @@ -10,18 +10,7 @@ # the CONNACK and verifying that rc=0, the client should send a DISCONNECT # message. If rc!=0, the client should exit with an error. -import inspect -import os -import socket -import ssl -import sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/08-ssl-connect-cert-auth.py b/test/lib/08-ssl-connect-cert-auth.py index f1485bb969..8f5f31d51e 100755 --- a/test/lib/08-ssl-connect-cert-auth.py +++ b/test/lib/08-ssl-connect-cert-auth.py @@ -10,18 +10,7 @@ # the CONNACK and verifying that rc=0, the client should send a DISCONNECT # message. If rc!=0, the client should exit with an error. -import inspect -import os -import socket -import ssl -import sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/08-ssl-connect-no-auth.py b/test/lib/08-ssl-connect-no-auth.py index 55c819622e..2499c31cec 100755 --- a/test/lib/08-ssl-connect-no-auth.py +++ b/test/lib/08-ssl-connect-no-auth.py @@ -9,18 +9,7 @@ # the CONNACK and verifying that rc=0, the client should send a DISCONNECT # message. If rc!=0, the client should exit with an error. -import inspect -import os -import socket -import ssl -import sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/08-ssl-fake-cacert.py b/test/lib/08-ssl-fake-cacert.py index 48967fd260..367cb47968 100755 --- a/test/lib/08-ssl-fake-cacert.py +++ b/test/lib/08-ssl-fake-cacert.py @@ -1,18 +1,6 @@ #!/usr/bin/env python -import inspect -import os -import socket -import ssl -import sys -import time - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/09-util-topic-tokenise.py b/test/lib/09-util-topic-tokenise.py index 6f8dc1228b..88974c2e18 100755 --- a/test/lib/09-util-topic-tokenise.py +++ b/test/lib/09-util-topic-tokenise.py @@ -1,14 +1,6 @@ #!/usr/bin/env python -import inspect -import os -import sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) -import mosq_test +from mosq_test_helper import * rc = 1 diff --git a/test/lib/11-prop-send-payload-format.py b/test/lib/11-prop-send-payload-format.py index 7e53699071..da6a61f051 100755 --- a/test/lib/11-prop-send-payload-format.py +++ b/test/lib/11-prop-send-payload-format.py @@ -10,18 +10,7 @@ # client should exit with an error. # After sending the PUBLISH message, the client should send a DISCONNECT message. -import inspect -import os -import socket -import sys - -# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder -cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) -if cmd_subfolder not in sys.path: - sys.path.insert(0, cmd_subfolder) - -import mosq_test -import mqtt5_props +from mosq_test_helper import * port = mosq_test.get_lib_port() diff --git a/test/lib/mosq_test_helper.py b/test/lib/mosq_test_helper.py new file mode 100644 index 0000000000..0e861dba07 --- /dev/null +++ b/test/lib/mosq_test_helper.py @@ -0,0 +1,15 @@ +import inspect, os, sys + +# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder +cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) +if cmd_subfolder not in sys.path: + sys.path.insert(0, cmd_subfolder) + +import mosq_test +import mqtt5_props + +import socket +import ssl +import struct +import subprocess +import time From d5108956bf99507d521246959913bc650133d971 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 27 Nov 2018 12:23:21 +0000 Subject: [PATCH 114/254] Process session-expiry-interval on CONNECT and DISCONNECT. Add test to check for invalid values. --- lib/mosquitto_internal.h | 1 + src/CMakeLists.txt | 1 + src/Makefile | 4 ++ src/handle_connect.c | 14 ++++ src/mosquitto_broker_internal.h | 6 ++ src/property_broker.c | 64 +++++++++++++++++++ test/broker/12-prop-session-expiry-invalid.py | 39 +++++++++++ test/broker/Makefile | 5 +- test/broker/ptest.py | 1 + test/broker/readme.txt | 5 ++ test/mosq_test.py | 15 +++-- 11 files changed, 149 insertions(+), 6 deletions(-) create mode 100644 src/property_broker.c create mode 100755 test/broker/12-prop-session-expiry-invalid.py diff --git a/lib/mosquitto_internal.h b/lib/mosquitto_internal.h index 1ca5f3c39e..55a537a77b 100644 --- a/lib/mosquitto_internal.h +++ b/lib/mosquitto_internal.h @@ -209,6 +209,7 @@ struct mosquitto { pthread_t thread_id; #endif bool clean_start; + uint32_t session_expiry_interval; #ifdef WITH_BROKER char *old_id; /* for when a duplicate client connects, but we still want to know what the id was */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3d93b2c5c6..e1eb6f4658 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,6 +31,7 @@ set (MOSQ_SRCS ../lib/packet_mosq.c ../lib/packet_mosq.h persist.c persist.h plugin.c + property_broker.c ../lib/property_mosq.c ../lib/property_mosq.h read_handle.c ../lib/read_handle.h diff --git a/src/Makefile b/src/Makefile index dcb92da4f3..07b917dd67 100644 --- a/src/Makefile +++ b/src/Makefile @@ -33,6 +33,7 @@ OBJS= mosquitto.o \ net_mosq.o \ packet_datatypes.o \ packet_mosq.o \ + property_broker.o \ property_mosq.o \ persist.o \ plugin.o \ @@ -141,6 +142,9 @@ packet_datatypes.o : ../lib/packet_datatypes.c ../lib/packet_mosq.h packet_mosq.o : ../lib/packet_mosq.c ../lib/packet_mosq.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ +property_broker.o : property_broker.c mosquitto_broker_internal.h + ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ + property_mosq.o : ../lib/property_mosq.c ../lib/property_mosq.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ diff --git a/src/handle_connect.c b/src/handle_connect.c index e0b50f7d3d..088ea051fc 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -254,6 +254,8 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) if(rc) return rc; mosquitto_property_free_all(&properties); } + property__process_connect(context, properties); + mosquitto_property_free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ if(packet__read_string(&context->in_packet, &client_id, &slen)){ @@ -727,9 +729,11 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) return rc; } + int handle__disconnect(struct mosquitto_db *db, struct mosquitto *context) { int rc; + uint8_t reason_code; mosquitto_property *properties = NULL; if(!context){ @@ -737,9 +741,19 @@ int handle__disconnect(struct mosquitto_db *db, struct mosquitto *context) } if(context->protocol == mosq_p_mqtt5){ + /* FIXME - must handle reason code */ + rc = packet__read_byte(&context->in_packet, &reason_code); + if(rc) return rc; rc = property__read_all(CMD_DISCONNECT, &context->in_packet, &properties); if(rc) return rc; + } + rc = property__process_disconnect(context, properties); + if(rc){ + if(rc == MOSQ_ERR_PROTOCOL){ + send__disconnect(context, MQTT_RC_PROTOCOL_ERROR, NULL); + } mosquitto_property_free_all(&properties); + return rc; } mosquitto_property_free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index 9c4439d365..3cfe07383c 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -608,6 +608,12 @@ int bridge__connect_step3(struct mosquitto_db *db, struct mosquitto *context); void bridge__packet_cleanup(struct mosquitto *context); #endif +/* ============================================================ + * Property related functions + * ============================================================ */ +int property__process_connect(struct mosquitto *context, mosquitto_property *props); +int property__process_disconnect(struct mosquitto *context, mosquitto_property *props); + /* ============================================================ * Security related functions * ============================================================ */ diff --git a/src/property_broker.c b/src/property_broker.c new file mode 100644 index 0000000000..e2f9d46646 --- /dev/null +++ b/src/property_broker.c @@ -0,0 +1,64 @@ +/* +Copyright (c) 2018 Roger Light + +All rights reserved. This program and the accompanying materials +are made available under the terms of the Eclipse Public License v1.0 +and Eclipse Distribution License v1.0 which accompany this distribution. + +The Eclipse Public License is available at + http://www.eclipse.org/legal/epl-v10.html +and the Eclipse Distribution License is available at + http://www.eclipse.org/org/documents/edl-v10.php. + +Contributors: + Roger Light - initial implementation and documentation. +*/ + +#include "config.h" + +#include +#include +#include + +#include "mosquitto_broker_internal.h" +#include "mqtt_protocol.h" +#include "property_mosq.h" + +/* Process the incoming properties, we should be able to assume that only valid + * properties for CONNECT are present here. */ +int property__process_connect(struct mosquitto *context, mosquitto_property *props) +{ + mosquitto_property *p; + + p = props; + + while(p){ + if(p->identifier == MQTT_PROP_SESSION_EXPIRY_INTERVAL){ + context->session_expiry_interval = p->value.i32; + } + p = p->next; + } + + return MOSQ_ERR_SUCCESS; +} + +/* Process the incoming properties, we should be able to assume that only valid + * properties for DISCONNECT are present here. */ +int property__process_disconnect(struct mosquitto *context, mosquitto_property *props) +{ + mosquitto_property *p; + + p = props; + + while(p){ + if(p->identifier == MQTT_PROP_SESSION_EXPIRY_INTERVAL){ + if(context->session_expiry_interval == 0 && p->value.i32 != 0){ + return MOSQ_ERR_PROTOCOL; + } + context->session_expiry_interval = p->value.i32; + } + p = p->next; + } + return MOSQ_ERR_SUCCESS; +} + diff --git a/test/broker/12-prop-session-expiry-invalid.py b/test/broker/12-prop-session-expiry-invalid.py new file mode 100755 index 0000000000..de31d0e637 --- /dev/null +++ b/test/broker/12-prop-session-expiry-invalid.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python + +# Test whether sending a non zero session expiry interval in DISCONNECT after +# having sent a zero session expiry interval is treated correctly in MQTT v5. + +from mosq_test_helper import * + +rc = 1 + +keepalive = 10 +props = mqtt5_props.gen_uint32_prop(mqtt5_props.PROP_SESSION_EXPIRY_INTERVAL, 0) +props = mqtt5_props.prop_finalise(props) +connect_packet = mosq_test.gen_connect("test", proto_ver=5, keepalive=keepalive, properties=props) + +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +props = mqtt5_props.gen_uint32_prop(mqtt5_props.PROP_SESSION_EXPIRY_INTERVAL, 1) +props = mqtt5_props.prop_finalise(props) +disconnect_client_packet = mosq_test.gen_disconnect(proto_ver=5, properties=props) + +disconnect_server_packet = mosq_test.gen_disconnect(proto_ver=5, reason_code=130) + +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, port=port) + mosq_test.do_send_receive(sock, disconnect_client_packet, disconnect_server_packet, "disconnect") + sock.close() + rc = 0 +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index 2d5237900b..0a90db09e2 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -15,7 +15,7 @@ test-compile : ptest : test-compile ./ptest.py -test : test-compile 01 02 03 04 05 06 07 08 09 10 11 +test : test-compile 01 02 03 04 05 06 07 08 09 10 11 12 01 : ./01-connect-success.py @@ -135,3 +135,6 @@ endif 11 : ./11-persistent-subscription.py + +12 : + ./12-prop-session-expiry-invalid.py diff --git a/test/broker/ptest.py b/test/broker/ptest.py index 7dfbaed5cf..ffb7b3ed4e 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -105,6 +105,7 @@ (2, './10-listener-mount-point.py'), (1, './11-persistent-subscription.py'), + (1, './12-prop-session-expiry-invalid.py'), ] minport = 1888 diff --git a/test/broker/readme.txt b/test/broker/readme.txt index 82eff27704..c31535deab 100644 --- a/test/broker/readme.txt +++ b/test/broker/readme.txt @@ -12,3 +12,8 @@ Numbering is as follows: 05: Clean session tests 06: Bridge tests 07: Will tests +08: TLS tests +09: Auth plugin tests +10: Listener tests +11: Persistence tests +12: Property tests diff --git a/test/mosq_test.py b/test/mosq_test.py index f2c7d3b7ed..cc3e926471 100644 --- a/test/mosq_test.py +++ b/test/mosq_test.py @@ -298,7 +298,7 @@ def to_string(packet): # Reserved return "0xF0" -def gen_connect(client_id, clean_session=True, keepalive=60, username=None, password=None, will_topic=None, will_qos=0, will_retain=False, will_payload="", proto_ver=4, connect_reserved=False, properties=None): +def gen_connect(client_id, clean_session=True, keepalive=60, username=None, password=None, will_topic=None, will_qos=0, will_retain=False, will_payload="", proto_ver=4, connect_reserved=False, properties=""): if (proto_ver&0x7F) == 3 or proto_ver == 0: remaining_length = 12 elif (proto_ver&0x7F) == 4 or proto_ver == 5: @@ -318,7 +318,9 @@ def gen_connect(client_id, clean_session=True, keepalive=60, username=None, pass connect_flags = connect_flags | 0x02 if proto_ver == 5: - remaining_length += 1 + if properties == "": + properties = struct.pack("B", 0) + remaining_length += len(properties) if will_topic != None: remaining_length = remaining_length + 2+len(will_topic) + 2+len(will_payload) @@ -341,7 +343,7 @@ def gen_connect(client_id, clean_session=True, keepalive=60, username=None, pass packet = packet + struct.pack("!H4sBBH", len("MQTT"), "MQTT", proto_ver, connect_flags, keepalive) if proto_ver == 5: - packet += struct.pack("B", 0) + packet += properties if client_id != None: packet = packet + struct.pack("!H"+str(len(client_id))+"s", len(client_id), client_id) @@ -467,9 +469,12 @@ def gen_pingreq(): def gen_pingresp(): return struct.pack('!BB', 208, 0) -def gen_disconnect(reason_code=0, proto_ver=4): +def gen_disconnect(reason_code=0, proto_ver=4, properties=""): if proto_ver == 5: - return struct.pack('!BBBB', 224, 2, reason_code, 0) + if properties == "": + properties = struct.pack("B", 0) + + return struct.pack('!BBB', 224, 1+len(properties), reason_code) + properties else: return struct.pack('!BB', 224, 0) From 1b854e250e0dec1885bd7c7513069acb38d752f0 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 28 Nov 2018 17:09:17 +0000 Subject: [PATCH 115/254] Function for copying property lists. --- lib/mosquitto.h | 15 +++++++ lib/property_mosq.c | 107 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) diff --git a/lib/mosquitto.h b/lib/mosquitto.h index 46fe350e5f..e641a8d14c 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -90,6 +90,7 @@ enum mosq_err_t { MOSQ_ERR_LOOKUP = 20, MOSQ_ERR_MALFORMED_PACKET = 19, MOSQ_ERR_DUPLICATE_PROPERTY = 20, + MOSQ_ERR_TLS_HANDSHAKE = 21, }; /* Error values */ @@ -2587,6 +2588,20 @@ libmosq_EXPORT int mosquitto_property_read_string_pair(const mosquitto_property */ libmosq_EXPORT void mosquitto_property_free_all(mosquitto_property **properties); +/* + * Function: mosquitto_property_copy_all + * + * Parameters: + * dest : pointer for new property list + * src : property list + * + * Returns: + * MOSQ_ERR_SUCCESS - on successful copy + * MOSQ_ERR_INVAL - if dest is NULL + * MOSQ_ERR_NOMEM - on out of memory (dest will be set to NULL) + */ +libmosq_EXPORT int mosquitto_property_copy_all(mosquitto_property **dest, const mosquitto_property *src); + /* * Function: mosquitto_property_check_command * diff --git a/lib/property_mosq.c b/lib/property_mosq.c index 46ab2d8a94..40fc3909b1 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -1020,3 +1020,110 @@ int mosquitto_property_read_string_pair(const mosquitto_property *property, char return MOSQ_ERR_SUCCESS; } + + +int mosquitto_property_copy_all(mosquitto_property **dest, const mosquitto_property *src) +{ + mosquitto_property *pnew, *plast = NULL; + + if(!src) return MOSQ_ERR_SUCCESS; + if(!dest) return MOSQ_ERR_INVAL; + + *dest = NULL; + + while(src){ + pnew = calloc(1, sizeof(mosquitto_property)); + if(!pnew){ + mosquitto_property_free_all(dest); + return MOSQ_ERR_NOMEM; + } + if(plast){ + plast->next = pnew; + }else{ + *dest = pnew; + } + plast = pnew; + + pnew->identifier = src->identifier; + switch(pnew->identifier){ + case MQTT_PROP_PAYLOAD_FORMAT_INDICATOR: + case MQTT_PROP_REQUEST_PROBLEM_INFORMATION: + case MQTT_PROP_REQUEST_RESPONSE_INFORMATION: + case MQTT_PROP_MAXIMUM_QOS: + case MQTT_PROP_RETAIN_AVAILABLE: + case MQTT_PROP_WILDCARD_SUB_AVAILABLE: + case MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE: + case MQTT_PROP_SHARED_SUB_AVAILABLE: + pnew->value.i8 = src->value.i8; + break; + + case MQTT_PROP_SERVER_KEEP_ALIVE: + case MQTT_PROP_RECEIVE_MAXIMUM: + case MQTT_PROP_TOPIC_ALIAS_MAXIMUM: + case MQTT_PROP_TOPIC_ALIAS: + pnew->value.i16 = src->value.i16; + break; + + case MQTT_PROP_MESSAGE_EXPIRY_INTERVAL: + case MQTT_PROP_SESSION_EXPIRY_INTERVAL: + case MQTT_PROP_WILL_DELAY_INTERVAL: + case MQTT_PROP_MAXIMUM_PACKET_SIZE: + pnew->value.i32 = src->value.i32; + break; + + case MQTT_PROP_SUBSCRIPTION_IDENTIFIER: + pnew->value.varint = src->value.varint; + break; + + case MQTT_PROP_CONTENT_TYPE: + case MQTT_PROP_RESPONSE_TOPIC: + case MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER: + case MQTT_PROP_AUTHENTICATION_METHOD: + case MQTT_PROP_RESPONSE_INFORMATION: + case MQTT_PROP_SERVER_REFERENCE: + case MQTT_PROP_REASON_STRING: + pnew->value.s.len = src->value.s.len; + pnew->value.s.v = strdup(src->value.s.v); + if(!pnew->value.s.v){ + mosquitto_property_free_all(dest); + return MOSQ_ERR_NOMEM; + } + break; + + case MQTT_PROP_AUTHENTICATION_DATA: + case MQTT_PROP_CORRELATION_DATA: + pnew->value.bin.len = src->value.bin.len; + pnew->value.bin.v = malloc(pnew->value.bin.len); + if(!pnew->value.bin.v){ + mosquitto_property_free_all(dest); + return MOSQ_ERR_NOMEM; + } + memcpy(pnew->value.bin.v, src->value.bin.v, pnew->value.bin.len); + break; + + case MQTT_PROP_USER_PROPERTY: + pnew->value.s.len = src->value.s.len; + pnew->value.s.v = strdup(src->value.s.v); + if(!pnew->value.s.v){ + mosquitto_property_free_all(dest); + return MOSQ_ERR_NOMEM; + } + + pnew->name.len = src->name.len; + pnew->name.v = strdup(src->name.v); + if(!pnew->name.v){ + mosquitto_property_free_all(dest); + return MOSQ_ERR_NOMEM; + } + break; + + default: + mosquitto_property_free_all(dest); + return MOSQ_ERR_INVAL; + } + + src = src->next; + } + + return MOSQ_ERR_SUCCESS; +} From 867fe80e0ec049c2c991c26c1af0ce5664f2b226 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 29 Nov 2018 16:51:48 +0000 Subject: [PATCH 116/254] Properties are now freed after the callback. --- lib/handle_connack.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/handle_connack.c b/lib/handle_connack.c index 75a5db8726..530e8bf614 100644 --- a/lib/handle_connack.c +++ b/lib/handle_connack.c @@ -44,7 +44,6 @@ int handle__connack(struct mosquitto *mosq) if(mosq->protocol == mosq_p_mqtt5){ rc = property__read_all(CMD_CONNACK, &mosq->in_packet, &properties); if(rc) return rc; - mosquitto_property_free_all(&properties); } log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received CONNACK (%d)", mosq->id, reason_code); From 7020fad86c5dee49b21e423aec2e60d400c03ed0 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 29 Nov 2018 17:19:26 +0000 Subject: [PATCH 117/254] Add server support for Assigned Client Identifier. --- src/handle_connect.c | 46 ++++++++++++++++++++------------- src/mosquitto_broker_internal.h | 2 +- src/send_connack.c | 21 +++++++++------ 3 files changed, 42 insertions(+), 27 deletions(-) diff --git a/src/handle_connect.c b/src/handle_connect.c index 088ea051fc..ad737b8fc1 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -132,6 +132,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) int i; struct mosquitto__security_options *security_opts; mosquitto_property *properties = NULL; + mosquitto_property *connack_props = NULL; #ifdef WITH_TLS X509 *client_cert = NULL; X509_NAME *name; @@ -179,7 +180,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) log__printf(NULL, MOSQ_LOG_INFO, "Invalid protocol version %d in CONNECT from %s.", protocol_version, context->address); } - send__connack(db, context, 0, CONNACK_REFUSED_PROTOCOL_VERSION); + send__connack(db, context, 0, CONNACK_REFUSED_PROTOCOL_VERSION, NULL); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } @@ -194,7 +195,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) log__printf(NULL, MOSQ_LOG_INFO, "Invalid protocol version %d in CONNECT from %s.", protocol_version, context->address); } - send__connack(db, context, 0, CONNACK_REFUSED_PROTOCOL_VERSION); + send__connack(db, context, 0, CONNACK_REFUSED_PROTOCOL_VERSION, NULL); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } @@ -238,7 +239,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) if(will && will_retain && db->config->retain_available == false){ if(protocol_version == mosq_p_mqtt5){ - send__connack(db, context, 0, MQTT_RC_RETAIN_NOT_SUPPORTED); + send__connack(db, context, 0, MQTT_RC_RETAIN_NOT_SUPPORTED, NULL); } rc = 1; goto handle_connect_error; @@ -265,7 +266,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) if(slen == 0){ if(context->protocol == mosq_p_mqtt31){ - send__connack(db, context, 0, CONNACK_REFUSED_IDENTIFIER_REJECTED); + send__connack(db, context, 0, CONNACK_REFUSED_IDENTIFIER_REJECTED, NULL); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; }else{ /* mqtt311/mqtt5 */ @@ -279,7 +280,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) allow_zero_length_clientid = db->config->security_options.allow_zero_length_clientid; } if(clean_start == 0 || allow_zero_length_clientid == false){ - send__connack(db, context, 0, CONNACK_REFUSED_IDENTIFIER_REJECTED); + send__connack(db, context, 0, CONNACK_REFUSED_IDENTIFIER_REJECTED, NULL); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; }else{ @@ -292,6 +293,12 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) rc = MOSQ_ERR_NOMEM; goto handle_connect_error; } + if(context->protocol == mosq_p_mqtt5){ + if(mosquitto_property_add_string(&connack_props, MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER, client_id)){ + rc = MOSQ_ERR_NOMEM; + goto handle_connect_error; + } + } } } } @@ -299,7 +306,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) /* clientid_prefixes check */ if(db->config->clientid_prefixes){ if(strncmp(db->config->clientid_prefixes, client_id, strlen(db->config->clientid_prefixes))){ - send__connack(db, context, 0, CONNACK_REFUSED_NOT_AUTHORIZED); + send__connack(db, context, 0, CONNACK_REFUSED_NOT_AUTHORIZED, NULL); rc = 1; goto handle_connect_error; } @@ -425,7 +432,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) password = NULL; if(!context->ssl){ - send__connack(db, context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); + send__connack(db, context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD, NULL); rc = 1; goto handle_connect_error; } @@ -433,7 +440,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) if(context->listener->psk_hint){ /* Client should have provided an identity to get this far. */ if(!context->username){ - send__connack(db, context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); + send__connack(db, context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD, NULL); rc = 1; goto handle_connect_error; } @@ -441,20 +448,20 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) #endif /* WITH_TLS_PSK */ client_cert = SSL_get_peer_certificate(context->ssl); if(!client_cert){ - send__connack(db, context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); + send__connack(db, context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD, NULL); rc = 1; goto handle_connect_error; } name = X509_get_subject_name(client_cert); if(!name){ - send__connack(db, context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); + send__connack(db, context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD, NULL); rc = 1; goto handle_connect_error; } if (context->listener->use_identity_as_username) { //use_identity_as_username i = X509_NAME_get_index_by_NID(name, NID_commonName, -1); if(i == -1){ - send__connack(db, context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); + send__connack(db, context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD, NULL); rc = 1; goto handle_connect_error; } @@ -462,19 +469,19 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) if(name_entry){ name_asn1 = X509_NAME_ENTRY_get_data(name_entry); if (name_asn1 == NULL) { - send__connack(db, context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); + send__connack(db, context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD, NULL); rc = 1; goto handle_connect_error; } context->username = mosquitto__strdup((char *) ASN1_STRING_data(name_asn1)); if(!context->username){ - send__connack(db, context, 0, CONNACK_REFUSED_SERVER_UNAVAILABLE); + send__connack(db, context, 0, CONNACK_REFUSED_SERVER_UNAVAILABLE, NULL); rc = MOSQ_ERR_NOMEM; goto handle_connect_error; } /* Make sure there isn't an embedded NUL character in the CN */ if ((size_t)ASN1_STRING_length(name_asn1) != strlen(context->username)) { - send__connack(db, context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); + send__connack(db, context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD, NULL); rc = 1; goto handle_connect_error; } @@ -518,7 +525,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) case MOSQ_ERR_SUCCESS: break; case MOSQ_ERR_AUTH: - send__connack(db, context, 0, CONNACK_REFUSED_NOT_AUTHORIZED); + send__connack(db, context, 0, CONNACK_REFUSED_NOT_AUTHORIZED, NULL); context__disconnect(db, context); rc = 1; goto handle_connect_error; @@ -539,7 +546,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) if((db->config->per_listener_settings && context->listener->security_options.allow_anonymous == false) || (!db->config->per_listener_settings && db->config->security_options.allow_anonymous == false)){ - send__connack(db, context, 0, CONNACK_REFUSED_NOT_AUTHORIZED); + send__connack(db, context, 0, CONNACK_REFUSED_NOT_AUTHORIZED, NULL); rc = 1; goto handle_connect_error; } @@ -557,7 +564,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) goto handle_connect_error; } }else{ - send__connack(db, context, 0, CONNACK_REFUSED_NOT_AUTHORIZED); + send__connack(db, context, 0, CONNACK_REFUSED_NOT_AUTHORIZED, NULL); rc = 1; goto handle_connect_error; } @@ -710,7 +717,9 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) } #endif context->state = mosq_cs_connected; - return send__connack(db, context, connect_ack, CONNACK_ACCEPTED); + rc = send__connack(db, context, connect_ack, CONNACK_ACCEPTED, connack_props); + mosquitto_property_free_all(&connack_props); + return rc; handle_connect_error: mosquitto__free(client_id); @@ -721,6 +730,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) if(will_struct){ mosquitto_property_free_all(&will_struct->properties); } + mosquitto_property_free_all(&connack_props); mosquitto__free(will_struct); #ifdef WITH_TLS if(client_cert) X509_free(client_cert); diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index 3cfe07383c..7a1b6bd753 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -512,7 +512,7 @@ int restore_privileges(void); /* ============================================================ * Server send functions * ============================================================ */ -int send__connack(struct mosquitto_db *db, struct mosquitto *context, int ack, int reason_code); +int send__connack(struct mosquitto_db *db, struct mosquitto *context, int ack, int reason_code, const mosquitto_property *properties); int send__suback(struct mosquitto *context, uint16_t mid, uint32_t payloadlen, const void *payload); int send__unsuback(struct mosquitto *context, uint16_t mid, const mosquitto_property *properties); diff --git a/src/send_connack.c b/src/send_connack.c index 0891af6056..1c20820c34 100644 --- a/src/send_connack.c +++ b/src/send_connack.c @@ -23,13 +23,18 @@ and the Eclipse Distribution License is available at #include "property_mosq.h" #include "util_mosq.h" -int send__connack(struct mosquitto_db *db, struct mosquitto *context, int ack, int reason_code) +int send__connack(struct mosquitto_db *db, struct mosquitto *context, int ack, int reason_code, const mosquitto_property *properties) { struct mosquitto__packet *packet = NULL; int rc; - mosquitto_property *properties = NULL; + mosquitto_property *connack_props = NULL; int proplen, varbytes; + rc = mosquitto_property_copy_all(&connack_props, properties); + if(rc){ + return rc; + } + if(context){ if(context->id){ log__printf(NULL, MOSQ_LOG_DEBUG, "Sending CONNACK to %s (%d, %d)", context->id, ack, reason_code); @@ -45,25 +50,25 @@ int send__connack(struct mosquitto_db *db, struct mosquitto *context, int ack, i packet->remaining_length = 2; if(context->protocol == mosq_p_mqtt5){ if(reason_code < 128 && db->config->retain_available == false){ - rc = mosquitto_property_add_byte(&properties, MQTT_PROP_RETAIN_AVAILABLE, 0); + rc = mosquitto_property_add_byte(&connack_props, MQTT_PROP_RETAIN_AVAILABLE, 0); if(rc){ mosquitto__free(packet); return rc; } } /* FIXME - disable support until available */ - rc = mosquitto_property_add_byte(&properties, MQTT_PROP_SHARED_SUB_AVAILABLE, 0); + rc = mosquitto_property_add_byte(&connack_props, MQTT_PROP_SHARED_SUB_AVAILABLE, 0); if(rc){ mosquitto__free(packet); return rc; } - rc = mosquitto_property_add_byte(&properties, MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE, 0); + rc = mosquitto_property_add_byte(&connack_props, MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE, 0); if(rc){ mosquitto__free(packet); return rc; } - proplen = property__get_length_all(properties); + proplen = property__get_length_all(connack_props); varbytes = packet__varint_bytes(proplen); packet->remaining_length += proplen + varbytes; } @@ -75,9 +80,9 @@ int send__connack(struct mosquitto_db *db, struct mosquitto *context, int ack, i packet__write_byte(packet, ack); packet__write_byte(packet, reason_code); if(context->protocol == mosq_p_mqtt5){ - property__write_all(packet, properties); + property__write_all(packet, connack_props); } - mosquitto_property_free_all(&properties); + mosquitto_property_free_all(&connack_props); return packet__queue(context, packet); } From 44135bc680927761573c4ac52b39e912f341b1b2 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 29 Nov 2018 22:54:25 +0000 Subject: [PATCH 118/254] Web: Roadmap and MQTT 5 updates. --- www/README.md | 3 ++ www/conf.py | 1 + www/pages/roadmap.md | 81 +++++++++++++++++++++++++++++ www/posts/2018/11/mqtt5-progress.md | 59 +++++++++++++++++++++ 4 files changed, 144 insertions(+) create mode 100644 www/README.md create mode 100644 www/pages/roadmap.md create mode 100644 www/posts/2018/11/mqtt5-progress.md diff --git a/www/README.md b/www/README.md new file mode 100644 index 0000000000..923f54bfec --- /dev/null +++ b/www/README.md @@ -0,0 +1,3 @@ +This is the mosquitto website, it can be built with `nikola`: + +`nikola build` \ No newline at end of file diff --git a/www/conf.py b/www/conf.py index b41452372a..7b5f4ded55 100644 --- a/www/conf.py +++ b/www/conf.py @@ -87,6 +87,7 @@ #("/sponsoring/", "Sponsoring"), ( ( + ("/roadmap/", "Roadmap"), ("/api/", "API"), ("/man/libmosquitto-3.html", "libmosquitto"), ("/man/mosquitto-8.html", "mosquitto"), diff --git a/www/pages/roadmap.md b/www/pages/roadmap.md new file mode 100644 index 0000000000..7e607cf7f0 --- /dev/null +++ b/www/pages/roadmap.md @@ -0,0 +1,81 @@ + + +# Roadmap + +## Version 1.6 + +The next minor release. The focus of this release is on providing support for +version 5 of the MQTT protocol. + +This release will provide a feature complete implementation, but does not +represent the final interface for all features. In particular, functions are +being added to libmosquitto to provide support for MQTT 5 features, but these +will be consolidated with the API changes planned for version 2.0. + +### Deprecation notices + +#### libmosquittopp + +libmosquittopp, the C++ wrapper around libmosquitto is now deprecated and will +be removed in the next major release (2.0). The wrapper came about by an +external request and at the time it was created there were no other C++ +solutions for MQTT. This has changed in the past years and this wrapper +provides no benefit over true C++ libraries or using the pure C libmosquitto. + +#### libmosquitto API changes + +The Mosquitto project has maintained API and ABI compatibility in libmosquitto +since version 1.0, and has dealt with the introduction of new specification +features by adding new functions which duplicate the behaviour of existing +functions, but with additional arguments to support the new features. +Particularly with regards to adding support for MQTT version 5, this has lead +to a proliferation of functions which offer small variations on a theme. + +The libmosquitto functions listed below (which includes some new functions +included in 1.6) are going to be updated for version 2.0. Functions not listed +here should still be considered at risk of being updated. + +* mosquitto\_will\_set +* mosquitto\_connect\* +* mosquitto\_reconnect\* +* mosquitto\_disconnect +* mosquitto\_publish\* +* mosquitto\_subscribe\* +* mosquitto\_unsubscribe\* +* mosquitto\_loop\* +* mosquitto\_\*\_callback\_set +* All callbacks +* mosquitto\_\*\_topic\_check\* + + +## Version 2.0 + +This is the next major release and includes breaking changes. Other features +planned include: + +## Disk persistence improvements + +A new disk persistence interface will be created to allow persistence to occur +immediately, rather than periodically. This will allow queued messages for +disconnected clients to be removed from memory, and reduce the periodic pause +caused when writing the persistence file. + +## Breaking changes + +### libmosquitto + +The libmosquitto API is being consolidated to better support the new MQTT 5 +features whilst reducing the number of function variants. + +### libmosquittopp + +The C++ wrapper around libmosquitto will be removed in this release. diff --git a/www/posts/2018/11/mqtt5-progress.md b/www/posts/2018/11/mqtt5-progress.md new file mode 100644 index 0000000000..2b27e82172 --- /dev/null +++ b/www/posts/2018/11/mqtt5-progress.md @@ -0,0 +1,59 @@ + + +Development of support for MQTT 5 is ongoing and making good progress, but has +been substantially delayed due to other non-Mosquitto work having to take +priority. + +It is possible to test the current state of MQTT 5 support by using the `mqtt5` +branch of the [repository]. Please note that this is very much a work in +progress, so parts are incomplete and interfaces may yet change. The client +library in particular has had to have an increase in functions available in +order to provide the features needed whilst providing backwards compatibility. +Part of the plan for the 2.0 release, which will follow after 1.6, is to +consolidate the libmosquitto API with breaking changes. There are more details +on the [roadmap]. + +Current features include: + +* Support for all incoming and outgoing packets, although not everything is + processed. +* Support for sending and receiving all properties, with not all properties + processed. +* Client support for setting properties +* Request/response support (client cannot process incoming correlation data) +* Retain availability +* Message expiry interval support +* Server support for assigned client identifiers +* Payload format indicator support +* Content-type support +* Basic topic alias support from client to broker +* Lots of new tests + +Both `mosquitto_pub` and `mosquitto_sub` support setting properties on the +command line, for example: + +``` +mosquitto_sub -t topic -v -D connect session-expiry-interval 60 -D connect user-property key value -D subscribe user-property sub-key sub-value +``` + +``` +mosquitto_pub -t topic -m '{"key":"value"}' -D publish content-type "application/json" +``` + +``` +./sensor_read.sh | mosquitto_pub -t topic -l -D publish topic-alias 1 +``` + +Further updates will be posted when more features are available. + +[repository]: https://github.com/eclipse/mosquitto/tree/mqtt5 +[roadmap]: https://mosquitto.org/roadmap/ \ No newline at end of file From 34293d07c1739d45588f30dacd4b3badd93efc54 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 4 Dec 2018 09:24:04 +0000 Subject: [PATCH 119/254] Always print leading zeros in mosquitto_sub when output format is hex. Closes #1066. Thanks to skiizo. Bug: https://github.com/eclipse/mosquitto/issues/1066 --- ChangeLog.txt | 8 ++++++++ client/sub_client_output.c | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index cc35d767be..d6942a0d71 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,11 @@ +1.5.5 - 201812xx +================ + +Client: +- Always print leading zeros in mosquitto_sub when output format is hex. + Closes #1066. + + 1.5.4 - 20181108 ================ diff --git a/client/sub_client_output.c b/client/sub_client_output.c index ab3f5e963a..4aeb8c3966 100644 --- a/client/sub_client_output.c +++ b/client/sub_client_output.c @@ -85,11 +85,11 @@ static void write_payload(const unsigned char *payload, int payloadlen, int hex) (void)fwrite(payload, 1, payloadlen, stdout); }else if(hex == 1){ for(i=0; i Date: Tue, 4 Dec 2018 10:51:41 +0000 Subject: [PATCH 120/254] Tidy up unused Windows installer pages. --- installer/mosquitto.nsi | 36 +++++------------------------------- installer/mosquitto64.nsi | 36 +++++------------------------------- 2 files changed, 10 insertions(+), 62 deletions(-) diff --git a/installer/mosquitto.nsi b/installer/mosquitto.nsi index 34143f8523..d7db79b825 100644 --- a/installer/mosquitto.nsi +++ b/installer/mosquitto.nsi @@ -18,8 +18,7 @@ InstallDir "$PROGRAMFILES\mosquitto" ; Installer pages !insertmacro MUI_PAGE_WELCOME -Page custom DependencyPage -!insertmacro MUI_PAGE_COMPONENTS +;!insertmacro MUI_PAGE_COMPONENTS !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_FINISH @@ -55,8 +54,8 @@ Section "Files" SecInstall File "..\readme.md" File "..\readme-windows.txt" ;File "C:\pthreads\Pre-built.2\dll\x86\pthreadVC2.dll" - ;File "C:\OpenSSL-Win32\bin\libssl_1-1.dll" - ;File "C:\OpenSSL-Win32\bin\libcrypto_1-1.dll" + File "C:\OpenSSL-Win32\bin\libssl-1_1.dll" + File "C:\OpenSSL-Win32\bin\libcrypto-1_1.dll" File "..\edl-v10" File "..\epl-v10" @@ -96,8 +95,8 @@ Section "Uninstall" Delete "$INSTDIR\readme.txt" Delete "$INSTDIR\readme-windows.txt" ;Delete "$INSTDIR\pthreadVC2.dll" - ;Delete "$INSTDIR\libssl_1-1.dll" - ;Delete "$INSTDIR\libcrypto_1-1.dll" + Delete "$INSTDIR\libssl-1_1.dll" + Delete "$INSTDIR\libcrypto-1_1.dll" Delete "$INSTDIR\edl-v10" Delete "$INSTDIR\epl-v10" @@ -120,28 +119,3 @@ LangString DESC_SecInstall ${LANG_ENGLISH} "The main installation." !insertmacro MUI_DESCRIPTION_TEXT ${SecInstall} $(DESC_SecInstall) !insertmacro MUI_FUNCTION_DESCRIPTION_END -Var Dialog -Var OSSLLink -Var PTHLink - -Function DependencyPage - nsDialogs::Create 1018 - Pop $Dialog - - ${If} $Dialog == error - Abort - ${EndIf} - - ${NSD_CreateLabel} 0 0 100% 12u "OpenSSL - install 'Win32 OpenSSL v1.1.0* Light' then copy libssl_1-1.dll and libcrypto_1-1.dll to the mosquitto directory" - ${NSD_CreateLink} 13u 13u 100% 12u "http://slproweb.com/products/Win32OpenSSL.html" - Pop $OSSLLink - ${NSD_OnClick} $OSSLLink OnClick_OSSL - - !insertmacro MUI_HEADER_TEXT_PAGE "Dependencies" "This page lists packages that must be installed if not already present" - nsDialogs::Show -FunctionEnd - -Function OnClick_OSSL - Pop $0 - ExecShell "open" "http://slproweb.com/products/Win32OpenSSL.html" -FunctionEnd diff --git a/installer/mosquitto64.nsi b/installer/mosquitto64.nsi index 097f4521a4..7ae8dccd0c 100644 --- a/installer/mosquitto64.nsi +++ b/installer/mosquitto64.nsi @@ -19,8 +19,7 @@ InstallDir "$PROGRAMFILES64\mosquitto" ; Installer pages !insertmacro MUI_PAGE_WELCOME -Page custom DependencyPage -!insertmacro MUI_PAGE_COMPONENTS +;!insertmacro MUI_PAGE_COMPONENTS !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_FINISH @@ -56,8 +55,8 @@ Section "Files" SecInstall File "..\readme.md" File "..\readme-windows.txt" ;File "C:\pthreads\Pre-built.2\dll\x64\pthreadVC2.dll" - ;File "C:\OpenSSL-Win64\bin\libssl_1-1-x64.dll" - ;File "C:\OpenSSL-Win64\bin\libcrypto_1-1-x64.dll" + File "C:\OpenSSL-Win64\bin\libssl-1_1-x64.dll" + File "C:\OpenSSL-Win64\bin\libcrypto-1_1-x64.dll" File "..\edl-v10" File "..\epl-v10" @@ -97,8 +96,8 @@ Section "Uninstall" Delete "$INSTDIR\readme.txt" Delete "$INSTDIR\readme-windows.txt" ;Delete "$INSTDIR\pthreadVC2.dll" - ;Delete "$INSTDIR\libssl_1-1-x64.dll" - ;Delete "$INSTDIR\libcrypto_1-1-x64.dll" + Delete "$INSTDIR\libssl-1_1-x64.dll" + Delete "$INSTDIR\libcrypto-1_1-x64.dll" Delete "$INSTDIR\edl-v10" Delete "$INSTDIR\epl-v10" @@ -121,28 +120,3 @@ LangString DESC_SecInstall ${LANG_ENGLISH} "The main installation." !insertmacro MUI_DESCRIPTION_TEXT ${SecInstall} $(DESC_SecInstall) !insertmacro MUI_FUNCTION_DESCRIPTION_END -Var Dialog -Var OSSLLink -Var PTHLink - -Function DependencyPage - nsDialogs::Create 1018 - Pop $Dialog - - ${If} $Dialog == error - Abort - ${EndIf} - - ${NSD_CreateLabel} 0 0 100% 12u "OpenSSL - install 'Win64 OpenSSL v1.1.0* Light' then copy libssl_1-1-x64.dll and libcrypto_1-1-x64.dll to the mosquitto directory" - ${NSD_CreateLink} 13u 13u 100% 12u "http://slproweb.com/products/Win32OpenSSL.html" - Pop $OSSLLink - ${NSD_OnClick} $OSSLLink OnClick_OSSL - - !insertmacro MUI_HEADER_TEXT_PAGE "Dependencies" "This page lists packages that must be installed if not already present" - nsDialogs::Show -FunctionEnd - -Function OnClick_OSSL - Pop $0 - ExecShell "open" "http://slproweb.com/products/Win32OpenSSL.html" -FunctionEnd From 8509dde34253093d8f77f46b5806fd32e6e663d8 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 20 Nov 2018 11:30:44 +0000 Subject: [PATCH 121/254] Make docker uid/gid explicit. Closes #1034. Thanks to Daniele Sluijters. --- docker/1.5/Dockerfile | 4 ++-- docker/1.5/README.md | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/docker/1.5/Dockerfile b/docker/1.5/Dockerfile index 0f480effb3..5661fb35b5 100644 --- a/docker/1.5/Dockerfile +++ b/docker/1.5/Dockerfile @@ -67,8 +67,8 @@ RUN set -x && \ WITH_WEBSOCKETS=yes \ prefix=/usr \ binary && \ - addgroup -S mosquitto 2>/dev/null && \ - adduser -S -D -H -h /var/empty -s /sbin/nologin -G mosquitto -g mosquitto mosquitto 2>/dev/null && \ + addgroup -S -g 1883 mosquitto 2>/dev/null && \ + adduser -S -u 1883 -D -H -h /var/empty -s /sbin/nologin -G mosquitto -g mosquitto mosquitto 2>/dev/null && \ mkdir -p /mosquitto/config /mosquitto/data /mosquitto/log && \ install -d /usr/sbin/ && \ install -s -m755 /build/mosq/src/mosquitto /usr/sbin/mosquitto && \ diff --git a/docker/1.5/README.md b/docker/1.5/README.md index 6a8c17949c..27b05904c9 100644 --- a/docker/1.5/README.md +++ b/docker/1.5/README.md @@ -13,6 +13,11 @@ Two docker volumes have been created in the image to be used for persistent stor /mosquitto/log ``` +## User/Group + +The image runs mosqutto under the mosquitto user and group, which are created +with a uid and gid of 1883. + ## Configuration When creating a container from the image, the default configuration values are used. To use a custom configuration file, mount a **local** configuration file to `/mosquitto/config/mosquitto.conf` From d29dac087d42f6a2ac744c446845fe58ca55a683 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 20 Nov 2018 12:23:27 +0000 Subject: [PATCH 122/254] Add socket_domain option. --- ChangeLog.txt | 6 ++++++ man/mosquitto.conf.5.xml | 21 +++++++++++++++++++++ src/conf.c | 18 ++++++++++++++++++ src/mosquitto_broker_internal.h | 1 + src/net.c | 6 +++++- src/websockets.c | 3 +++ 6 files changed, 54 insertions(+), 1 deletion(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index d6942a0d71..cfe54fc21d 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,6 +1,12 @@ 1.5.5 - 201812xx ================ +Broker: +- Add `socket_domain` option to allow listeners to disable IPv6 support. + This is required to work around a problem in libwebsockets that means + sockets only listen on IPv6 by default if IPv6 support is compiled in. + Closes #1004. + Client: - Always print leading zeros in mosquitto_sub when output format is hex. Closes #1066. diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml index a6bf0c99a2..d5dcc50b65 100644 --- a/man/mosquitto.conf.5.xml +++ b/man/mosquitto.conf.5.xml @@ -813,6 +813,27 @@ Not reloaded on reload signal. + + [ ipv4 | ipv6 ] + + By default, a listener will attempt to listen on + all supported IP protocol versions. If you do not + have an IPv4 or IPv6 interface you may wish to + disable support for either of those protocol + versions. In particular, note that due to the + limitations of the websockets library, it will only + ever attempt to open IPv6 sockets if IPv6 support + is compiled in, and so will fail if IPv6 is not + available. + Set to to force the + listener to only use IPv4, or set to + to force the listener to only + use IPv6. If you want support for both IPv4 and + IPv6, then do not use the + option. + Not reloaded on reload signal. + + [ true | false ] diff --git a/src/conf.c b/src/conf.c index 0b1d79cfe9..c6bd897cb9 100644 --- a/src/conf.c +++ b/src/conf.c @@ -446,6 +446,7 @@ int config__parse_args(struct mosquitto_db *db, struct mosquitto__config *config || config->default_listener.max_connections != -1 || config->default_listener.mount_point || config->default_listener.protocol != mp_mqtt + || config->default_listener.socket_domain || config->default_listener.security_options.password_file || config->default_listener.security_options.psk_file || config->default_listener.security_options.auth_plugin_config_count @@ -476,6 +477,7 @@ int config__parse_args(struct mosquitto_db *db, struct mosquitto__config *config } config->listeners[config->listener_count-1].max_connections = config->default_listener.max_connections; config->listeners[config->listener_count-1].protocol = config->default_listener.protocol; + config->listeners[config->listener_count-1].socket_domain = config->default_listener.socket_domain; config->listeners[config->listener_count-1].client_count = 0; config->listeners[config->listener_count-1].socks = NULL; config->listeners[config->listener_count-1].sock_count = 0; @@ -1773,6 +1775,22 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct #else log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif + }else if(!strcmp(token, "socket_domain")){ + if(reload) continue; // Listeners not valid for reloading. + token = strtok_r(NULL, " ", &saveptr); + if(token){ + if(!strcmp(token, "ipv4")){ + cur_listener->socket_domain = AF_INET; + }else if(!strcmp(token, "ipv6")){ + cur_listener->socket_domain = AF_INET6; + }else{ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid socket_domain value \"%s\" in configuration.", token); + return MOSQ_ERR_INVAL; + } + }else{ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Empty socket_domain value in configuration."); + return MOSQ_ERR_INVAL; + } }else if(!strcmp(token, "store_clean_interval")){ log__printf(NULL, MOSQ_LOG_WARNING, "Warning: store_clean_interval is no longer needed."); }else if(!strcmp(token, "sys_interval")){ diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index 67a2924cbb..bd6ad13655 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -218,6 +218,7 @@ struct mosquitto__listener { int sock_count; int client_count; enum mosquitto_protocol protocol; + int socket_domain; bool use_username_as_clientid; #ifdef WITH_TLS char *cafile; diff --git a/src/net.c b/src/net.c index 08f2b824fa..21f5ec6893 100644 --- a/src/net.c +++ b/src/net.c @@ -391,7 +391,11 @@ int net__socket_listen(struct mosquitto__listener *listener) snprintf(service, 10, "%d", listener->port); memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_UNSPEC; + if(listener->socket_domain){ + hints.ai_family = listener->socket_domain; + }else{ + hints.ai_family = AF_UNSPEC; + } hints.ai_flags = AI_PASSIVE; hints.ai_socktype = SOCK_STREAM; diff --git a/src/websockets.c b/src/websockets.c index bf2804b8d2..a57330aabe 100644 --- a/src/websockets.c +++ b/src/websockets.c @@ -729,6 +729,9 @@ struct libwebsocket_context *mosq_websockets_init(struct mosquitto__listener *li #if LWS_LIBRARY_VERSION_MAJOR>1 info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; #endif + if(listener->socket_domain == AF_INET){ + info.options |= LWS_SERVER_OPTION_DISABLE_IPV6; + } user = mosquitto__calloc(1, sizeof(struct libws_mqtt_hack)); if(!user){ From e169f1c7c2d190c5dadd1f7d7e5d7c874d58ad1b Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 4 Dec 2018 12:39:00 +0000 Subject: [PATCH 123/254] When using ADNS, don't ask for all network protocols when connecting. This can lead to confusing "Protocol not supported" errors if the network is down, because UDP sockets are provided. Thanks to jsaak. Closes #1062. Bug: https://github.com/eclipse/mosquitto/issues/1062 --- ChangeLog.txt | 3 +++ lib/net_mosq.c | 23 +++++++++++++++++++++-- src/context.c | 7 +++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index cfe54fc21d..953a2b3cd7 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -6,6 +6,9 @@ Broker: This is required to work around a problem in libwebsockets that means sockets only listen on IPv6 by default if IPv6 support is compiled in. Closes #1004. +- When using ADNS, don't ask for all network protocols when connecting, + because this can lead to confusing "Protocol not supported" errors if the + network is down. Closes #1062. Client: - Always print leading zeros in mosquitto_sub when output format is hex. diff --git a/lib/net_mosq.c b/lib/net_mosq.c index 4efda3d2f8..f2bb628bc1 100644 --- a/lib/net_mosq.c +++ b/lib/net_mosq.c @@ -208,21 +208,39 @@ int net__try_connect_step1(struct mosquitto *mosq, const char *host) { int s; void *sevp = NULL; + struct addrinfo *hints; if(mosq->adns){ + gai_cancel(mosq->adns); + mosquitto__free((struct addrinfo *)mosq->adns->ar_request); mosquitto__free(mosq->adns); } mosq->adns = mosquitto__calloc(1, sizeof(struct gaicb)); if(!mosq->adns){ return MOSQ_ERR_NOMEM; } + + hints = mosquitto__calloc(1, sizeof(struct addrinfo)); + if(!hints){ + mosquitto__free(mosq->adns); + mosq->adns = NULL; + return MOSQ_ERR_NOMEM; + } + + hints->ai_family = AF_UNSPEC; + hints->ai_socktype = SOCK_STREAM; + mosq->adns->ar_name = host; + mosq->adns->ar_request = hints; s = getaddrinfo_a(GAI_NOWAIT, &mosq->adns, 1, sevp); if(s){ errno = s; - mosquitto__free(mosq->adns); - mosq->adns = NULL; + if(mosq->adns){ + mosquitto__free((struct addrinfo *)mosq->adns->ar_request); + mosquitto__free(mosq->adns); + mosq->adns = NULL; + } return MOSQ_ERR_EAI; } @@ -278,6 +296,7 @@ int net__try_connect_step2(struct mosquitto *mosq, uint16_t port, mosq_sock_t *s freeaddrinfo(mosq->adns->ar_result); mosq->adns->ar_result = NULL; + mosquitto__free((struct addrinfo *)mosq->adns->ar_request); mosquitto__free(mosq->adns); mosq->adns = NULL; diff --git a/src/context.c b/src/context.c index 1d3ae1633e..e8cbfdfc45 100644 --- a/src/context.c +++ b/src/context.c @@ -197,6 +197,13 @@ void context__cleanup(struct mosquitto_db *db, struct mosquitto *context, bool d context->queued_msgs = NULL; context->last_queued_msg = NULL; } +#if defined(WITH_BROKER) && defined(__GLIBC__) && defined(WITH_ADNS) + if(context->adns){ + gai_cancel(context->adns); + mosquitto__free((struct addrinfo *)context->adns->ar_request); + mosquitto__free(context->adns); + } +#endif if(do_free){ mosquitto__free(context); } From 5d02f5815181aae427949641e3a612c3e4daa01b Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 4 Dec 2018 17:19:31 +0000 Subject: [PATCH 124/254] Fix reconnect delay backoff behaviour. Closes #1027. Thanks to Harm Verhagen. Bug: https://github.com/eclipse/mosquitto/issues/1027 --- ChangeLog.txt | 3 +++ lib/loop.c | 8 ++++++-- lib/options.c | 2 ++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 953a2b3cd7..969c6c2a3e 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -10,6 +10,9 @@ Broker: because this can lead to confusing "Protocol not supported" errors if the network is down. Closes #1062. +Library: +- Fix reconnect delay backoff behaviour. Closes #1027. + Client: - Always print leading zeros in mosquitto_sub when output format is hex. Closes #1066. diff --git a/lib/loop.c b/lib/loop.c index 23e60825e0..349ee5dc4b 100644 --- a/lib/loop.c +++ b/lib/loop.c @@ -245,8 +245,12 @@ int mosquitto_loop_forever(struct mosquitto *mosq, int timeout, int max_packets) }else{ pthread_mutex_unlock(&mosq->state_mutex); - if(mosq->reconnect_delay > 0 && mosq->reconnect_exponential_backoff){ - reconnect_delay = mosq->reconnect_delay*reconnects*reconnects; + if(mosq->reconnect_delay_max > mosq->reconnect_delay){ + if(mosq->reconnect_exponential_backoff){ + reconnect_delay = mosq->reconnect_delay*(reconnects+1)*(reconnects+1); + }else{ + reconnect_delay = mosq->reconnect_delay*(reconnects+1); + } }else{ reconnect_delay = mosq->reconnect_delay; } diff --git a/lib/options.c b/lib/options.c index dd9f718099..00951a6877 100644 --- a/lib/options.c +++ b/lib/options.c @@ -76,6 +76,8 @@ int mosquitto_reconnect_delay_set(struct mosquitto *mosq, unsigned int reconnect { if(!mosq) return MOSQ_ERR_INVAL; + if(reconnect_delay == 0) reconnect_delay = 1; + mosq->reconnect_delay = reconnect_delay; mosq->reconnect_delay_max = reconnect_delay_max; mosq->reconnect_exponential_backoff = reconnect_exponential_backoff; From 464b12f3d6e3949fd5b1d28560489315c603f5a2 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 4 Dec 2018 20:45:15 +0000 Subject: [PATCH 125/254] Fix outgoing retained messages not being sent by bridges. This now happens on initial connection, after CONNACK is processed, before it was happening (and being dropped) before the connection was made. Closes #1040. Thanks to giover. Bug: https://github.com/eclipse/mosquitto/issues/1040 --- ChangeLog.txt | 2 ++ src/bridge.c | 10 ---------- src/handle_connack.c | 9 +++++++++ 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 969c6c2a3e..f79c5277f5 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -9,6 +9,8 @@ Broker: - When using ADNS, don't ask for all network protocols when connecting, because this can lead to confusing "Protocol not supported" errors if the network is down. Closes #1062. +- Fix outgoing retained messages not being sent by bridges on initial + connection. Closes #1040. Library: - Fix reconnect delay backoff behaviour. Closes #1027. diff --git a/src/bridge.c b/src/bridge.c index a3f2ed7dd5..e35cacced3 100644 --- a/src/bridge.c +++ b/src/bridge.c @@ -141,16 +141,6 @@ int bridge__connect_step1(struct mosquitto_db *db, struct mosquitto *context) */ sub__clean_session(db, context); - for(i=0; ibridge->topic_count; i++){ - if(context->bridge->topics[i].direction == bd_out || context->bridge->topics[i].direction == bd_both){ - log__printf(NULL, MOSQ_LOG_DEBUG, "Bridge %s doing local SUBSCRIBE on topic %s", context->id, context->bridge->topics[i].local_topic); - if(sub__add(db, context, context->bridge->topics[i].local_topic, context->bridge->topics[i].qos, &db->subs)) return 1; - sub__retain_queue(db, context, - context->bridge->topics[i].local_topic, - context->bridge->topics[i].qos); - } - } - if(context->bridge->notifications){ if(context->bridge->notification_topic){ if(!context->bridge->initial_notification_done){ diff --git a/src/handle_connack.c b/src/handle_connack.c index 52e78e4f2c..9e16e4d4fe 100644 --- a/src/handle_connack.c +++ b/src/handle_connack.c @@ -90,6 +90,15 @@ int handle__connack(struct mosquitto_db *db, struct mosquitto *context) } } } + for(i=0; ibridge->topic_count; i++){ + if(context->bridge->topics[i].direction == bd_out || context->bridge->topics[i].direction == bd_both){ + log__printf(NULL, MOSQ_LOG_DEBUG, "Bridge %s doing local SUBSCRIBE on topic %s", context->id, context->bridge->topics[i].local_topic); + if(sub__add(db, context, context->bridge->topics[i].local_topic, context->bridge->topics[i].qos, &db->subs)) return 1; + sub__retain_queue(db, context, + context->bridge->topics[i].local_topic, + context->bridge->topics[i].qos); + } + } } context->state = mosq_cs_connected; return MOSQ_ERR_SUCCESS; From c9ed2708f644206c3d8f32b3384c514afcb2f323 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 4 Dec 2018 20:51:25 +0000 Subject: [PATCH 126/254] Don't reload auth_opt_ options on reload. This matches the behaviour of the other plugin options. Closes #1068. Thanks to Jason McFadyen. Bug: https://github.com/eclipse/mosquitto/issues/1068 --- ChangeLog.txt | 2 ++ src/conf.c | 1 + 2 files changed, 3 insertions(+) diff --git a/ChangeLog.txt b/ChangeLog.txt index f79c5277f5..e80a1d40f2 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -11,6 +11,8 @@ Broker: network is down. Closes #1062. - Fix outgoing retained messages not being sent by bridges on initial connection. Closes #1040. +- Don't reload auth_opt_ options on reload, to match the behaviour of the + other plugin options. Closes #1068. Library: - Fix reconnect delay backoff behaviour. Closes #1027. diff --git a/src/conf.c b/src/conf.c index c6bd897cb9..67e172b00a 100644 --- a/src/conf.c +++ b/src/conf.c @@ -818,6 +818,7 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct conf__set_cur_security_options(config, cur_listener, &cur_security_options); if(conf__parse_bool(&token, "allow_zero_length_clientid", &cur_security_options->allow_zero_length_clientid, saveptr)) return MOSQ_ERR_INVAL; }else if(!strncmp(token, "auth_opt_", 9)){ + if(reload) continue; // Auth plugin not currently valid for reloading. if(!cur_auth_plugin_config){ log__printf(NULL, MOSQ_LOG_ERR, "Error: An auth_opt_ option exists in the config file without an auth_plugin."); return MOSQ_ERR_INVAL; From 919333567ce6e8a2a8ec81764ebc8798e71ef349 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 4 Dec 2018 22:48:56 +0000 Subject: [PATCH 127/254] Add home interface support to snap, for users that need it. --- snap/snapcraft.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index fa1127ed55..0b31af92ec 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -16,11 +16,11 @@ 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] sub: command: usr/bin/mosquitto_sub @@ -28,6 +28,7 @@ apps: passwd: command: usr/bin/mosquitto_passwd + plugs: [home] parts: From 3a871828ac0b8ca7a0316d1d43ead85070feda3b Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 5 Dec 2018 11:25:41 +0000 Subject: [PATCH 128/254] Print message on error when installing as a Windows service. --- ChangeLog.txt | 1 + src/service.c | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/ChangeLog.txt b/ChangeLog.txt index e80a1d40f2..ec08285591 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -13,6 +13,7 @@ Broker: connection. Closes #1040. - Don't reload auth_opt_ options on reload, to match the behaviour of the other plugin options. Closes #1068. +- Print message on error when installing/uninstalling as a Windows service. Library: - Fix reconnect delay backoff behaviour. Closes #1027. diff --git a/src/service.c b/src/service.c index 11b4b018a8..c0fdc68a2c 100644 --- a/src/service.c +++ b/src/service.c @@ -27,6 +27,18 @@ SERVICE_STATUS_HANDLE service_handle = 0; static SERVICE_STATUS service_status; int main(int argc, char *argv[]); +static void print_error(void) +{ + char *buf; + + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, GetLastError(), LANG_NEUTRAL, &buf, 0, NULL); + + fprintf(stderr, "Error: %s\n", buf); + LocalFree(buf); +} + + /* Service control callback */ void __stdcall service_handler(DWORD fdwControl) { @@ -112,8 +124,12 @@ void service_install(void) svc_desc.lpDescription = "MQTT v3.1.1 broker"; ChangeServiceConfig2(svc_handle, SERVICE_CONFIG_DESCRIPTION, &svc_desc); CloseServiceHandle(svc_handle); + }else{ + print_error(); } CloseServiceHandle(sc_manager); + } else { + print_error(); } } @@ -132,8 +148,12 @@ void service_uninstall(void) } } CloseServiceHandle(svc_handle); + }else{ + print_error(); } CloseServiceHandle(sc_manager); + }else{ + print_error(); } } From d07864939a62b98fb1facd5db9b30d9a4d0bcad5 Mon Sep 17 00:00:00 2001 From: Tamaki Nishino Date: Tue, 13 Nov 2018 22:09:18 +0900 Subject: [PATCH 129/254] Check SSL_DATA_PENDING in mosquitto_loop_read() Signed-off-by: Tamaki Nishino --- lib/loop.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/loop.c b/lib/loop.c index 349ee5dc4b..b8fd2c5764 100644 --- a/lib/loop.c +++ b/lib/loop.c @@ -147,12 +147,10 @@ int mosquitto_loop(struct mosquitto *mosq, int timeout, int max_packets) }else{ if(mosq->sock != INVALID_SOCKET){ if(FD_ISSET(mosq->sock, &readfds)){ - do{ - rc = mosquitto_loop_read(mosq, max_packets); - if(rc || mosq->sock == INVALID_SOCKET){ - return rc; - } - }while(SSL_DATA_PENDING(mosq)); + rc = mosquitto_loop_read(mosq, max_packets); + if(rc || mosq->sock == INVALID_SOCKET){ + return rc; + } } if(mosq->sockpairR != INVALID_SOCKET && FD_ISSET(mosq->sockpairR, &readfds)){ #ifndef WIN32 @@ -368,7 +366,7 @@ int mosquitto_loop_read(struct mosquitto *mosq, int max_packets) /* Queue len here tells us how many messages are awaiting processing and * have QoS > 0. We should try to deal with that many in this loop in order * to keep up. */ - for(i=0; isocks5_host){ rc = socks5__read(mosq); From ead440e47d3dcb56ebe5773def6b2a3cef35754a Mon Sep 17 00:00:00 2001 From: Abilio Marques Date: Sat, 10 Nov 2018 11:34:01 +0100 Subject: [PATCH 130/254] bridge: fix issue where keepalive_interval gets added to restart_timeout using ADNS Signed-off-by: Abilio Marques --- src/loop.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/loop.c b/src/loop.c index c049c8ef49..6773185a89 100644 --- a/src/loop.c +++ b/src/loop.c @@ -408,6 +408,10 @@ int mosquitto_main_loop(struct mosquitto_db *db, mosq_sock_t *listensock, int li context->bridge->restart_t = 0; } }else{ +#ifdef WITH_EPOLL + /* clean any events triggered in previous connection */ + context->events = 0; +#endif rc = bridge__connect_step1(db, context); if(rc){ context->bridge->cur_address++; From 085fdf3593465ab7f1b95e8919b00831457f5840 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 5 Dec 2018 13:28:26 +0000 Subject: [PATCH 131/254] Add tests for Content Type property sending. --- .../02-subpub-qos0-payload-format-v5.py | 47 --------------- test/broker/12-prop-subpub-content-type.py | 17 ++++++ test/broker/12-prop-subpub-payload-format.py | 17 ++++++ test/broker/Makefile | 3 +- test/broker/prop_subpub_helper.py | 43 ++++++++++++++ test/broker/ptest.py | 4 +- test/lib/11-prop-send-content-type.py | 54 +++++++++++++++++ test/lib/Makefile | 1 + test/lib/c/11-prop-send-content-type.c | 58 +++++++++++++++++++ test/lib/c/Makefile | 5 +- test/lib/ptest.py | 1 + 11 files changed, 200 insertions(+), 50 deletions(-) delete mode 100755 test/broker/02-subpub-qos0-payload-format-v5.py create mode 100755 test/broker/12-prop-subpub-content-type.py create mode 100755 test/broker/12-prop-subpub-payload-format.py create mode 100755 test/broker/prop_subpub_helper.py create mode 100755 test/lib/11-prop-send-content-type.py create mode 100644 test/lib/c/11-prop-send-content-type.c diff --git a/test/broker/02-subpub-qos0-payload-format-v5.py b/test/broker/02-subpub-qos0-payload-format-v5.py deleted file mode 100755 index 8fa7aae256..0000000000 --- a/test/broker/02-subpub-qos0-payload-format-v5.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python - -# Test whether a client subscribed to a topic receives its own message sent to that topic. -# Does the Payload Format Indicator property get sent through? -# MQTT v5 - -from mosq_test_helper import * - -rc = 1 -mid = 53 -keepalive = 60 -connect_packet = mosq_test.gen_connect("subpub-qos0-test", keepalive=keepalive, proto_ver=5) -connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) - -subscribe_packet = mosq_test.gen_subscribe(mid, "subpub/qos0", 0, proto_ver=5) -suback_packet = mosq_test.gen_suback(mid, 0, proto_ver=5) - -props = mqtt5_props.gen_byte_prop(mqtt5_props.PROP_PAYLOAD_FORMAT_INDICATOR, 0xed) -props = props+mqtt5_props.gen_uint16_prop(mqtt5_props.PROP_TOPIC_ALIAS, 1) -props = mqtt5_props.prop_finalise(props) -publish_packet_out = mosq_test.gen_publish("subpub/qos0", qos=0, payload="message", proto_ver=5, properties=props) - -props = mqtt5_props.gen_byte_prop(mqtt5_props.PROP_PAYLOAD_FORMAT_INDICATOR, 0xed) -props = mqtt5_props.prop_finalise(props) -publish_packet_expected = mosq_test.gen_publish("subpub/qos0", qos=0, payload="message", proto_ver=5, properties=props) - -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) - - mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback") - mosq_test.do_send_receive(sock, publish_packet_out, publish_packet_expected, "publish") - - rc = 0 - - sock.close() -finally: - broker.terminate() - broker.wait() - (stdo, stde) = broker.communicate() - if rc: - print(stde) - -exit(rc) - diff --git a/test/broker/12-prop-subpub-content-type.py b/test/broker/12-prop-subpub-content-type.py new file mode 100755 index 0000000000..43ec811dbb --- /dev/null +++ b/test/broker/12-prop-subpub-content-type.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +# Test whether a client subscribed to a topic receives its own message sent to that topic. +# Does the Content Type property get sent through? +# MQTT v5 + +import prop_subpub_helper as helper +from mosq_test_helper import * + +props_out = mqtt5_props.gen_string_prop(mqtt5_props.PROP_CONTENT_TYPE, "text") +props_out = props_out+mqtt5_props.gen_uint16_prop(mqtt5_props.PROP_TOPIC_ALIAS, 1) +props_out = mqtt5_props.prop_finalise(props_out) + +props_in = mqtt5_props.gen_string_prop(mqtt5_props.PROP_CONTENT_TYPE, "text") +props_in = mqtt5_props.prop_finalise(props_in) + +helper.prop_subpub_helper(props_out, props_in) diff --git a/test/broker/12-prop-subpub-payload-format.py b/test/broker/12-prop-subpub-payload-format.py new file mode 100755 index 0000000000..96d63afefa --- /dev/null +++ b/test/broker/12-prop-subpub-payload-format.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +# Test whether a client subscribed to a topic receives its own message sent to that topic. +# Does the Payload Format Indicator property get sent through? +# MQTT v5 + +import prop_subpub_helper as helper +from mosq_test_helper import * + +props_out = mqtt5_props.gen_byte_prop(mqtt5_props.PROP_PAYLOAD_FORMAT_INDICATOR, 0xed) +props_out = props_out+mqtt5_props.gen_uint16_prop(mqtt5_props.PROP_TOPIC_ALIAS, 1) +props_out = mqtt5_props.prop_finalise(props_out) + +props_in = mqtt5_props.gen_byte_prop(mqtt5_props.PROP_PAYLOAD_FORMAT_INDICATOR, 0xed) +props_in = mqtt5_props.prop_finalise(props_in) + +helper.prop_subpub_helper(props_out, props_in) diff --git a/test/broker/Makefile b/test/broker/Makefile index 0a90db09e2..f19566eaf4 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -53,7 +53,6 @@ endif ./02-unsubscribe-qos1.py ./02-unsubscribe-qos2.py ./02-unsubscribe-qos2-v5.py - ./02-subpub-qos0-payload-format-v5.py ./02-unsubscribe-invalid-no-topic.py ./02-subscribe-invalid-utf8.py ./02-subscribe-persistence-flipflop.py @@ -138,3 +137,5 @@ endif 12 : ./12-prop-session-expiry-invalid.py + ./12-prop-subpub-payload-format.py + ./12-prop-subpub-content-type.py diff --git a/test/broker/prop_subpub_helper.py b/test/broker/prop_subpub_helper.py new file mode 100755 index 0000000000..212e4d7e23 --- /dev/null +++ b/test/broker/prop_subpub_helper.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +# Test whether a client subscribed to a topic receives its own message sent to that topic. +# Does a given property get sent through? +# MQTT v5 + +from mosq_test_helper import * + +def prop_subpub_helper(props_out, props_in): + rc = 1 + mid = 53 + keepalive = 60 + connect_packet = mosq_test.gen_connect("subpub-qos0-test", keepalive=keepalive, proto_ver=5) + connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + + subscribe_packet = mosq_test.gen_subscribe(mid, "subpub/qos0", 0, proto_ver=5) + suback_packet = mosq_test.gen_suback(mid, 0, proto_ver=5) + + publish_packet_out = mosq_test.gen_publish("subpub/qos0", qos=0, payload="message", proto_ver=5, properties=props_out) + + publish_packet_expected = mosq_test.gen_publish("subpub/qos0", qos=0, payload="message", proto_ver=5, properties=props_in) + + 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) + + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback") + mosq_test.do_send_receive(sock, publish_packet_out, publish_packet_expected, "publish") + + rc = 0 + + sock.close() + finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + + exit(rc) + diff --git a/test/broker/ptest.py b/test/broker/ptest.py index ffb7b3ed4e..5d9fb0a3f7 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -32,7 +32,6 @@ (1, './02-subpub-qos0-v5.py'), (1, './02-subpub-qos1-v5.py'), (1, './02-subpub-qos2-v5.py'), - (1, './02-subpub-qos0-payload-format-v5.py'), (1, './02-unsubscribe-qos0.py'), (1, './02-unsubscribe-qos1.py'), (1, './02-unsubscribe-qos2.py'), @@ -105,7 +104,10 @@ (2, './10-listener-mount-point.py'), (1, './11-persistent-subscription.py'), + (1, './12-prop-session-expiry-invalid.py'), + (1, './12-prop-subpub-payload-format.py'), + (1, './12-prop-subpub-content-type.py'), ] minport = 1888 diff --git a/test/lib/11-prop-send-content-type.py b/test/lib/11-prop-send-content-type.py new file mode 100755 index 0000000000..f78bb3a6f7 --- /dev/null +++ b/test/lib/11-prop-send-content-type.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python + +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, "application/json") +props = mqtt5_props.prop_finalise(props) +publish_packet = mosq_test.gen_publish("prop/qos0", qos=0, payload="message", proto_ver=5, properties=props) + +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) + + if mosq_test.expect_packet(conn, "publish", publish_packet): + if mosq_test.expect_packet(conn, "disconnect", disconnect_packet): + rc = 0 + + conn.close() +finally: + client.terminate() + client.wait() + if rc: + (stdo, stde) = client.communicate() + print(stde) + sock.close() + +exit(rc) diff --git a/test/lib/Makefile b/test/lib/Makefile index b1ef54f464..e9b0c54c6b 100644 --- a/test/lib/Makefile +++ b/test/lib/Makefile @@ -50,6 +50,7 @@ ifeq ($(WITH_TLS),yes) endif ./09-util-topic-tokenise.py $@/09-util-topic-tokenise.test ./11-prop-send-payload-format.py $@/11-prop-send-payload-format.test + ./11-prop-send-content-type.py $@/11-prop-send-content-type.test clean : $(MAKE) -C c clean diff --git a/test/lib/c/11-prop-send-content-type.c b/test/lib/c/11-prop-send-content-type.c new file mode 100644 index 0000000000..d60c8b5add --- /dev/null +++ b/test/lib/c/11-prop-send-content-type.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include + +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); + }else{ + rc2 = mosquitto_property_add_string(&proplist, MQTT_PROP_CONTENT_TYPE, "application/json"); + mosquitto_publish_v5(mosq, &sent_mid, "prop/qos0", strlen("message"), "message", 0, false, proplist); + } +} + +void on_publish(struct mosquitto *mosq, void *obj, int mid) +{ + if(mid == sent_mid){ + mosquitto_disconnect(mosq); + run = 0; + }else{ + exit(1); + } +} + +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_publish_callback_set(mosq, on_publish); + tmp = MQTT_PROTOCOL_V5; + mosquitto_opts_set(mosq, MOSQ_OPT_PROTOCOL_VERSION, &tmp); + + rc = mosquitto_connect(mosq, "localhost", port, 60); + + while(run == -1){ + rc = mosquitto_loop(mosq, -1, 1); + } + + mosquitto_lib_cleanup(); + return run; +} diff --git a/test/lib/c/Makefile b/test/lib/c/Makefile index 45a6c7e773..4727680f52 100644 --- a/test/lib/c/Makefile +++ b/test/lib/c/Makefile @@ -89,6 +89,9 @@ all : 01 02 03 04 08 09 11 11-prop-send-payload-format.test : 11-prop-send-payload-format.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) +11-prop-send-content-type.test : 11-prop-send-content-type.c + $(CC) $< -o $@ $(CFLAGS) $(LIBS) + 01 : 01-con-discon-success.test 01-will-set.test 01-unpwd-set.test 01-will-unpwd-set.test 01-no-clean-session.test 01-keepalive-pingreq.test 02 : 02-subscribe-qos0.test 02-subscribe-qos1.test 02-subscribe-qos2.test 02-unsubscribe.test @@ -101,7 +104,7 @@ all : 01 02 03 04 08 09 11 09 : 09-util-topic-tokenise.test -11 : 11-prop-send-payload-format.test +11 : 11-prop-send-payload-format.test 11-prop-send-content-type.test reallyclean : clean -rm -f *.orig diff --git a/test/lib/ptest.py b/test/lib/ptest.py index d3981a7c34..64990e5e95 100755 --- a/test/lib/ptest.py +++ b/test/lib/ptest.py @@ -32,6 +32,7 @@ ('./08-ssl-connect-no-auth.py', 'c/08-ssl-connect-no-auth.test'), ('./09-util-topic-tokenise.py', 'c/09-util-topic-tokenise.test'), ('./11-prop-send-payload-format.py', 'c/11-prop-send-payload-format.test'), + ('./11-prop-send-content-type.py', 'c/11-prop-send-content-type.test'), ('./01-con-discon-success.py', 'cpp/01-con-discon-success.test'), ('./01-keepalive-pingreq.py', 'cpp/01-keepalive-pingreq.test'), From f01042fb9756889723ef3c88efd1b3e6cc13a840 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 5 Dec 2018 13:53:00 +0000 Subject: [PATCH 132/254] Simplify test makefiles. --- test/broker/c/Makefile | 38 ++++++----- test/lib/c/Makefile | 139 +++++++++++------------------------------ 2 files changed, 55 insertions(+), 122 deletions(-) diff --git a/test/broker/c/Makefile b/test/broker/c/Makefile index f60f9d5fab..2005270df3 100644 --- a/test/broker/c/Makefile +++ b/test/broker/c/Makefile @@ -1,34 +1,32 @@ -.PHONY: all test clean reallyclean 08 +.PHONY: all test clean reallyclean CFLAGS=-I../../../lib -I../../../src -Wall -Werror -all : auth_plugin.so auth_plugin_pwd.so auth_plugin_acl.so auth_plugin_v2.so auth_plugin_msg_params.so auth_plugin_context_params.so 08 +PLUGIN_SRC = \ + auth_plugin.c \ + auth_plugin_pwd.c \ + auth_plugin_acl.c \ + auth_plugin_v2.c \ + auth_plugin_context_params.c \ + auth_plugin_msg_params.c -08 : 08-tls-psk-pub.test 08-tls-psk-bridge.test +PLUGINS = ${PLUGIN_SRC:.c=.so} -auth_plugin.so : auth_plugin.c - $(CC) ${CFLAGS} -fPIC -shared $^ -o $@ +SRC = \ + 08-tls-psk-pub.c \ + 08-tls-psk-bridge.c -auth_plugin_pwd.so : auth_plugin_pwd.c - $(CC) ${CFLAGS} -fPIC -shared $^ -o $@ +TESTS = ${SRC:.c=.test} -auth_plugin_acl.so : auth_plugin_acl.c - $(CC) ${CFLAGS} -fPIC -shared $^ -o $@ -auth_plugin_v2.so : auth_plugin_v2.c - $(CC) ${CFLAGS} -fPIC -shared $^ -o $@ +all : ${PLUGINS} ${TESTS} -auth_plugin_context_params.so : auth_plugin_context_params.c - $(CC) ${CFLAGS} -fPIC -shared $^ -o $@ +${PLUGINS} : %.so: %.c + $(CC) ${CFLAGS} -fPIC -shared $< -o $@ -auth_plugin_msg_params.so : auth_plugin_msg_params.c - $(CC) ${CFLAGS} -fPIC -shared $^ -o $@ -08-tls-psk-pub.test : 08-tls-psk-pub.c - $(CC) ${CFLAGS} $^ -o $@ ../../../lib/libmosquitto.so.1 - -08-tls-psk-bridge.test : 08-tls-psk-bridge.c - $(CC) ${CFLAGS} $^ -o $@ ../../../lib/libmosquitto.so.1 +${TESTS} : %.test: %.c + $(CC) ${CFLAGS} $< -o $@ ../../../lib/libmosquitto.so.1 reallyclean : clean diff --git a/test/lib/c/Makefile b/test/lib/c/Makefile index 4727680f52..0986b528dc 100644 --- a/test/lib/c/Makefile +++ b/test/lib/c/Makefile @@ -1,111 +1,46 @@ -.PHONY: all test 01 02 03 04 08 09 clean reallyclean +.PHONY: all clean reallyclean CFLAGS=-I../../../lib -Werror LIBS=../../../lib/libmosquitto.so.1 -all : 01 02 03 04 08 09 11 - -01-con-discon-success.test : 01-con-discon-success.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -01-will-set.test : 01-will-set.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -01-unpwd-set.test : 01-unpwd-set.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -01-will-unpwd-set.test : 01-will-unpwd-set.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -01-no-clean-session.test : 01-no-clean-session.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -01-keepalive-pingreq.test : 01-keepalive-pingreq.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -02-subscribe-qos0.test : 02-subscribe-qos0.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -02-subscribe-qos1.test : 02-subscribe-qos1.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -02-subscribe-qos2.test : 02-subscribe-qos2.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -02-unsubscribe.test : 02-unsubscribe.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -03-publish-qos0.test : 03-publish-qos0.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -03-publish-qos0-no-payload.test : 03-publish-qos0-no-payload.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -03-publish-c2b-qos1-disconnect.test : 03-publish-c2b-qos1-disconnect.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -03-publish-c2b-qos2.test : 03-publish-c2b-qos2.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -03-publish-c2b-qos2-disconnect.test : 03-publish-c2b-qos2-disconnect.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -03-publish-b2c-qos1.test : 03-publish-b2c-qos1.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -03-request-response-1.test : 03-request-response-1.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -03-request-response-2.test : 03-request-response-2.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -03-request-response-correlation-1.test : 03-request-response-correlation-1.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -03-publish-b2c-qos2.test : 03-publish-b2c-qos2.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -04-retain-qos0.test : 04-retain-qos0.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -08-ssl-connect-no-auth.test : 08-ssl-connect-no-auth.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -08-ssl-connect-cert-auth.test : 08-ssl-connect-cert-auth.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -08-ssl-connect-cert-auth-enc.test : 08-ssl-connect-cert-auth-enc.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -08-ssl-bad-cacert.test : 08-ssl-bad-cacert.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -08-ssl-fake-cacert.test : 08-ssl-fake-cacert.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -09-util-topic-tokenise.test : 09-util-topic-tokenise.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -11-prop-send-payload-format.test : 11-prop-send-payload-format.c - $(CC) $< -o $@ $(CFLAGS) $(LIBS) - -11-prop-send-content-type.test : 11-prop-send-content-type.c +SRC = \ + 01-con-discon-success.c \ + 01-will-set.c \ + 01-unpwd-set.c \ + 01-will-unpwd-set.c \ + 01-no-clean-session.c \ + 01-keepalive-pingreq.c \ + 02-subscribe-qos0.c \ + 02-subscribe-qos1.c \ + 02-subscribe-qos2.c \ + 02-unsubscribe.c \ + 03-publish-qos0.c \ + 03-publish-qos0-no-payload.c \ + 03-publish-c2b-qos1-disconnect.c \ + 03-publish-c2b-qos2.c \ + 03-publish-c2b-qos2-disconnect.c \ + 03-publish-b2c-qos1.c \ + 03-request-response-1.c \ + 03-request-response-2.c \ + 03-request-response-correlation-1.c \ + 03-publish-b2c-qos2.c \ + 04-retain-qos0.c \ + 08-ssl-connect-no-auth.c \ + 08-ssl-connect-cert-auth.c \ + 08-ssl-connect-cert-auth-enc.c \ + 08-ssl-bad-cacert.c \ + 08-ssl-fake-cacert.c \ + 09-util-topic-tokenise.c \ + 11-prop-send-payload-format.c \ + 11-prop-send-content-type.c + +TESTS = ${SRC:.c=.test} + +all : ${TESTS} + +${TESTS} : %.test: %.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) -01 : 01-con-discon-success.test 01-will-set.test 01-unpwd-set.test 01-will-unpwd-set.test 01-no-clean-session.test 01-keepalive-pingreq.test - -02 : 02-subscribe-qos0.test 02-subscribe-qos1.test 02-subscribe-qos2.test 02-unsubscribe.test - -03 : 03-publish-qos0.test 03-publish-qos0-no-payload.test 03-publish-c2b-qos1-disconnect.test 03-publish-c2b-qos2.test 03-publish-c2b-qos2-disconnect.test 03-publish-b2c-qos1.test 03-publish-b2c-qos2.test 03-request-response-1.test 03-request-response-2.test 03-request-response-correlation-1.test - -04 : 04-retain-qos0.test - -08 : 08-ssl-connect-no-auth.test 08-ssl-connect-cert-auth.test 08-ssl-connect-cert-auth-enc.test 08-ssl-bad-cacert.test 08-ssl-fake-cacert.test - -09 : 09-util-topic-tokenise.test - -11 : 11-prop-send-payload-format.test 11-prop-send-content-type.test - reallyclean : clean -rm -f *.orig From 1d3949bce0415475579360bb0fccee1307e2ca55 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 5 Dec 2018 16:39:45 +0000 Subject: [PATCH 133/254] Improve broker generated client ids for the non-Linux case. Removes libuuid dependency. --- ChangeLog.txt | 4 +++ compiling.txt | 1 - config.mk | 11 ------ readme.md | 1 - snap/snapcraft.yaml | 3 -- src/CMakeLists.txt | 9 ----- src/handle_connect.c | 86 ++++++++++++++++++++++++++++++++++---------- travis-install.sh | 2 +- 8 files changed, 72 insertions(+), 45 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 8ebaa2a916..bb3fc58f2a 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,6 +1,10 @@ 1.6 - 2018xxxx ============== +Broker features: +- Improved general support for broker generated client ids. Removed libuuid + dependency. + Client library features: - Add mosquitto_subscribe_multiple() for sending subscriptions to multiple topics in one command. diff --git a/compiling.txt b/compiling.txt index 99ddc56e49..8d44b44971 100644 --- a/compiling.txt +++ b/compiling.txt @@ -3,7 +3,6 @@ are optional. * openssl * c-ares (for DNS-SRV support, disabled by default) -* libuuid (from util-linux, can be disabled) * tcp-wrappers (optional, package name libwrap0-dev) * libwebsockets (optional, disabled by default, version 1.3 and above) * On Windows, a pthreads library is required if threading support is to be diff --git a/config.mk b/config.mk index 6f3f3ac592..f7a030dbc4 100644 --- a/config.mk +++ b/config.mk @@ -64,10 +64,6 @@ WITH_SYSTEMD:=no # Build with SRV lookup support. WITH_SRV:=no -# Build using libuuid for clientid generation (Linux only - please report if -# supported on your platform). -WITH_UUID:=yes - # Build with websockets support on the broker. WITH_WEBSOCKETS:=no @@ -209,13 +205,6 @@ ifeq ($(WITH_SOCKS),yes) CLIENT_CFLAGS:=$(CLIENT_CFLAGS) -DWITH_SOCKS endif -ifeq ($(WITH_UUID),yes) - ifeq ($(UNAME),Linux) - BROKER_CFLAGS:=$(BROKER_CFLAGS) -DWITH_UUID - BROKER_LIBS:=$(BROKER_LIBS) -luuid - endif -endif - ifeq ($(WITH_BRIDGE),yes) BROKER_CFLAGS:=$(BROKER_CFLAGS) -DWITH_BRIDGE endif diff --git a/readme.md b/readme.md index 3272689479..ee038fbcfe 100644 --- a/readme.md +++ b/readme.md @@ -66,7 +66,6 @@ already be built. Use `make binary` to skip building the man pages, or install ### Build Dependencies * c-ares (libc-ares-dev on Debian based systems) - disable with `make WITH_SRV=no` -* libuuid (uuid-dev) - disable with `make WITH_UUID=no` * libwebsockets (libwebsockets-dev) - enable with `make WITH_WEBSOCKETS=yes` * openssl (libssl-dev on Debian based systems) - disable with `make WITH_TLS=no` * xsltproc (xsltproc and docbook-xsl on Debian based systems) - only needed when building from git sources - disable with `make WITH_DOCS=no` diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index c7569010ed..7ce01902b3 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -51,14 +51,12 @@ parts: build-packages: - libssl-dev - - uuid-dev - xsltproc - docbook-xsl - gcc - g++ stage-packages: - libssl1.0.0 - - libuuid1 prime: - usr/sbin/mosquitto - usr/bin/mosquitto_pub @@ -66,7 +64,6 @@ parts: - usr/lib/libmosquitto.so* - lib/*-linux-gnu/libcrypto.so* - lib/*-linux-gnu/libssl.so* - - lib/*-linux-gnu/libuuid.so* lws: plugin: cmake diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e1eb6f4658..960b263a2f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -160,15 +160,6 @@ if (${WITH_WEBSOCKETS} STREQUAL ON) endif (${STATIC_WEBSOCKETS} STREQUAL ON) endif (${WITH_WEBSOCKETS} STREQUAL ON) -# Simple detect libuuid -if(NOT APPLE) - FIND_PATH(UUID_HEADER uuid/uuid.h) - if (UUID_HEADER) - add_definitions(-DWITH_UUID) - set (MOSQ_LIBS ${MOSQ_LIBS} uuid) - endif (UUID_HEADER) -endif(NOT APPLE) - add_executable(mosquitto ${MOSQ_SRCS}) target_link_libraries(mosquitto ${MOSQ_LIBS}) diff --git a/src/handle_connect.c b/src/handle_connect.c index ad737b8fc1..0c92d6d330 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -30,28 +30,75 @@ and the Eclipse Distribution License is available at #include "tls_mosq.h" #include "util_mosq.h" -#ifdef WITH_UUID -# include +#ifdef WITH_TLS +# include +#endif + +#ifdef __linux__ +# include #endif #ifdef WITH_WEBSOCKETS # include #endif -static char *client_id_gen(struct mosquitto_db *db, int *idlen, const char *auto_id_prefix, int auto_id_prefix_len) + +static int random_16_bytes(uint8_t *bytes) { - char *client_id; -#ifdef WITH_UUID - uuid_t uuid; + int rc = MOSQ_ERR_UNKNOWN; + +#ifdef WITH_TLS + if(RAND_bytes(bytes, 16) == 1){ + rc = MOSQ_ERR_SUCCESS; + } #else +# ifdef __GLIBC__ + if(getrandom(bytes, 16, 0) == 0){ + rc = MOSQ_ERR_SUCCESS; + } +# elif defined(WIN32) + HRYPTPROV provider; + + if(!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)){ + return MOSQ_ERR_UNKNOWN; + } + + if(CryptGenRandom(provider, 16, bytes)){ + rc = MOSQ_ERR_SUCCESS; + } + + CryptReleaseContext(provider, 0); +# else int i; + + for(i=0; i<16; i++){ + bytes[i] = (uint8_t )(random()&0xFF); + } + rc = MOSQ_ERR_SUCCESS; +# endif #endif + return rc; +} + +static char nibble_to_hex(uint8_t value) +{ + if(value < 0x0A){ + return '0'+value; + }else{ + return 'A'+value-0x0A; + } +} + +static char *client_id_gen(struct mosquitto_db *db, int *idlen, const char *auto_id_prefix, int auto_id_prefix_len) +{ + char *client_id; + uint8_t rnd[16]; + int i; + int pos; + + if(random_16_bytes(rnd)) return NULL; -#ifdef WITH_UUID *idlen = 36 + auto_id_prefix_len; -#else - *idlen = 64 + auto_id_prefix_len; -#endif client_id = (char *)mosquitto__calloc((*idlen) + 1, sizeof(char)); if(!client_id){ @@ -61,16 +108,17 @@ static char *client_id_gen(struct mosquitto_db *db, int *idlen, const char *auto memcpy(client_id, auto_id_prefix, auto_id_prefix_len); } - -#ifdef WITH_UUID - uuid_generate_random(uuid); - uuid_unparse_lower(uuid, &client_id[auto_id_prefix_len]); -#else - for(i=0; i<64; i++){ - client_id[i+auto_id_prefix_len] = (rand()%73)+48; + pos = 0; + for(i=0; i<16; i++){ + client_id[auto_id_prefix_len + pos + 0] = nibble_to_hex(rnd[i] & 0x0F); + client_id[auto_id_prefix_len + pos + 1] = nibble_to_hex((rnd[i] >> 4) & 0x0F); + pos += 2; + if(pos == 8 || pos == 13 || pos == 18 || pos == 23){ + client_id[auto_id_prefix_len + pos] = '-'; + pos++; + } } - client_id[i] = '\0'; -#endif + return client_id; } diff --git a/travis-install.sh b/travis-install.sh index f1f31dd1c3..4c8fbb8959 100755 --- a/travis-install.sh +++ b/travis-install.sh @@ -3,7 +3,7 @@ if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get update -qq - sudo apt-get install -y debhelper libc-ares-dev libssl-dev libwrap0-dev python-all python3-all uthash-dev uuid-dev libuuid1 xsltproc docbook-xsl libcunit1-dev + sudo apt-get install -y debhelper libc-ares-dev libssl-dev libwrap0-dev python-all python3-all uthash-dev xsltproc docbook-xsl libcunit1-dev fi if [ "$TRAVIS_OS_NAME" == "osx" ]; then From 48c22170154e472fee7c13b1ffb03db141713fe7 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 5 Dec 2018 17:17:35 +0000 Subject: [PATCH 134/254] auto_id_prefix now defaults to 'auto-'. --- ChangeLog.txt | 1 + man/mosquitto.conf.5.xml | 2 +- mosquitto.conf | 3 ++- src/conf.c | 26 +++++++++++++++++++++++++- 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index bb3fc58f2a..e2dd2e3a16 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -4,6 +4,7 @@ Broker features: - Improved general support for broker generated client ids. Removed libuuid dependency. +- auto_id_prefix now defaults to 'auto-'. Client library features: - Add mosquitto_subscribe_multiple() for sending subscriptions to multiple diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml index fa9d1e86b8..ee240762cf 100644 --- a/man/mosquitto.conf.5.xml +++ b/man/mosquitto.conf.5.xml @@ -262,7 +262,7 @@ true, this option allows you to set a string that will be prefixed to the automatically generated client ids to aid visibility in - logs. Defaults to no prefix. + logs. Defaults to . Reloaded on reload signal. diff --git a/mosquitto.conf b/mosquitto.conf index fa332a24eb..d9456a683e 100644 --- a/mosquitto.conf +++ b/mosquitto.conf @@ -89,7 +89,8 @@ # If allow_zero_length_clientid is true, this option allows you to set a prefix # to automatically generated client ids to aid visibility in logs. -#auto_id_prefix +# Defaults to 'auto-' +#auto_id_prefix auto- # This option allows persistent clients (those with clean session set to false) # to be removed if they do not reconnect within a certain time frame. diff --git a/src/conf.c b/src/conf.c index 00d30b2ebf..68da9929f0 100644 --- a/src/conf.c +++ b/src/conf.c @@ -2066,8 +2066,10 @@ static int config__check(struct mosquitto__config *config) { /* Checks that are easy to make after the config has been loaded. */ + int i; + #ifdef WITH_BRIDGE - int i, j; + int j; struct mosquitto__bridge *bridge1, *bridge2; char hostname[256]; int len; @@ -2115,6 +2117,28 @@ static int config__check(struct mosquitto__config *config) } } #endif + + /* Default to auto_id_prefix = 'auto-' if none set. */ + if(config->per_listener_settings){ + for(i=0; ilistener_count; i++){ + if(!config->listeners[i].security_options.auto_id_prefix){ + config->listeners[i].security_options.auto_id_prefix = mosquitto__strdup("auto-"); + if(!config->listeners[i].security_options.auto_id_prefix){ + return MOSQ_ERR_NOMEM; + } + config->listeners[i].security_options.auto_id_prefix_len = strlen("auto-"); + } + } + }else{ + if(!config->security_options.auto_id_prefix){ + config->security_options.auto_id_prefix = mosquitto__strdup("auto-"); + if(!config->security_options.auto_id_prefix){ + return MOSQ_ERR_NOMEM; + } + config->security_options.auto_id_prefix_len = strlen("auto-"); + } + } + return MOSQ_ERR_SUCCESS; } From fda66e8311b1788ddd97433869575ec84ae8b5c1 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 5 Dec 2018 20:26:43 +0000 Subject: [PATCH 135/254] Add broker test for assigned client id. --- lib/connect.c | 18 +++++++ lib/mosquitto.c | 16 ------- lib/send_connect.c | 15 ++++-- test/broker/01-connect-invalid-id-missing.py | 5 +- .../12-prop-assigned-client-identifier.py | 48 +++++++++++++++++++ test/broker/Makefile | 1 + test/broker/ptest.py | 1 + test/mosq_test.py | 4 ++ 8 files changed, 87 insertions(+), 21 deletions(-) create mode 100755 test/broker/12-prop-assigned-client-identifier.py diff --git a/lib/connect.c b/lib/connect.c index 6fbc776e08..0de0032216 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -33,9 +33,27 @@ static int mosquitto__connect_init(struct mosquitto *mosq, const char *host, int static int mosquitto__connect_init(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address) { + int i; + if(!mosq) return MOSQ_ERR_INVAL; if(!host || port <= 0) return MOSQ_ERR_INVAL; + if(mosq->id == NULL && (mosq->protocol == mosq_p_mqtt31 || mosq->protocol == mosq_p_mqtt311)){ + mosq->id = (char *)mosquitto__calloc(24, sizeof(char)); + if(!mosq->id){ + return MOSQ_ERR_NOMEM; + } + mosq->id[0] = 'm'; + mosq->id[1] = 'o'; + mosq->id[2] = 's'; + mosq->id[3] = 'q'; + mosq->id[4] = '/'; + + for(i=5; i<23; i++){ + mosq->id[i] = (random()%73)+48; + } + } + mosquitto__free(mosq->host); mosq->host = mosquitto__strdup(host); if(!mosq->host) return MOSQ_ERR_NOMEM; diff --git a/lib/mosquitto.c b/lib/mosquitto.c index 688312d3f7..92c4e9ea4e 100644 --- a/lib/mosquitto.c +++ b/lib/mosquitto.c @@ -104,8 +104,6 @@ struct mosquitto *mosquitto_new(const char *id, bool clean_start, void *userdata int mosquitto_reinitialise(struct mosquitto *mosq, const char *id, bool clean_start, void *userdata) { - int i; - if(!mosq) return MOSQ_ERR_INVAL; if(clean_start == false && id == NULL){ @@ -134,20 +132,6 @@ int mosquitto_reinitialise(struct mosquitto *mosq, const char *id, bool clean_st return MOSQ_ERR_MALFORMED_UTF8; } mosq->id = mosquitto__strdup(id); - }else{ - mosq->id = (char *)mosquitto__calloc(24, sizeof(char)); - if(!mosq->id){ - return MOSQ_ERR_NOMEM; - } - mosq->id[0] = 'm'; - mosq->id[1] = 'o'; - mosq->id[2] = 's'; - mosq->id[3] = 'q'; - mosq->id[4] = '/'; - - for(i=5; i<23; i++){ - mosq->id[i] = (rand()%73)+48; - } } mosq->in_packet.payload = NULL; packet__cleanup(&mosq->in_packet); diff --git a/lib/send_connect.c b/lib/send_connect.c index a052a39806..5b50e2c7f3 100644 --- a/lib/send_connect.c +++ b/lib/send_connect.c @@ -44,7 +44,8 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session int proplen, varbytes; assert(mosq); - assert(mosq->id); + + if(mosq->protocol == mosq_p_mqtt31 && !mosq->id) return MOSQ_ERR_PROTOCOL; #if defined(WITH_BROKER) && defined(WITH_BRIDGE) if(mosq->bridge){ @@ -81,7 +82,11 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet)); if(!packet) return MOSQ_ERR_NOMEM; - payloadlen = 2+strlen(clientid); + if(clientid){ + payloadlen = 2+strlen(clientid); + }else{ + payloadlen = 2; + } if(mosq->will){ will = 1; assert(mosq->will->msg.topic); @@ -140,7 +145,11 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session } /* Payload */ - packet__write_string(packet, clientid, strlen(clientid)); + if(clientid){ + packet__write_string(packet, clientid, strlen(clientid)); + }else{ + packet__write_uint16(packet, 0); + } if(will){ if(mosq->protocol == mosq_p_mqtt5){ /* Write will properties */ diff --git a/test/broker/01-connect-invalid-id-missing.py b/test/broker/01-connect-invalid-id-missing.py index 32188a12fe..63273e93c0 100755 --- a/test/broker/01-connect-invalid-id-missing.py +++ b/test/broker/01-connect-invalid-id-missing.py @@ -6,13 +6,14 @@ rc = 1 keepalive = 10 -connect_packet = mosq_test.gen_connect(None, keepalive=keepalive) +connect_packet = mosq_test.gen_connect(None, keepalive=keepalive, proto_ver=3) +connack_packet = mosq_test.gen_connack(rc=2) 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, "", port=port) + sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port) sock.close() rc = 0 finally: diff --git a/test/broker/12-prop-assigned-client-identifier.py b/test/broker/12-prop-assigned-client-identifier.py new file mode 100755 index 0000000000..fac50d11e0 --- /dev/null +++ b/test/broker/12-prop-assigned-client-identifier.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python + +# Test whether sending a non zero session expiry interval in DISCONNECT after +# having sent a zero session expiry interval is treated correctly in MQTT v5. + +from mosq_test_helper import * + +rc = 1 + +keepalive = 10 + + +connect_packet = mosq_test.gen_connect(None, proto_ver=5, keepalive=keepalive) + +props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_ASSIGNED_CLIENT_IDENTIFIER, "auto-00000000-0000-0000-0000-000000000000") +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5, properties=props) + +props = mqtt5_props.gen_uint32_prop(mqtt5_props.PROP_SESSION_EXPIRY_INTERVAL, 1) +props = mqtt5_props.prop_finalise(props) +disconnect_client_packet = mosq_test.gen_disconnect(proto_ver=5, properties=props) + +disconnect_server_packet = mosq_test.gen_disconnect(proto_ver=5, reason_code=130) + +port = mosq_test.get_port() +broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port) + +try: + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.settimeout(10) + sock.connect(("localhost", port)) + + sock.send(connect_packet) + connack_recvd = sock.recv(len(connack_packet)) + + if connack_recvd[0:12] == connack_packet[0:12]: + # FIXME - this test could be tightened up a lot + rc = 0 + + sock.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index f19566eaf4..db0b971a22 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -139,3 +139,4 @@ endif ./12-prop-session-expiry-invalid.py ./12-prop-subpub-payload-format.py ./12-prop-subpub-content-type.py + ./12-prop-assigned-client-identifier.py diff --git a/test/broker/ptest.py b/test/broker/ptest.py index 5d9fb0a3f7..ff2984fd62 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -108,6 +108,7 @@ (1, './12-prop-session-expiry-invalid.py'), (1, './12-prop-subpub-payload-format.py'), (1, './12-prop-subpub-content-type.py'), + (1, './12-prop-assigned-client-identifier.py'), ] minport = 1888 diff --git a/test/mosq_test.py b/test/mosq_test.py index cc3e926471..8d29d1a560 100644 --- a/test/mosq_test.py +++ b/test/mosq_test.py @@ -308,6 +308,8 @@ def gen_connect(client_id, clean_session=True, keepalive=60, username=None, pass if client_id != None: remaining_length = remaining_length + 2+len(client_id) + else: + remaining_length = remaining_length + 2 connect_flags = 0 @@ -347,6 +349,8 @@ def gen_connect(client_id, clean_session=True, keepalive=60, username=None, pass if client_id != None: packet = packet + struct.pack("!H"+str(len(client_id))+"s", len(client_id), client_id) + else: + packet = packet + struct.pack("!H", 0) if will_topic != None: packet = packet + struct.pack("!H"+str(len(will_topic))+"s", len(will_topic), will_topic) From 5073d83bf8623a60a169cb0a5444097d86237c26 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 5 Dec 2018 21:26:22 +0000 Subject: [PATCH 136/254] Don't generate client ids in v5 mode. --- client/client_shared.c | 2 +- client/pub_client.c | 4 ++-- client/pub_shared.h | 2 +- client/sub_client.c | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/client/client_shared.c b/client/client_shared.c index 13972770be..8811220137 100644 --- a/client/client_shared.c +++ b/client/client_shared.c @@ -1011,7 +1011,7 @@ int client_id_generate(struct mosq_config *cfg, const char *id_base) return 1; } snprintf(cfg->id, strlen(cfg->id_prefix)+10, "%s%d", cfg->id_prefix, getpid()); - }else if(!cfg->id){ + }else if(!cfg->id && (cfg->protocol_version == MQTT_PROTOCOL_V31 || cfg->protocol_version == MQTT_PROTOCOL_V311)){ hostname[0] = '\0'; gethostname(hostname, 256); hostname[255] = '\0'; diff --git a/client/pub_client.c b/client/pub_client.c index 139bb3aaaf..bede0032fc 100644 --- a/client/pub_client.c +++ b/client/pub_client.c @@ -48,7 +48,7 @@ int my_publish(struct mosquitto *mosq, int *mid, const char *topic, int payloadl } -void my_connect_callback(struct mosquitto *mosq, void *obj, int result) +void my_connect_callback(struct mosquitto *mosq, void *obj, int result, int flags, const mosquitto_property *properties) { int rc = MOSQ_ERR_SUCCESS; @@ -262,7 +262,7 @@ int main(int argc, char *argv[]) if(cfg.debug){ mosquitto_log_callback_set(mosq, my_log_callback); } - mosquitto_connect_callback_set(mosq, my_connect_callback); + mosquitto_connect_v5_callback_set(mosq, my_connect_callback); mosquitto_disconnect_v5_callback_set(mosq, my_disconnect_callback); mosquitto_publish_callback_set(mosq, my_publish_callback); diff --git a/client/pub_shared.h b/client/pub_shared.h index feaa22ebb8..22f88e6265 100644 --- a/client/pub_shared.h +++ b/client/pub_shared.h @@ -26,7 +26,7 @@ extern int status; extern struct mosq_config cfg; -void my_connect_callback(struct mosquitto *mosq, void *obj, int result); +void my_connect_callback(struct mosquitto *mosq, void *obj, int result, int flags, const mosquitto_property *properties); void my_disconnect_callback(struct mosquitto *mosq, void *obj, int rc, const mosquitto_property *properties); void my_publish_callback(struct mosquitto *mosq, void *obj, int mid); void my_log_callback(struct mosquitto *mosq, void *obj, int level, const char *str); diff --git a/client/sub_client.c b/client/sub_client.c index cd297b0b32..1a26bcb0bd 100644 --- a/client/sub_client.c +++ b/client/sub_client.c @@ -85,7 +85,7 @@ void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquit } } -void my_connect_callback(struct mosquitto *mosq, void *obj, int result, int flags) +void my_connect_callback(struct mosquitto *mosq, void *obj, int result, int flags, const mosquitto_property *properties) { int i; @@ -281,7 +281,7 @@ int main(int argc, char *argv[]) mosquitto_log_callback_set(mosq, my_log_callback); mosquitto_subscribe_callback_set(mosq, my_subscribe_callback); } - mosquitto_connect_with_flags_callback_set(mosq, my_connect_callback); + mosquitto_connect_v5_callback_set(mosq, my_connect_callback); mosquitto_message_callback_set(mosq, my_message_callback); rc = client_connect(mosq, &cfg); From 29846d282d0742a061e625190c251046b459ff8a Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 5 Dec 2018 21:58:31 +0000 Subject: [PATCH 137/254] Client library now reads its assigned client id. --- lib/handle_connack.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib/handle_connack.c b/lib/handle_connack.c index 530e8bf614..98adae1d31 100644 --- a/lib/handle_connack.c +++ b/lib/handle_connack.c @@ -34,6 +34,7 @@ int handle__connack(struct mosquitto *mosq) uint8_t reason_code; int rc; mosquitto_property *properties = NULL; + const mosquitto_property *prop; assert(mosq); rc = packet__read_byte(&mosq->in_packet, &connect_flags); @@ -46,6 +47,21 @@ int handle__connack(struct mosquitto *mosq) if(rc) return rc; } + prop = mosquitto_property_get_property(properties, MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER, false); + if(prop){ + if(mosq->id){ + /* We've been sent a client identifier but already have one. This + * shouldn't happen. */ + mosquitto_property_free_all(&properties); + return MOSQ_ERR_PROTOCOL; + }else{ + rc = mosquitto_property_read_string(prop, &mosq->id); + if(rc){ + mosquitto_property_free_all(&properties); + return rc; + } + } + } log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received CONNACK (%d)", mosq->id, reason_code); pthread_mutex_lock(&mosq->callback_mutex); if(mosq->on_connect){ @@ -65,6 +81,7 @@ int handle__connack(struct mosquitto *mosq) } pthread_mutex_unlock(&mosq->callback_mutex); mosquitto_property_free_all(&properties); + switch(reason_code){ case 0: if(mosq->state != mosq_cs_disconnecting){ From 6ef2c79e9abb0bffc8aeb5298c251cebab2b78f8 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 6 Dec 2018 08:49:02 +0000 Subject: [PATCH 138/254] Add max_keepalive, for limiting keepalives of MQTT v5 clients. --- ChangeLog.txt | 2 ++ lib/handle_connack.c | 10 ++++++ man/mosquitto.conf.5.xml | 19 +++++++++++ mosquitto.conf | 10 ++++++ src/conf.c | 8 +++++ src/handle_connect.c | 10 ++++-- src/mosquitto_broker_internal.h | 1 + test/broker/12-prop-server-keepalive.py | 42 +++++++++++++++++++++++++ test/broker/Makefile | 1 + test/broker/ptest.py | 1 + 10 files changed, 102 insertions(+), 2 deletions(-) create mode 100755 test/broker/12-prop-server-keepalive.py diff --git a/ChangeLog.txt b/ChangeLog.txt index e2dd2e3a16..27be9d4632 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -5,6 +5,8 @@ Broker features: - Improved general support for broker generated client ids. Removed libuuid dependency. - auto_id_prefix now defaults to 'auto-'. +- Add max_keepalive option, to allow a maximum keepalive value to be set for + MQTT v5 clients only. Client library features: - Add mosquitto_subscribe_multiple() for sending subscriptions to multiple diff --git a/lib/handle_connack.c b/lib/handle_connack.c index 98adae1d31..7cd65d4e94 100644 --- a/lib/handle_connack.c +++ b/lib/handle_connack.c @@ -62,6 +62,16 @@ int handle__connack(struct mosquitto *mosq) } } } + + prop = mosquitto_property_get_property(properties, MQTT_PROP_SERVER_KEEP_ALIVE, false); + if(prop){ + rc = mosquitto_property_read_int16(prop, &mosq->keepalive); + if(rc){ + mosquitto_property_free_all(&properties); + return rc; + } + } + log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received CONNACK (%d)", mosq->id, reason_code); pthread_mutex_lock(&mosq->callback_mutex); if(mosq->on_connect){ diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml index ee240762cf..dbfce513a2 100644 --- a/man/mosquitto.conf.5.xml +++ b/man/mosquitto.conf.5.xml @@ -435,6 +435,25 @@ Reloaded on reload signal. + + value + + For MQTT v5 clients, it is possible to have the + server send a "server keepalive" value that will + override the keepalive value set by the client. This + is intended to be used as a mechanism to say that the + server will disconnect the client earlier than it + anticipated, and that the client should use the new + keepalive value. The max_keepalive option allows you to + specify that clients may only connect with keepalive + less than or equal to this value, otherwise they will + be sent a server keepalive telling them to use + max_keepalive. This only applies to MQTT v5 clients. + The maximum value allowable, and default value, is + 65535. Do not set below 10 seconds. + Reloaded on reload signal. + + count diff --git a/mosquitto.conf b/mosquitto.conf index d9456a683e..cf24e2ed8c 100644 --- a/mosquitto.conf +++ b/mosquitto.conf @@ -155,6 +155,16 @@ # false. #retain_available true +# For MQTT v5 clients, it is possible to have the server send a "server +# keepalive" value that will override the keepalive value set by the client. +# This is intended to be used as a mechanism to say that the server will +# disconnect the client earlier than it anticipated, and that the client should +# use the new keepalive value. The max_keepalive option allows you to specify +# that clients may only connect with keepalive less than or equal to this +# value, otherwise they will be sent a server keepalive telling them to use +# max_keepalive. This only applies to MQTT v5 clients. The maximum value +# allowable is 65535. Do not set below 10. +#max_keepalive 65535 # ================================================================= # Default listener diff --git a/src/conf.c b/src/conf.c index 68da9929f0..9053f22888 100644 --- a/src/conf.c +++ b/src/conf.c @@ -212,6 +212,7 @@ static void config__init_reload(struct mosquitto_db *db, struct mosquitto__confi } #endif config->log_timestamp = true; + config->max_keepalive = 65535; config->persistence = false; mosquitto__free(config->persistence_location); config->persistence_location = NULL; @@ -1513,6 +1514,13 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct }else{ log__printf(NULL, MOSQ_LOG_ERR, "Error: Empty max_inflight_messages value in configuration."); } + }else if(!strcmp(token, "max_keepalive")){ + if(conf__parse_int(&token, "max_keepalive", &tmp_int, saveptr)) return MOSQ_ERR_INVAL; + if(tmp_int < 10 || tmp_int > 65535){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid max_keepalive value (%d).", tmp_int); + return MOSQ_ERR_INVAL; + } + config->max_keepalive = tmp_int; }else if(!strcmp(token, "max_queued_bytes")){ token = strtok_r(NULL, " ", &saveptr); if(token){ diff --git a/src/handle_connect.c b/src/handle_connect.c index 0c92d6d330..c1634eb74e 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -297,11 +297,17 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) rc = 1; goto handle_connect_error; } + if(protocol_version == PROTOCOL_VERSION_v5 && context->keepalive > db->config->max_keepalive){ + context->keepalive = db->config->max_keepalive; + if(mosquitto_property_add_int16(&connack_props, MQTT_PROP_SERVER_KEEP_ALIVE, context->keepalive)){ + rc = MOSQ_ERR_NOMEM; + goto handle_connect_error; + } + } if(protocol_version == PROTOCOL_VERSION_v5){ rc = property__read_all(CMD_CONNECT, &context->in_packet, &properties); - if(rc) return rc; - mosquitto_property_free_all(&properties); + if(rc) goto handle_connect_error; } property__process_connect(context, properties); diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index 7a1b6bd753..cc0a5eddfb 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -259,6 +259,7 @@ struct mosquitto__config { bool log_timestamp; char *log_file; FILE *log_fptr; + uint16_t max_keepalive; uint32_t message_size_limit; bool persistence; char *persistence_location; diff --git a/test/broker/12-prop-server-keepalive.py b/test/broker/12-prop-server-keepalive.py new file mode 100755 index 0000000000..5073f28cba --- /dev/null +++ b/test/broker/12-prop-server-keepalive.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python + +# Test whether sending a non zero session expiry interval in DISCONNECT after +# having sent a zero session expiry interval is treated correctly in MQTT v5. + +from mosq_test_helper import * + +def write_config(filename, port): + with open(filename, 'w') as f: + f.write("port %d\n" % (port)) + f.write("\n") + f.write("max_keepalive 60\n") + +port = mosq_test.get_port(1) +conf_file = os.path.basename(__file__).replace('.py', '.conf') +write_config(conf_file, port) + + +rc = 1 + +keepalive = 61 +connect_packet = mosq_test.gen_connect("test", proto_ver=5, keepalive=keepalive) + +props = mqtt5_props.gen_uint16_prop(mqtt5_props.PROP_SERVER_KEEP_ALIVE, 60) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5, properties=props) + +broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port, use_conf=True) + +try: + sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port) + sock.close() + rc = 0 +finally: + os.remove(conf_file) + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index db0b971a22..0b9bf16908 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -140,3 +140,4 @@ endif ./12-prop-subpub-payload-format.py ./12-prop-subpub-content-type.py ./12-prop-assigned-client-identifier.py + ./12-prop-server-keepalive.py diff --git a/test/broker/ptest.py b/test/broker/ptest.py index ff2984fd62..a9772aa5ab 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -109,6 +109,7 @@ (1, './12-prop-subpub-payload-format.py'), (1, './12-prop-subpub-content-type.py'), (1, './12-prop-assigned-client-identifier.py'), + (1, './12-prop-server-keepalive.py'), ] minport = 1888 From 9896e617277dccc219a5afd7a2977ec50cd195c0 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 6 Dec 2018 09:29:25 +0000 Subject: [PATCH 139/254] Test and small fix for response-topic and correlation-data props. --- src/handle_publish.c | 10 +-- ...12-prop-response-topic-correlation-data.py | 61 +++++++++++++++++++ test/broker/12-prop-response-topic.py | 60 ++++++++++++++++++ test/broker/Makefile | 2 + test/broker/ptest.py | 2 + 5 files changed, 128 insertions(+), 7 deletions(-) create mode 100755 test/broker/12-prop-response-topic-correlation-data.py create mode 100755 test/broker/12-prop-response-topic.py diff --git a/src/handle_publish.c b/src/handle_publish.c index 8cb1144996..f328a77e9b 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -158,10 +158,11 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) msg_properties_last = NULL; while(p){ switch(p->identifier){ - case MQTT_PROP_PAYLOAD_FORMAT_INDICATOR: + case MQTT_PROP_CONTENT_TYPE: case MQTT_PROP_CORRELATION_DATA: + case MQTT_PROP_PAYLOAD_FORMAT_INDICATOR: + case MQTT_PROP_RESPONSE_TOPIC: case MQTT_PROP_USER_PROPERTY: - case MQTT_PROP_CONTENT_TYPE: if(msg_properties){ msg_properties_last->next = p; msg_properties_last = p; @@ -184,11 +185,6 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) p = p->next; break; - case MQTT_PROP_RESPONSE_TOPIC: - p_prev = p; - p = p->next; - break; - case MQTT_PROP_MESSAGE_EXPIRY_INTERVAL: message_expiry_interval = p->value.i32; p_prev = p; diff --git a/test/broker/12-prop-response-topic-correlation-data.py b/test/broker/12-prop-response-topic-correlation-data.py new file mode 100755 index 0000000000..9a04382585 --- /dev/null +++ b/test/broker/12-prop-response-topic-correlation-data.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python + +# client 1 subscribes to normal-topic +# client 2 susbscribes to response-topic +# client 2 publishes message to normal-topic with response-topic property and correlation-data property +# client 1 receives message, publishes a response on response-topic +# client 2 receives message, checks payload + +from mosq_test_helper import * + +rc = 1 + +keepalive = 10 + +connect_packet1 = mosq_test.gen_connect("client1", proto_ver=5, keepalive=keepalive) +connect_packet2 = mosq_test.gen_connect("client2", proto_ver=5, keepalive=keepalive) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +subscribe_packet1 = mosq_test.gen_subscribe(mid=1, topic="normal/topic", qos=0, proto_ver=5) +subscribe_packet2 = mosq_test.gen_subscribe(mid=1, topic="response/topic", qos=0, proto_ver=5) +suback_packet = mosq_test.gen_suback(mid=1, qos=0, proto_ver=5) + +props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_RESPONSE_TOPIC, "response/topic") +props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_CORRELATION_DATA, "45vyvynq30q3vt4 nuy893b4v3") +props = mqtt5_props.prop_finalise(props) +publish_packet2 = mosq_test.gen_publish(topic="normal/topic", qos=0, payload="2", proto_ver=5, properties=props) + +publish_packet1 = mosq_test.gen_publish(topic="response/topic", qos=0, payload="22", proto_ver=5) + +disconnect_client_packet = mosq_test.gen_disconnect(proto_ver=5, properties=props) + +disconnect_server_packet = mosq_test.gen_disconnect(proto_ver=5, reason_code=130) + +port = mosq_test.get_port() +broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port) + +try: + sock1 = mosq_test.do_client_connect(connect_packet1, connack_packet, port=port) + sock2 = mosq_test.do_client_connect(connect_packet2, connack_packet, port=port) + + mosq_test.do_send_receive(sock1, subscribe_packet1, suback_packet, "subscribe1") + mosq_test.do_send_receive(sock2, subscribe_packet2, suback_packet, "subscribe2") + + sock2.send(publish_packet2) + if mosq_test.expect_packet(sock1, "publish1", publish_packet2): + # FIXME - it would be better to extract the property and payload, even though we know them + sock1.send(publish_packet1) + if mosq_test.expect_packet(sock2, "publish2", publish_packet1): + rc = 0 + + sock1.close() + sock2.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/12-prop-response-topic.py b/test/broker/12-prop-response-topic.py new file mode 100755 index 0000000000..3b9c3e8bf4 --- /dev/null +++ b/test/broker/12-prop-response-topic.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python + +# client 1 subscribes to normal-topic +# client 2 susbscribes to response-topic +# client 2 publishes message to normal-topic with response-topic property +# client 1 receives message, publishes a response on response-topic +# client 2 receives message, checks payload + +from mosq_test_helper import * + +rc = 1 + +keepalive = 10 + +connect_packet1 = mosq_test.gen_connect("client1", proto_ver=5, keepalive=keepalive) +connect_packet2 = mosq_test.gen_connect("client2", proto_ver=5, keepalive=keepalive) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +subscribe_packet1 = mosq_test.gen_subscribe(mid=1, topic="normal/topic", qos=0, proto_ver=5) +subscribe_packet2 = mosq_test.gen_subscribe(mid=1, topic="response/topic", qos=0, proto_ver=5) +suback_packet = mosq_test.gen_suback(mid=1, qos=0, proto_ver=5) + +props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_RESPONSE_TOPIC, "response/topic") +props = mqtt5_props.prop_finalise(props) +publish_packet2 = mosq_test.gen_publish(topic="normal/topic", qos=0, payload="2", proto_ver=5, properties=props) + +publish_packet1 = mosq_test.gen_publish(topic="response/topic", qos=0, payload="22", proto_ver=5) + +disconnect_client_packet = mosq_test.gen_disconnect(proto_ver=5, properties=props) + +disconnect_server_packet = mosq_test.gen_disconnect(proto_ver=5, reason_code=130) + +port = mosq_test.get_port() +broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port) + +try: + sock1 = mosq_test.do_client_connect(connect_packet1, connack_packet, port=port) + sock2 = mosq_test.do_client_connect(connect_packet2, connack_packet, port=port) + + mosq_test.do_send_receive(sock1, subscribe_packet1, suback_packet, "subscribe1") + mosq_test.do_send_receive(sock2, subscribe_packet2, suback_packet, "subscribe2") + + sock2.send(publish_packet2) + if mosq_test.expect_packet(sock1, "publish1", publish_packet2): + # FIXME - it would be better to extract the property and payload, even though we know them + sock1.send(publish_packet1) + if mosq_test.expect_packet(sock2, "publish2", publish_packet1): + rc = 0 + + sock1.close() + sock2.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index 0b9bf16908..3105c62ad1 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -141,3 +141,5 @@ endif ./12-prop-subpub-content-type.py ./12-prop-assigned-client-identifier.py ./12-prop-server-keepalive.py + ./12-prop-response-topic.py + ./12-prop-response-topic-correlation-data.py diff --git a/test/broker/ptest.py b/test/broker/ptest.py index a9772aa5ab..2804dfd86f 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -110,6 +110,8 @@ (1, './12-prop-subpub-content-type.py'), (1, './12-prop-assigned-client-identifier.py'), (1, './12-prop-server-keepalive.py'), + (1, './12-prop-response-topic.py'), + (1, './12-prop-response-topic-correlation-data.py'), ] minport = 1888 From 73c46174f8135c5d4a5bf2592552c78d2d240d5e Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 6 Dec 2018 10:45:57 +0000 Subject: [PATCH 140/254] Don't call on_disconnect() twice if keepalive tests fail. Closes #1067. Thanks to xingchen02. Bug: https://github.com/eclipse/mosquitto/issues/1067 --- ChangeLog.txt | 1 + lib/loop.c | 26 +------------------------- lib/util_mosq.c | 9 ++++++--- lib/util_mosq.h | 4 ++-- 4 files changed, 10 insertions(+), 30 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index ec08285591..c3a6c60a17 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -17,6 +17,7 @@ Broker: Library: - Fix reconnect delay backoff behaviour. Closes #1027. +- Don't call on_disconnect() twice if keepalive tests fail. Closes #1067. Client: - Always print leading zeros in mosquitto_sub when output format is hex. diff --git a/lib/loop.c b/lib/loop.c index b8fd2c5764..4b27775226 100644 --- a/lib/loop.c +++ b/lib/loop.c @@ -292,31 +292,7 @@ int mosquitto_loop_misc(struct mosquitto *mosq) if(!mosq) return MOSQ_ERR_INVAL; if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; - mosquitto__check_keepalive(mosq); - now = mosquitto_time(); - - if(mosq->ping_t && now - mosq->ping_t >= mosq->keepalive){ - /* mosq->ping_t != 0 means we are waiting for a pingresp. - * This hasn't happened in the keepalive time so we should disconnect. - */ - net__socket_close(mosq); - pthread_mutex_lock(&mosq->state_mutex); - if(mosq->state == mosq_cs_disconnecting){ - rc = MOSQ_ERR_SUCCESS; - }else{ - rc = MOSQ_ERR_KEEPALIVE; - } - pthread_mutex_unlock(&mosq->state_mutex); - pthread_mutex_lock(&mosq->callback_mutex); - if(mosq->on_disconnect){ - mosq->in_callback = true; - mosq->on_disconnect(mosq, mosq->userdata, rc); - mosq->in_callback = false; - } - pthread_mutex_unlock(&mosq->callback_mutex); - return MOSQ_ERR_CONN_LOST; - } - return MOSQ_ERR_SUCCESS; + return mosquitto__check_keepalive(mosq); } diff --git a/lib/util_mosq.c b/lib/util_mosq.c index 56d8cb0564..405cb3900b 100644 --- a/lib/util_mosq.c +++ b/lib/util_mosq.c @@ -46,9 +46,9 @@ and the Eclipse Distribution License is available at #endif #ifdef WITH_BROKER -void mosquitto__check_keepalive(struct mosquitto_db *db, struct mosquitto *mosq) +int mosquitto__check_keepalive(struct mosquitto_db *db, struct mosquitto *mosq) #else -void mosquitto__check_keepalive(struct mosquitto *mosq) +int mosquitto__check_keepalive(struct mosquitto *mosq) #endif { time_t next_msg_out; @@ -67,7 +67,7 @@ void mosquitto__check_keepalive(struct mosquitto *mosq) log__printf(NULL, MOSQ_LOG_NOTICE, "Bridge connection %s has exceeded idle timeout, disconnecting.", mosq->id); net__socket_close(db, mosq); - return; + return MOSQ_ERR_SUCCESS; } #endif pthread_mutex_lock(&mosq->msgtime_mutex); @@ -108,9 +108,12 @@ void mosquitto__check_keepalive(struct mosquitto *mosq) mosq->in_callback = false; } pthread_mutex_unlock(&mosq->callback_mutex); + + return rc; #endif } } + return MOSQ_ERR_SUCCESS; } uint16_t mosquitto__mid_generate(struct mosquitto *mosq) diff --git a/lib/util_mosq.h b/lib/util_mosq.h index 0e65dd9889..8e601a0ffd 100644 --- a/lib/util_mosq.h +++ b/lib/util_mosq.h @@ -26,9 +26,9 @@ and the Eclipse Distribution License is available at #endif #ifdef WITH_BROKER -void mosquitto__check_keepalive(struct mosquitto_db *db, struct mosquitto *mosq); +int mosquitto__check_keepalive(struct mosquitto_db *db, struct mosquitto *mosq); #else -void mosquitto__check_keepalive(struct mosquitto *mosq); +int mosquitto__check_keepalive(struct mosquitto *mosq); #endif uint16_t mosquitto__mid_generate(struct mosquitto *mosq); FILE *mosquitto__fopen(const char *path, const char *mode, bool restrict_read); From 608b8d33e7b49ba72f74f6b4c53a32c6574b1952 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 6 Dec 2018 10:55:58 +0000 Subject: [PATCH 141/254] Remove no longer used file. --- test/broker/01-connect-uname-password-success-no-tls.conf | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 test/broker/01-connect-uname-password-success-no-tls.conf diff --git a/test/broker/01-connect-uname-password-success-no-tls.conf b/test/broker/01-connect-uname-password-success-no-tls.conf deleted file mode 100644 index 776e304503..0000000000 --- a/test/broker/01-connect-uname-password-success-no-tls.conf +++ /dev/null @@ -1,3 +0,0 @@ -port 9999 -password_file 01-connect-uname-password-success-no-tls.pwfile -allow_anonymous false From 4fe75b1af031d6af722b64dd8d4188c94afe281e Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 6 Dec 2018 16:59:53 +0000 Subject: [PATCH 142/254] Make user functions for reading properties easier to use. --- lib/actions.c | 74 ++++++-- lib/connect.c | 33 +++- lib/handle_connack.c | 23 +-- lib/linker.version | 1 - lib/mosquitto.h | 171 +++++++++++------ lib/property_mosq.c | 193 ++++++++++++-------- lib/property_mosq.h | 1 + test/lib/03-request-response-correlation.py | 12 +- test/lib/c/03-request-response-2.c | 10 +- 9 files changed, 344 insertions(+), 174 deletions(-) diff --git a/lib/actions.c b/lib/actions.c index 38074b1be9..653881955d 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -39,15 +39,32 @@ int mosquitto_publish_v5(struct mosquitto *mosq, int *mid, const char *topic, in uint16_t local_mid; int queue_status; const mosquitto_property *p; + const mosquitto_property *outgoing_properties = NULL; + mosquitto_property local_property; bool have_topic_alias; int rc; if(!mosq || qos<0 || qos>2) return MOSQ_ERR_INVAL; + if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED; + + if(properties){ + if(properties->client_generated){ + outgoing_properties = properties; + }else{ + memcpy(&local_property, properties, sizeof(mosquitto_property)); + local_property.client_generated = true; + local_property.next = NULL; + outgoing_properties = &local_property; + } + rc = mosquitto_property_check_all(CMD_PUBLISH, outgoing_properties); + if(rc) return rc; + } + if(!topic || STREMPTY(topic)){ if(topic) topic = NULL; if(mosq->protocol == mosq_p_mqtt5){ - p = properties; + p = outgoing_properties; have_topic_alias = false; while(p){ if(p->identifier == MQTT_PROP_TOPIC_ALIAS){ @@ -69,10 +86,6 @@ int mosquitto_publish_v5(struct mosquitto *mosq, int *mid, const char *topic, in return MOSQ_ERR_INVAL; } } - if(properties){ - rc = mosquitto_property_check_all(CMD_PUBLISH, properties); - if(rc) return rc; - } local_mid = mosquitto__mid_generate(mosq); if(mid){ @@ -80,7 +93,7 @@ int mosquitto_publish_v5(struct mosquitto *mosq, int *mid, const char *topic, in } if(qos == 0){ - return send__publish(mosq, local_mid, topic, payloadlen, payload, qos, retain, false, properties); + return send__publish(mosq, local_mid, topic, payloadlen, payload, qos, retain, false, outgoing_properties); }else{ message = mosquitto__calloc(1, sizeof(struct mosquitto_message_all)); if(!message) return MOSQ_ERR_NOMEM; @@ -120,7 +133,7 @@ int mosquitto_publish_v5(struct mosquitto *mosq, int *mid, const char *topic, in message->state = mosq_ms_wait_for_pubrec; } pthread_mutex_unlock(&mosq->out_message_mutex); - return send__publish(mosq, message->msg.mid, message->msg.topic, message->msg.payloadlen, message->msg.payload, message->msg.qos, message->msg.retain, message->dup, properties); + return send__publish(mosq, message->msg.mid, message->msg.topic, message->msg.payloadlen, message->msg.payload, message->msg.qos, message->msg.retain, message->dup, outgoing_properties); }else{ message->state = mosq_ms_invalid; pthread_mutex_unlock(&mosq->out_message_mutex); @@ -137,34 +150,57 @@ int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const char *sub, int q int mosquitto_subscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, int qos, const mosquitto_property *properties) { + const mosquitto_property *outgoing_properties = NULL; + mosquitto_property local_property; + int rc; if(!mosq) return MOSQ_ERR_INVAL; + if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED; if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; if(mosquitto_sub_topic_check(sub)) return MOSQ_ERR_INVAL; if(mosquitto_validate_utf8(sub, strlen(sub))) return MOSQ_ERR_MALFORMED_UTF8; if(properties){ - rc = mosquitto_property_check_all(CMD_SUBSCRIBE, properties); + if(properties->client_generated){ + outgoing_properties = properties; + }else{ + memcpy(&local_property, properties, sizeof(mosquitto_property)); + local_property.client_generated = true; + local_property.next = NULL; + outgoing_properties = &local_property; + } + rc = mosquitto_property_check_all(CMD_SUBSCRIBE, outgoing_properties); if(rc) return rc; } - return send__subscribe(mosq, mid, 1, (char *const *const)&sub, qos, properties); + return send__subscribe(mosq, mid, 1, (char *const *const)&sub, qos, outgoing_properties); } int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, int qos, const mosquitto_property *properties) { + const mosquitto_property *outgoing_properties = NULL; + mosquitto_property local_property; int i; int rc; if(!mosq || !sub_count || !sub) return MOSQ_ERR_INVAL; + if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED; if(qos < 0 || qos > 2) return MOSQ_ERR_INVAL; if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; - if(mosq->protocol == mosq_p_mqtt5 && properties){ - rc = mosquitto_property_check_all(CMD_SUBSCRIBE, properties); + if(properties){ + if(properties->client_generated){ + outgoing_properties = properties; + }else{ + memcpy(&local_property, properties, sizeof(mosquitto_property)); + local_property.client_generated = true; + local_property.next = NULL; + outgoing_properties = &local_property; + } + rc = mosquitto_property_check_all(CMD_SUBSCRIBE, outgoing_properties); if(rc) return rc; } @@ -184,18 +220,30 @@ int mosquitto_unsubscribe(struct mosquitto *mosq, int *mid, const char *sub) int mosquitto_unsubscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, const mosquitto_property *properties) { + const mosquitto_property *outgoing_properties = NULL; + mosquitto_property local_property; int rc; if(!mosq) return MOSQ_ERR_INVAL; + if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED; if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; if(mosquitto_sub_topic_check(sub)) return MOSQ_ERR_INVAL; if(mosquitto_validate_utf8(sub, strlen(sub))) return MOSQ_ERR_MALFORMED_UTF8; if(properties){ - rc = mosquitto_property_check_all(CMD_PUBLISH, properties); + if(properties->client_generated){ + outgoing_properties = properties; + }else{ + memcpy(&local_property, properties, sizeof(mosquitto_property)); + local_property.client_generated = true; + local_property.next = NULL; + outgoing_properties = &local_property; + } + rc = mosquitto_property_check_all(CMD_UNSUBSCRIBE, outgoing_properties); if(rc) return rc; } - return send__unsubscribe(mosq, mid, sub, properties); + + return send__unsubscribe(mosq, mid, sub, outgoing_properties); } diff --git a/lib/connect.c b/lib/connect.c index 0de0032216..791aadd56b 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -149,10 +149,26 @@ int mosquitto_reconnect(struct mosquitto *mosq) static int mosquitto__reconnect(struct mosquitto *mosq, bool blocking, const mosquitto_property *properties) { + const mosquitto_property *outgoing_properties = NULL; + mosquitto_property local_property; int rc; struct mosquitto__packet *packet; if(!mosq) return MOSQ_ERR_INVAL; if(!mosq->host || mosq->port <= 0) return MOSQ_ERR_INVAL; + if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED; + + if(properties){ + if(properties->client_generated){ + outgoing_properties = properties; + }else{ + memcpy(&local_property, properties, sizeof(mosquitto_property)); + local_property.client_generated = true; + local_property.next = NULL; + outgoing_properties = &local_property; + } + rc = mosquitto_property_check_all(CMD_DISCONNECT, outgoing_properties); + if(rc) return rc; + } pthread_mutex_lock(&mosq->state_mutex); #ifdef WITH_SOCKS @@ -223,7 +239,7 @@ static int mosquitto__reconnect(struct mosquitto *mosq, bool blocking, const mos }else #endif { - return send__connect(mosq, mosq->keepalive, mosq->clean_start, properties); + return send__connect(mosq, mosq->keepalive, mosq->clean_start, outgoing_properties); } } @@ -235,11 +251,22 @@ int mosquitto_disconnect(struct mosquitto *mosq) int mosquitto_disconnect_v5(struct mosquitto *mosq, int reason_code, const mosquitto_property *properties) { + const mosquitto_property *outgoing_properties = NULL; + mosquitto_property local_property; int rc; if(!mosq) return MOSQ_ERR_INVAL; + if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED; if(properties){ - rc = mosquitto_property_check_all(CMD_DISCONNECT, properties); + if(properties->client_generated){ + outgoing_properties = properties; + }else{ + memcpy(&local_property, properties, sizeof(mosquitto_property)); + local_property.client_generated = true; + local_property.next = NULL; + outgoing_properties = &local_property; + } + rc = mosquitto_property_check_all(CMD_DISCONNECT, outgoing_properties); if(rc) return rc; } @@ -248,7 +275,7 @@ int mosquitto_disconnect_v5(struct mosquitto *mosq, int reason_code, const mosqu pthread_mutex_unlock(&mosq->state_mutex); if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; - return send__disconnect(mosq, reason_code, properties); + return send__disconnect(mosq, reason_code, outgoing_properties); } diff --git a/lib/handle_connack.c b/lib/handle_connack.c index 7cd65d4e94..5e5fa86df0 100644 --- a/lib/handle_connack.c +++ b/lib/handle_connack.c @@ -34,7 +34,7 @@ int handle__connack(struct mosquitto *mosq) uint8_t reason_code; int rc; mosquitto_property *properties = NULL; - const mosquitto_property *prop; + char *clientid = NULL; assert(mosq); rc = packet__read_byte(&mosq->in_packet, &connect_flags); @@ -47,30 +47,21 @@ int handle__connack(struct mosquitto *mosq) if(rc) return rc; } - prop = mosquitto_property_get_property(properties, MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER, false); - if(prop){ + mosquitto_property_read_string(properties, MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER, &clientid, false); + if(clientid){ if(mosq->id){ /* We've been sent a client identifier but already have one. This * shouldn't happen. */ + free(clientid); mosquitto_property_free_all(&properties); return MOSQ_ERR_PROTOCOL; }else{ - rc = mosquitto_property_read_string(prop, &mosq->id); - if(rc){ - mosquitto_property_free_all(&properties); - return rc; - } + mosq->id = clientid; + clientid = NULL; } } - prop = mosquitto_property_get_property(properties, MQTT_PROP_SERVER_KEEP_ALIVE, false); - if(prop){ - rc = mosquitto_property_read_int16(prop, &mosq->keepalive); - if(rc){ - mosquitto_property_free_all(&properties); - return rc; - } - } + mosquitto_property_read_int16(properties, MQTT_PROP_SERVER_KEEP_ALIVE, &mosq->keepalive, false); log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received CONNACK (%d)", mosq->id, reason_code); pthread_mutex_lock(&mosq->callback_mutex); diff --git a/lib/linker.version b/lib/linker.version index b1be3a11cd..e9ee68ca0a 100644 --- a/lib/linker.version +++ b/lib/linker.version @@ -106,7 +106,6 @@ MOSQ_1.6 { mosquitto_property_add_string; mosquitto_property_add_string_pair; mosquitto_property_add_varint; - mosquitto_property_get_property; mosquitto_property_read_binary; mosquitto_property_read_byte; mosquitto_property_read_int16; diff --git a/lib/mosquitto.h b/lib/mosquitto.h index e641a8d14c..f8ca07940f 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -2428,17 +2428,26 @@ libmosq_EXPORT int mosquitto_property_add_string(mosquitto_property **proplist, libmosq_EXPORT int mosquitto_property_add_string_pair(mosquitto_property **proplist, int identifier, const char *name, const char *value); /* - * Function: mosquitto_property_get_property + * Function: mosquitto_property_read_byte + * + * Attempt to read a byte property matching an identifier, from a property list + * or single property. This function can search for multiple entries of the + * same identifier by using the returned value and skip_first. Note however + * that it is forbidden for most properties to be duplicated. * - * Retrieve a property matching an identifier, from a property list. This - * function can search for multiple entries of an identifier by using the - * returned value and skip_first. + * If the property is not found, *value will not be modified, so it is safe to + * pass a variable with a default value to be potentially overwritten: + * + * uint16_t keepalive = 60; // default value + * // Get value from property list, or keep default if not found. + * mosquitto_property_read_int16(proplist, MQTT_PROP_SERVER_KEEP_ALIVE, &keepalive, false); * * Parameters: - * proplist - mosquitto_property pointer, the list of properties + * proplist - mosquitto_property pointer, the list of properties or single property * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) + * value - pointer to store the value, or NULL if the value is not required. * skip_first - boolean that indicates whether the first item in the list - * should be ignored or not. + * should be ignored or not. Should usually be set to false. * * Returns: * A valid property pointer if the property is found @@ -2447,30 +2456,17 @@ libmosq_EXPORT int mosquitto_property_add_string_pair(mosquitto_property **propl * Example: * // proplist is obtained from a callback * mosquitto_property *prop; - * prop = mosquitto_property_get_property(proplist, MQTT_PROP_USER_PROPERTY, false); + * prop = mosquitto_property_read_byte(proplist, identifier, &value, false); * while(prop){ - * mosquitto_property_read_string_pair(prop, &key, &value); - * printf("key: %s value: %s\n", key, value); - * - * prop = mosquitto_property_get_property(prop, MQTT_PROP_USER_PROPERTY, true); + * printf("value: %s\n", value); + * prop = mosquitto_property_read_byte(prop, identifier, &value); * } */ -libmosq_EXPORT const mosquitto_property *mosquitto_property_get_property(const mosquitto_property *proplist, int identifier, bool skip_first); - -/* - * Function: mosquitto_property_read_byte - * - * Read a byte property value from a property. - * - * Parameters: - * property - property to read - * value - pointer to integer, for the property to be stored in - * - * Returns: - * MOSQ_ERR_SUCCESS - on success - * MOSQ_ERR_INVAL - if property or value is NULL, or if property is not a byte - */ -libmosq_EXPORT int mosquitto_property_read_byte(const mosquitto_property *property, uint8_t *value); +libmosq_EXPORT const mosquitto_property *mosquitto_property_read_byte( + const mosquitto_property *proplist, + int identifier, + uint8_t *value, + bool skip_first); /* * Function: mosquitto_property_read_int16 @@ -2479,13 +2475,23 @@ libmosq_EXPORT int mosquitto_property_read_byte(const mosquitto_property *proper * * Parameters: * property - property to read - * value - pointer to integer, for the property to be stored in + * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) + * value - pointer to store the value, or NULL if the value is not required. + * skip_first - boolean that indicates whether the first item in the list + * should be ignored or not. Should usually be set to false. * * Returns: - * MOSQ_ERR_SUCCESS - on success - * MOSQ_ERR_INVAL - if property or value is NULL, or if property is not a uint16 + * A valid property pointer if the property is found + * NULL, if the property is not found, or proplist is NULL. + * + * Example: + * See */ -libmosq_EXPORT int mosquitto_property_read_int16(const mosquitto_property *property, uint16_t *value); +libmosq_EXPORT const mosquitto_property *mosquitto_property_read_int16( + const mosquitto_property *proplist, + int identifier, + uint16_t *value, + bool skip_first); /* * Function: mosquitto_property_read_int32 @@ -2494,13 +2500,23 @@ libmosq_EXPORT int mosquitto_property_read_int16(const mosquitto_property *prope * * Parameters: * property - pointer to mosquitto_property pointer, the list of properties - * value - pointer to integer, for the property to be stored in + * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) + * value - pointer to store the value, or NULL if the value is not required. + * skip_first - boolean that indicates whether the first item in the list + * should be ignored or not. Should usually be set to false. * * Returns: - * MOSQ_ERR_SUCCESS - on success - * MOSQ_ERR_INVAL - if property or value is NULL, or if property is not an int32 + * A valid property pointer if the property is found + * NULL, if the property is not found, or proplist is NULL. + * + * Example: + * See */ -libmosq_EXPORT int mosquitto_property_read_int32(const mosquitto_property *property, uint32_t *value); +libmosq_EXPORT const mosquitto_property *mosquitto_property_read_int32( + const mosquitto_property *proplist, + int identifier, + uint32_t *value, + bool skip_first); /* * Function: mosquitto_property_read_varint @@ -2509,13 +2525,23 @@ libmosq_EXPORT int mosquitto_property_read_int32(const mosquitto_property *prope * * Parameters: * property - property to read - * value - pointer to integer, for the property to be stored in + * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) + * value - pointer to store the value, or NULL if the value is not required. + * skip_first - boolean that indicates whether the first item in the list + * should be ignored or not. Should usually be set to false. * * Returns: - * MOSQ_ERR_SUCCESS - on success - * MOSQ_ERR_INVAL - if property or value is NULL, or if property is not a varint + * A valid property pointer if the property is found + * NULL, if the property is not found, or proplist is NULL. + * + * Example: + * See */ -libmosq_EXPORT int mosquitto_property_read_varint(const mosquitto_property *property, uint32_t *value); +libmosq_EXPORT const mosquitto_property *mosquitto_property_read_varint( + const mosquitto_property *proplist, + int identifier, + uint32_t *value, + bool skip_first); /* * Function: mosquitto_property_read_binary @@ -2526,15 +2552,24 @@ libmosq_EXPORT int mosquitto_property_read_varint(const mosquitto_property *prop * * Parameters: * property - property to read - * value - pointer to void pointer, for the property data to be stored in - * len - int pointer to store the data length + * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) + * value - pointer to store the value, or NULL if the value is not required. + * skip_first - boolean that indicates whether the first item in the list + * should be ignored or not. Should usually be set to false. * * Returns: - * MOSQ_ERR_SUCCESS - on success - * MOSQ_ERR_INVAL - if property, len, or value is NULL, or if property is not a binary type - * MOSQ_ERR_NOMEM - on out of memory + * A valid property pointer if the property is found + * NULL, if the property is not found, or proplist is NULL, or if an out of memory condition occurred. + * + * Example: + * See */ -libmosq_EXPORT int mosquitto_property_read_binary(const mosquitto_property *property, void **value, int *len); +libmosq_EXPORT const mosquitto_property *mosquitto_property_read_binary( + const mosquitto_property *proplist, + int identifier, + void **value, + int *len, + bool skip_first); /* * Function: mosquitto_property_read_string @@ -2545,14 +2580,24 @@ libmosq_EXPORT int mosquitto_property_read_binary(const mosquitto_property *prop * * Parameters: * property - property to read - * value - pointer to char*, for the property data to be stored in + * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) + * value - pointer to char*, for the property data to be stored in, or NULL if + * the value is not required. + * skip_first - boolean that indicates whether the first item in the list + * should be ignored or not. Should usually be set to false. * * Returns: - * MOSQ_ERR_SUCCESS - on success - * MOSQ_ERR_INVAL - if property or value is NULL, or if property is not a string - * MOSQ_ERR_NOMEM - on out of memory + * A valid property pointer if the property is found + * NULL, if the property is not found, or proplist is NULL, or if an out of memory condition occurred. + * + * Example: + * See */ -libmosq_EXPORT int mosquitto_property_read_string(const mosquitto_property *property, char **value); +libmosq_EXPORT const mosquitto_property *mosquitto_property_read_string( + const mosquitto_property *proplist, + int identifier, + char **value, + bool skip_first); /* * Function: mosquitto_property_read_string_pair @@ -2563,15 +2608,27 @@ libmosq_EXPORT int mosquitto_property_read_string(const mosquitto_property *prop * * Parameters: * property - property to read - * name - pointer to char* for the name property data to be stored in - * value - pointer to char* for the value property data to be stored in + * identifier - property identifier (e.g. MQTT_PROP_PAYLOAD_FORMAT_INDICATOR) + * name - pointer to char* for the name property data to be stored in, or NULL + * if the name is not required. + * value - pointer to char*, for the property data to be stored in, or NULL if + * the value is not required. + * skip_first - boolean that indicates whether the first item in the list + * should be ignored or not. Should usually be set to false. * * Returns: - * MOSQ_ERR_SUCCESS - on success - * MOSQ_ERR_INVAL - if property, name, or value is NULL, or if property is not a string pair - * MOSQ_ERR_NOMEM - on out of memory - */ -libmosq_EXPORT int mosquitto_property_read_string_pair(const mosquitto_property *property, char **name, char **value); + * A valid property pointer if the property is found + * NULL, if the property is not found, or proplist is NULL, or if an out of memory condition occurred. + * + * Example: + * See + */ +libmosq_EXPORT const mosquitto_property *mosquitto_property_read_string_pair( + const mosquitto_property *proplist, + int identifier, + char **name, + char **value, + bool skip_first); /* * Function: mosquitto_property_free_all diff --git a/lib/property_mosq.c b/lib/property_mosq.c index 40fc3909b1..ae2d02bb5c 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -636,6 +636,7 @@ int mosquitto_property_add_byte(mosquitto_property **proplist, int identifier, u prop = mosquitto__calloc(1, sizeof(mosquitto_property)); if(!prop) return MOSQ_ERR_NOMEM; + prop->client_generated = true; prop->identifier = identifier; prop->value.i8 = value; @@ -659,6 +660,7 @@ int mosquitto_property_add_int16(mosquitto_property **proplist, int identifier, prop = mosquitto__calloc(1, sizeof(mosquitto_property)); if(!prop) return MOSQ_ERR_NOMEM; + prop->client_generated = true; prop->identifier = identifier; prop->value.i16 = value; @@ -683,6 +685,7 @@ int mosquitto_property_add_int32(mosquitto_property **proplist, int identifier, prop = mosquitto__calloc(1, sizeof(mosquitto_property)); if(!prop) return MOSQ_ERR_NOMEM; + prop->client_generated = true; prop->identifier = identifier; prop->value.i32 = value; @@ -701,6 +704,7 @@ int mosquitto_property_add_varint(mosquitto_property **proplist, int identifier, prop = mosquitto__calloc(1, sizeof(mosquitto_property)); if(!prop) return MOSQ_ERR_NOMEM; + prop->client_generated = true; prop->identifier = identifier; prop->value.varint = value; @@ -723,6 +727,7 @@ int mosquitto_property_add_binary(mosquitto_property **proplist, int identifier, prop = mosquitto__calloc(1, sizeof(mosquitto_property)); if(!prop) return MOSQ_ERR_NOMEM; + prop->client_generated = true; prop->identifier = identifier; if(len){ @@ -764,6 +769,7 @@ int mosquitto_property_add_string(mosquitto_property **proplist, int identifier, prop = mosquitto__calloc(1, sizeof(mosquitto_property)); if(!prop) return MOSQ_ERR_NOMEM; + prop->client_generated = true; prop->identifier = identifier; if(value && strlen(value)){ prop->value.s.v = mosquitto__strdup(value); @@ -795,6 +801,7 @@ int mosquitto_property_add_string_pair(mosquitto_property **proplist, int identi prop = mosquitto__calloc(1, sizeof(mosquitto_property)); if(!prop) return MOSQ_ERR_NOMEM; + prop->client_generated = true; prop->identifier = identifier; if(name && strlen(name)){ @@ -873,7 +880,7 @@ int mosquitto_property_check_all(int command, const mosquitto_property *properti return MOSQ_ERR_SUCCESS; } -const mosquitto_property *mosquitto_property_get_property(const mosquitto_property *proplist, int identifier, bool skip_first) +const mosquitto_property *property__get_property(const mosquitto_property *proplist, int identifier, bool skip_first) { const mosquitto_property *p; bool is_first = true; @@ -893,132 +900,168 @@ const mosquitto_property *mosquitto_property_get_property(const mosquitto_proper } -int mosquitto_property_read_byte(const mosquitto_property *property, uint8_t *value) +const mosquitto_property *mosquitto_property_read_byte(const mosquitto_property *proplist, int identifier, uint8_t *value, bool skip_first) { - if(!property || !value) return MOSQ_ERR_INVAL; - if(property->identifier != MQTT_PROP_PAYLOAD_FORMAT_INDICATOR - && property->identifier != MQTT_PROP_REQUEST_PROBLEM_INFORMATION - && property->identifier != MQTT_PROP_REQUEST_RESPONSE_INFORMATION - && property->identifier != MQTT_PROP_MAXIMUM_QOS - && property->identifier != MQTT_PROP_RETAIN_AVAILABLE - && property->identifier != MQTT_PROP_WILDCARD_SUB_AVAILABLE - && property->identifier != MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE - && property->identifier != MQTT_PROP_SHARED_SUB_AVAILABLE){ - return MOSQ_ERR_INVAL; + const mosquitto_property *p; + if(!proplist) return NULL; + + p = property__get_property(proplist, identifier, skip_first); + if(!p) return NULL; + if(p->identifier != MQTT_PROP_PAYLOAD_FORMAT_INDICATOR + && p->identifier != MQTT_PROP_REQUEST_PROBLEM_INFORMATION + && p->identifier != MQTT_PROP_REQUEST_RESPONSE_INFORMATION + && p->identifier != MQTT_PROP_MAXIMUM_QOS + && p->identifier != MQTT_PROP_RETAIN_AVAILABLE + && p->identifier != MQTT_PROP_WILDCARD_SUB_AVAILABLE + && p->identifier != MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE + && p->identifier != MQTT_PROP_SHARED_SUB_AVAILABLE){ + return NULL; } - *value = property->value.i8; + if(value) *value = p->value.i8; - return MOSQ_ERR_SUCCESS; + return p; } -int mosquitto_property_read_int16(const mosquitto_property *property, uint16_t *value) +const mosquitto_property *mosquitto_property_read_int16(const mosquitto_property *proplist, int identifier, uint16_t *value, bool skip_first) { - if(!property || !value) return MOSQ_ERR_INVAL; - if(property->identifier != MQTT_PROP_SERVER_KEEP_ALIVE - && property->identifier != MQTT_PROP_RECEIVE_MAXIMUM - && property->identifier != MQTT_PROP_TOPIC_ALIAS_MAXIMUM - && property->identifier != MQTT_PROP_TOPIC_ALIAS){ - return MOSQ_ERR_INVAL; + const mosquitto_property *p; + if(!proplist) return NULL; + + p = property__get_property(proplist, identifier, skip_first); + if(!p) return NULL; + if(p->identifier != MQTT_PROP_SERVER_KEEP_ALIVE + && p->identifier != MQTT_PROP_RECEIVE_MAXIMUM + && p->identifier != MQTT_PROP_TOPIC_ALIAS_MAXIMUM + && p->identifier != MQTT_PROP_TOPIC_ALIAS){ + return NULL; } - *value = property->value.i16; + if(value) *value = p->value.i16; - return MOSQ_ERR_SUCCESS; + return p; } -int mosquitto_property_read_int32(const mosquitto_property *property, uint32_t *value) +const mosquitto_property *mosquitto_property_read_int32(const mosquitto_property *proplist, int identifier, uint32_t *value, bool skip_first) { - if(!property || !value) return MOSQ_ERR_INVAL; - if(property->identifier != MQTT_PROP_MESSAGE_EXPIRY_INTERVAL - && property->identifier != MQTT_PROP_SESSION_EXPIRY_INTERVAL - && property->identifier != MQTT_PROP_WILL_DELAY_INTERVAL - && property->identifier != MQTT_PROP_MAXIMUM_PACKET_SIZE){ + const mosquitto_property *p; + if(!proplist) return NULL; - return MOSQ_ERR_INVAL; + p = property__get_property(proplist, identifier, skip_first); + if(!p) return NULL; + if(p->identifier != MQTT_PROP_MESSAGE_EXPIRY_INTERVAL + && p->identifier != MQTT_PROP_SESSION_EXPIRY_INTERVAL + && p->identifier != MQTT_PROP_WILL_DELAY_INTERVAL + && p->identifier != MQTT_PROP_MAXIMUM_PACKET_SIZE){ + + return NULL; } - *value = property->value.i32; + if(value) *value = p->value.i32; - return MOSQ_ERR_SUCCESS; + return p; } -int mosquitto_property_read_varint(const mosquitto_property *property, uint32_t *value) +const mosquitto_property *mosquitto_property_read_varint(const mosquitto_property *proplist, int identifier, uint32_t *value, bool skip_first) { - if(!property || !value) return MOSQ_ERR_INVAL; - if(property->identifier != MQTT_PROP_SUBSCRIPTION_IDENTIFIER){ - return MOSQ_ERR_INVAL; + const mosquitto_property *p; + if(!proplist) return NULL; + + p = property__get_property(proplist, identifier, skip_first); + if(!p) return NULL; + if(p->identifier != MQTT_PROP_SUBSCRIPTION_IDENTIFIER){ + return NULL; } - *value = property->value.varint; + if(value) *value = p->value.varint; - return MOSQ_ERR_SUCCESS; + return p; } -int mosquitto_property_read_binary(const mosquitto_property *property, void **value, int *len) +const mosquitto_property *mosquitto_property_read_binary(const mosquitto_property *proplist, int identifier, void **value, int *len, bool skip_first) { - if(!property || !value || !len) return MOSQ_ERR_INVAL; - if(property->identifier != MQTT_PROP_CORRELATION_DATA - && property->identifier != MQTT_PROP_AUTHENTICATION_DATA){ + const mosquitto_property *p; + if(!proplist || (value && !len) || (!value && len)) return NULL; - return MOSQ_ERR_INVAL; + p = property__get_property(proplist, identifier, skip_first); + if(!p) return NULL; + if(p->identifier != MQTT_PROP_CORRELATION_DATA + && p->identifier != MQTT_PROP_AUTHENTICATION_DATA){ + + return NULL; } - *len = property->value.bin.len; - *value = malloc(*len); - if(!value) return MOSQ_ERR_NOMEM; + if(value){ + *len = p->value.bin.len; + *value = malloc(*len); + if(!value) return NULL; - memcpy(*value, property->value.bin.v, *len); + memcpy(*value, p->value.bin.v, *len); + } - return MOSQ_ERR_SUCCESS; + return p; } -int mosquitto_property_read_string(const mosquitto_property *property, char **value) +const mosquitto_property *mosquitto_property_read_string(const mosquitto_property *proplist, int identifier, char **value, bool skip_first) { - if(!property || !value) return MOSQ_ERR_INVAL; - if(property->identifier != MQTT_PROP_CONTENT_TYPE - && property->identifier != MQTT_PROP_RESPONSE_TOPIC - && property->identifier != MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER - && property->identifier != MQTT_PROP_AUTHENTICATION_METHOD - && property->identifier != MQTT_PROP_RESPONSE_INFORMATION - && property->identifier != MQTT_PROP_SERVER_REFERENCE - && property->identifier != MQTT_PROP_REASON_STRING){ - - return MOSQ_ERR_INVAL; + const mosquitto_property *p; + if(!proplist) return NULL; + + p = property__get_property(proplist, identifier, skip_first); + if(!p) return NULL; + if(p->identifier != MQTT_PROP_CONTENT_TYPE + && p->identifier != MQTT_PROP_RESPONSE_TOPIC + && p->identifier != MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER + && p->identifier != MQTT_PROP_AUTHENTICATION_METHOD + && p->identifier != MQTT_PROP_RESPONSE_INFORMATION + && p->identifier != MQTT_PROP_SERVER_REFERENCE + && p->identifier != MQTT_PROP_REASON_STRING){ + + return NULL; } - *value = calloc(1, property->value.s.len+1); - if(!value) return MOSQ_ERR_NOMEM; + if(value){ + *value = calloc(1, p->value.s.len+1); + if(!value) return NULL; + + memcpy(*value, p->value.s.v, p->value.s.len); + } - memcpy(*value, property->value.s.v, property->value.s.len); - return MOSQ_ERR_SUCCESS; + return p; } -int mosquitto_property_read_string_pair(const mosquitto_property *property, char **name, char **value) +const mosquitto_property *mosquitto_property_read_string_pair(const mosquitto_property *proplist, int identifier, char **name, char **value, bool skip_first) { - if(!property || !name || !value) return MOSQ_ERR_INVAL; - if(property->identifier != MQTT_PROP_USER_PROPERTY) return MOSQ_ERR_INVAL; + const mosquitto_property *p; + if(!proplist) return NULL; - *name = calloc(1, property->name.len+1); - if(!name) return MOSQ_ERR_NOMEM; + p = property__get_property(proplist, identifier, skip_first); + if(!p) return NULL; + if(p->identifier != MQTT_PROP_USER_PROPERTY) return NULL; - *value = calloc(1, property->value.s.len+1); - if(!value){ - free(*name); - return MOSQ_ERR_NOMEM; + if(name){ + *name = calloc(1, p->name.len+1); + if(!name) return NULL; + memcpy(*name, p->name.v, p->name.len); } - memcpy(*name, property->name.v, property->name.len); - memcpy(*value, property->value.s.v, property->value.s.len); + if(value){ + *value = calloc(1, p->value.s.len+1); + if(!value){ + if(name) free(*name); + return NULL; + } + memcpy(*value, p->value.s.v, p->value.s.len); + } - return MOSQ_ERR_SUCCESS; + return p; } diff --git a/lib/property_mosq.h b/lib/property_mosq.h index 97c11564e7..d31ce85e5e 100644 --- a/lib/property_mosq.h +++ b/lib/property_mosq.h @@ -36,6 +36,7 @@ struct mqtt5__property { } value; struct mqtt__string name; int32_t identifier; + bool client_generated; }; diff --git a/test/lib/03-request-response-correlation.py b/test/lib/03-request-response-correlation.py index b1ed9ccd58..a2ab54be50 100755 --- a/test/lib/03-request-response-correlation.py +++ b/test/lib/03-request-response-correlation.py @@ -23,7 +23,13 @@ props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_RESPONSE_TOPIC, resp_topic) props += mqtt5_props.gen_string_prop(mqtt5_props.PROP_CORRELATION_DATA, "corridor") props = mqtt5_props.prop_finalise(props) -publish1_packet = mosq_test.gen_publish(pub_topic, qos=0, payload="action", proto_ver=5, properties=props) +publish1_packet_incoming = mosq_test.gen_publish(pub_topic, qos=0, payload="action", proto_ver=5, properties=props) + +props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_RESPONSE_TOPIC, resp_topic) +props += mqtt5_props.gen_string_prop(mqtt5_props.PROP_CORRELATION_DATA, "corridor") +props += mqtt5_props.gen_string_pair_prop(mqtt5_props.PROP_USER_PROPERTY, "user", "data") +props = mqtt5_props.prop_finalise(props) +publish1_packet_outgoing = mosq_test.gen_publish(pub_topic, qos=0, payload="action", proto_ver=5, properties=props) props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_CORRELATION_DATA, "corridor") props = mqtt5_props.prop_finalise(props) @@ -65,8 +71,8 @@ if mosq_test.expect_packet(conn2, "subscribe2", subscribe2_packet): conn2.send(suback_packet) - if mosq_test.expect_packet(conn1, "publish1", publish1_packet): - conn2.send(publish1_packet) + if mosq_test.expect_packet(conn1, "publish1", publish1_packet_incoming): + conn2.send(publish1_packet_outgoing) if mosq_test.expect_packet(conn2, "publish2", publish2_packet): rc = 0 diff --git a/test/lib/c/03-request-response-2.c b/test/lib/c/03-request-response-2.c index 0f16f1efdf..3419f395d9 100644 --- a/test/lib/c/03-request-response-2.c +++ b/test/lib/c/03-request-response-2.c @@ -24,13 +24,11 @@ void on_message_v5(struct mosquitto *mosq, void *obj, const struct mosquitto_mes int rc; if(!strcmp(msg->topic, "request/topic")){ - p_resp = mosquitto_property_get_property(props, MQTT_PROP_RESPONSE_TOPIC, false); + p_resp = mosquitto_property_read_string(props, MQTT_PROP_RESPONSE_TOPIC, &resp_topic, false); if(p_resp){ - p_corr = mosquitto_property_get_property(props, MQTT_PROP_CORRELATION_DATA, false); - if(mosquitto_property_read_string(p_resp, &resp_topic) == MOSQ_ERR_SUCCESS){ - rc = mosquitto_publish_v5(mosq, NULL, resp_topic, strlen("a response"), "a response", 0, false, p_corr); - free(resp_topic); - } + p_corr = mosquitto_property_read_binary(props, MQTT_PROP_CORRELATION_DATA, NULL, NULL, false); + rc = mosquitto_publish_v5(mosq, NULL, resp_topic, strlen("a response"), "a response", 0, false, p_corr); + free(resp_topic); } } } From f90ba23738e1f89a73f2c8537af59dfb540ab5a6 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 6 Dec 2018 22:15:49 +0000 Subject: [PATCH 143/254] Retain handling support. --- lib/mosquitto.h | 1 + src/bridge.c | 8 ++++++-- src/handle_subscribe.c | 36 +++++++++++++++++++++++++++++++----- src/persist.c | 2 +- src/subs.c | 8 +++----- 5 files changed, 42 insertions(+), 13 deletions(-) diff --git a/lib/mosquitto.h b/lib/mosquitto.h index f8ca07940f..c5624c78b5 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -66,6 +66,7 @@ extern "C" { /* Error values */ enum mosq_err_t { + MOSQ_ERR_SUB_EXISTS = -2, MOSQ_ERR_CONN_PENDING = -1, MOSQ_ERR_SUCCESS = 0, MOSQ_ERR_NOMEM = 1, diff --git a/src/bridge.c b/src/bridge.c index 59e7b51641..80bed5501e 100644 --- a/src/bridge.c +++ b/src/bridge.c @@ -144,7 +144,9 @@ int bridge__connect_step1(struct mosquitto_db *db, struct mosquitto *context) for(i=0; ibridge->topic_count; i++){ if(context->bridge->topics[i].direction == bd_out || context->bridge->topics[i].direction == bd_both){ log__printf(NULL, MOSQ_LOG_DEBUG, "Bridge %s doing local SUBSCRIBE on topic %s", context->id, context->bridge->topics[i].local_topic); - if(sub__add(db, context, context->bridge->topics[i].local_topic, context->bridge->topics[i].qos, &db->subs)) return 1; + if(sub__add(db, context, context->bridge->topics[i].local_topic, context->bridge->topics[i].qos, &db->subs) > 0){ + return 1; + } sub__retain_queue(db, context, context->bridge->topics[i].local_topic, context->bridge->topics[i].qos); @@ -310,7 +312,9 @@ int bridge__connect(struct mosquitto_db *db, struct mosquitto *context) for(i=0; ibridge->topic_count; i++){ if(context->bridge->topics[i].direction == bd_out || context->bridge->topics[i].direction == bd_both){ log__printf(NULL, MOSQ_LOG_DEBUG, "Bridge %s doing local SUBSCRIBE on topic %s", context->id, context->bridge->topics[i].local_topic); - if(sub__add(db, context, context->bridge->topics[i].local_topic, context->bridge->topics[i].qos, &db->subs)) return 1; + if(sub__add(db, context, context->bridge->topics[i].local_topic, context->bridge->topics[i].qos, &db->subs) > 0){ + return 1; + } sub__retain_queue(db, context, context->bridge->topics[i].local_topic, context->bridge->topics[i].qos); diff --git a/src/handle_subscribe.c b/src/handle_subscribe.c index 0715b47589..ab2de07842 100644 --- a/src/handle_subscribe.c +++ b/src/handle_subscribe.c @@ -33,7 +33,10 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) int rc2; uint16_t mid; char *sub; + uint8_t subscription_options; uint8_t qos; + uint8_t retain_handling = 0; + uint8_t retain_as_published = 0; uint8_t *payload = NULL, *tmp_payload; uint32_t payloadlen = 0; int len; @@ -84,11 +87,25 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) return 1; } - if(packet__read_byte(&context->in_packet, &qos)){ + if(packet__read_byte(&context->in_packet, &subscription_options)){ mosquitto__free(sub); mosquitto__free(payload); return 1; } + if(context->protocol == mosq_p_mqtt31 || context->protocol == mosq_p_mqtt311){ + qos = subscription_options; + }else{ + qos = subscription_options & 0x03; + + retain_as_published = subscription_options & 0x04; + + retain_handling = (subscription_options & 0x30) >> 4; + if(retain_handling == 3){ + mosquitto__free(sub); + mosquitto__free(payload); + return MOSQ_ERR_PROTOCOL; + } + } if(qos > 2){ log__printf(NULL, MOSQ_LOG_INFO, "Invalid QoS in subscription command from %s, disconnecting.", @@ -97,6 +114,8 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) mosquitto__free(payload); return 1; } + + if(context->listener && context->listener->mount_point){ len = strlen(context->listener->mount_point) + slen + 1; sub_mount = mosquitto__malloc(len+1); @@ -130,11 +149,18 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) if(qos != 0x80){ rc2 = sub__add(db, context, sub, qos, &db->subs); - if(rc2 == MOSQ_ERR_SUCCESS){ - if(sub__retain_queue(db, context, sub, qos)) rc = 1; - }else if(rc2 != -1){ - rc = rc2; + if(context->protocol == mosq_p_mqtt311 || context->protocol == mosq_p_mqtt31){ + if(rc2 == MOSQ_ERR_SUCCESS || rc2 == MOSQ_ERR_SUB_EXISTS){ + if(sub__retain_queue(db, context, sub, qos)) rc = 1; + } + }else{ + if((rc2 == MOSQ_ERR_SUCCESS && retain_handling == 0) + || (rc2 == MOSQ_ERR_SUB_EXISTS && retain_handling == 1)){ + + if(sub__retain_queue(db, context, sub, qos)) rc = 1; + } } + log__printf(NULL, MOSQ_LOG_SUBSCRIBE, "%s %d %s", context->id, qos, sub); } mosquitto__free(sub); diff --git a/src/persist.c b/src/persist.c index d105c41325..b9e48ba3cc 100644 --- a/src/persist.c +++ b/src/persist.c @@ -799,7 +799,7 @@ static int persist__sub_chunk_restore(struct mosquitto_db *db, FILE *db_fptr) topic[slen] = '\0'; read_e(db_fptr, &qos, sizeof(uint8_t)); - if(persist__restore_sub(db, client_id, topic, qos)){ + if(persist__restore_sub(db, client_id, topic, qos) > 0){ rc = 1; } mosquitto__free(client_id); diff --git a/src/subs.c b/src/subs.c index 715b043f14..901cb72b96 100644 --- a/src/subs.c +++ b/src/subs.c @@ -260,11 +260,11 @@ static int sub__add_recurse(struct mosquitto_db *db, struct mosquitto *context, while(leaf){ if(leaf->context && leaf->context->id && !strcmp(leaf->context->id, context->id)){ /* Client making a second subscription to same topic. Only - * need to update QoS. Return -1 to indicate this to the - * calling function. */ + * need to update QoS. Return MOSQ_ERR_SUB_EXISTS to + * indicate this to the calling function. */ leaf->qos = qos; if(context->protocol == mosq_p_mqtt31){ - return -1; + return MOSQ_ERR_SUB_EXISTS; }else{ /* mqttv311/mqttv5 requires retained messages are resent on * resubscribe. */ @@ -472,8 +472,6 @@ int sub__add(struct mosquitto_db *db, struct mosquitto *context, const char *sub sub__topic_tokens_free(tokens); - /* We aren't worried about -1 (already subscribed) return codes. */ - if(rc == -1) rc = MOSQ_ERR_SUCCESS; return rc; } From 1a6f8d3c28e313900ba1434502f4541602580f16 Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Mon, 12 Nov 2018 22:22:36 +0100 Subject: [PATCH 144/254] src: ASN1_STRING_data is deprecated in OpenSSL 1.1 ASN1_STRING_get0_data replaces ASN1_STRING_data in OpenSSL 1.1 therefore add an #ifdef for backwards compatibility. Signed-off-by: Jelle van der Waa --- src/handle_connect.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/handle_connect.c b/src/handle_connect.c index fd60addfe5..2d300fc072 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -457,7 +457,11 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) rc = 1; goto handle_connect_error; } +#if OPENSSL_VERSION_NUMBER < 0x10100000L context->username = mosquitto__strdup((char *) ASN1_STRING_data(name_asn1)); +#else + context->username = mosquitto__strdup((char *) ASN1_STRING_get0_data(name_asn1)); +#endif if(!context->username){ send__connack(context, 0, CONNACK_REFUSED_SERVER_UNAVAILABLE); rc = MOSQ_ERR_NOMEM; From 9097577b49b7fdcf45d30975976dd93808ccc0c4 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sun, 9 Dec 2018 09:45:14 +0000 Subject: [PATCH 145/254] Fix acl_file being ignore for default listener if with per_listener_settings Close #1073. Thanks to Jef Driesen. Bug: https://github.com/eclipse/mosquitto/issues/1073 --- ChangeLog.txt | 5 +++++ src/conf.c | 1 + 2 files changed, 6 insertions(+) diff --git a/ChangeLog.txt b/ChangeLog.txt index c3a6c60a17..6287bce2e6 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,6 +1,11 @@ 1.5.5 - 201812xx ================ +Security: +- If `per_listener_settings` is set to true, then the `acl_file` setting was + ignored for the "default listener" only. This has been fixed. This does not + affect any listeners defined with the `listener` option. Closes #1073. + Broker: - Add `socket_domain` option to allow listeners to disable IPv6 support. This is required to work around a problem in libwebsockets that means diff --git a/src/conf.c b/src/conf.c index 67e172b00a..87294680a2 100644 --- a/src/conf.c +++ b/src/conf.c @@ -497,6 +497,7 @@ int config__parse_args(struct mosquitto_db *db, struct mosquitto__config *config config->listeners[config->listener_count-1].use_identity_as_username = config->default_listener.use_identity_as_username; config->listeners[config->listener_count-1].use_subject_as_username = config->default_listener.use_subject_as_username; #endif + config->listeners[config->listener_count-1].security_options.acl_file = config->default_listener.security_options.acl_file; config->listeners[config->listener_count-1].security_options.password_file = config->default_listener.security_options.password_file; config->listeners[config->listener_count-1].security_options.psk_file = config->default_listener.security_options.psk_file; config->listeners[config->listener_count-1].security_options.auth_plugin_configs = config->default_listener.security_options.auth_plugin_configs; From a00dd29af88965c47240f4f841f7bbedddae430c Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sun, 9 Dec 2018 13:40:38 +0000 Subject: [PATCH 146/254] Fix building where TLS-PSK is not available. Closes #68. --- ChangeLog.txt | 3 +++ client/client_shared.c | 10 +++++----- client/client_shared.h | 2 +- client/pub_client.c | 4 ++-- client/sub_client.c | 4 ++-- config.h | 8 ++++++++ lib/net_mosq.c | 4 ++-- lib/options.c | 2 +- lib/util_mosq.c | 2 +- lib/util_mosq.h | 2 +- src/bridge.c | 2 +- src/conf.c | 20 ++++++++++---------- src/handle_connect.c | 8 ++++---- src/mosquitto_broker_internal.h | 2 +- src/net.c | 6 +++--- 15 files changed, 45 insertions(+), 34 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 6287bce2e6..b36c1d965f 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -28,6 +28,9 @@ Client: - Always print leading zeros in mosquitto_sub when output format is hex. Closes #1066. +Build: +- Fix building where TLS-PSK is not available. Closes #68. + 1.5.4 - 20181108 ================ diff --git a/client/client_shared.c b/client/client_shared.c index 2788b7ce51..8f993dc98d 100644 --- a/client/client_shared.c +++ b/client/client_shared.c @@ -151,7 +151,7 @@ void client_config_cleanup(struct mosq_config *cfg) free(cfg->keyfile); free(cfg->ciphers); free(cfg->tls_version); -# ifdef WITH_TLS_PSK +# ifdef FINAL_WITH_TLS_PSK free(cfg->psk); free(cfg->psk_identity); # endif @@ -309,7 +309,7 @@ int client_config_load(struct mosq_config *cfg, int pub_or_sub, int argc, char * return 1; } #endif -#ifdef WITH_TLS_PSK +#ifdef FINAL_WITH_TLS_PSK if((cfg->cafile || cfg->capath) && cfg->psk){ if(!cfg->quiet) fprintf(stderr, "Error: Only one of --psk or --cafile/--capath may be used at once.\n"); return 1; @@ -673,7 +673,7 @@ int client_config_line_proc(struct mosq_config *cfg, int pub_or_sub, int argc, c i++; } #endif -#ifdef WITH_TLS_PSK +#ifdef FINAL_WITH_TLS_PSK }else if(!strcmp(argv[i], "--psk")){ if(i==argc-1){ fprintf(stderr, "Error: --psk argument given but no key specified.\n\n"); @@ -912,7 +912,7 @@ int client_opts_set(struct mosquitto *mosq, struct mosq_config *cfg) mosquitto_lib_cleanup(); return 1; } -# ifdef WITH_TLS_PSK +# ifdef FINAL_WITH_TLS_PSK if(cfg->psk && mosquitto_tls_psk_set(mosq, cfg->psk, cfg->psk_identity, NULL)){ if(!cfg->quiet) fprintf(stderr, "Error: Problem setting TLS-PSK options.\n"); mosquitto_lib_cleanup(); @@ -985,7 +985,7 @@ int client_connect(struct mosquitto *mosq, struct mosq_config *cfg) if(cfg->port < 0){ #ifdef WITH_TLS if(cfg->cafile || cfg->capath -# ifdef WITH_TLS_PSK +# ifdef FINAL_WITH_TLS_PSK || cfg->psk # endif ){ diff --git a/client/client_shared.h b/client/client_shared.h index f1ce6f3132..aee823a69a 100644 --- a/client/client_shared.h +++ b/client/client_shared.h @@ -66,7 +66,7 @@ struct mosq_config { char *ciphers; bool insecure; char *tls_version; -# ifdef WITH_TLS_PSK +# ifdef FINAL_WITH_TLS_PSK char *psk; char *psk_identity; # endif diff --git a/client/pub_client.c b/client/pub_client.c index 8c729b8766..49ca48c2f6 100644 --- a/client/pub_client.c +++ b/client/pub_client.c @@ -223,7 +223,7 @@ void print_usage(void) #ifdef WITH_TLS printf(" [{--cafile file | --capath dir} [--cert file] [--key file]\n"); printf(" [--ciphers ciphers] [--insecure]]\n"); -#ifdef WITH_TLS_PSK +#ifdef FINAL_WITH_TLS_PSK printf(" [--psk hex-key --psk-identity identity [--ciphers ciphers]]\n"); #endif #endif @@ -280,7 +280,7 @@ void print_usage(void) printf(" hostname. Using this option means that you cannot be sure that the\n"); printf(" remote host is the server you wish to connect to and so is insecure.\n"); printf(" Do not use this option in a production environment.\n"); -# ifdef WITH_TLS_PSK +# ifdef FINAL_WITH_TLS_PSK printf(" --psk : pre-shared-key in hexadecimal (no leading 0x) to enable TLS-PSK mode.\n"); printf(" --psk-identity : client identity string for TLS-PSK mode.\n"); # endif diff --git a/client/sub_client.c b/client/sub_client.c index 3d91ed0f2e..607f258cb6 100644 --- a/client/sub_client.c +++ b/client/sub_client.c @@ -155,7 +155,7 @@ void print_usage(void) #ifdef WITH_TLS printf(" [{--cafile file | --capath dir} [--cert file] [--key file]\n"); printf(" [--ciphers ciphers] [--insecure]]\n"); -#ifdef WITH_TLS_PSK +#ifdef FINAL_WITH_TLS_PSK printf(" [--psk hex-key --psk-identity identity [--ciphers ciphers]]\n"); #endif #endif @@ -218,7 +218,7 @@ void print_usage(void) printf(" hostname. Using this option means that you cannot be sure that the\n"); printf(" remote host is the server you wish to connect to and so is insecure.\n"); printf(" Do not use this option in a production environment.\n"); -#ifdef WITH_TLS_PSK +#ifdef FINAL_WITH_TLS_PSK printf(" --psk : pre-shared-key in hexadecimal (no leading 0x) to enable TLS-PSK mode.\n"); printf(" --psk-identity : client identity string for TLS-PSK mode.\n"); #endif diff --git a/config.h b/config.h index 97ac6be998..3c7770594e 100644 --- a/config.h +++ b/config.h @@ -37,4 +37,12 @@ #define uthash_malloc(sz) mosquitto__malloc(sz) #define uthash_free(ptr,sz) mosquitto__free(ptr) + +#ifdef WITH_TLS +# include +# if defined(WITH_TLS_PSK) && !defined(OPENSSL_NO_PSK) +# define FINAL_WITH_TLS_PSK +# endif +#endif + #endif diff --git a/lib/net_mosq.c b/lib/net_mosq.c index f2bb628bc1..09a26042dc 100644 --- a/lib/net_mosq.c +++ b/lib/net_mosq.c @@ -183,7 +183,7 @@ int net__socket_close(struct mosquitto *mosq) } -#ifdef WITH_TLS_PSK +#ifdef FINAL_WITH_TLS_PSK static unsigned int psk_client_callback(SSL *ssl, const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len) @@ -594,7 +594,7 @@ static int net__init_ssl_ctx(struct mosquitto *mosq) return MOSQ_ERR_TLS; } } -#ifdef WITH_TLS_PSK +#ifdef FINAL_WITH_TLS_PSK }else if(mosq->tls_psk){ SSL_CTX_set_psk_client_callback(mosq->ssl_ctx, psk_client_callback); #endif diff --git a/lib/options.c b/lib/options.c index 00951a6877..b4b8ac849c 100644 --- a/lib/options.c +++ b/lib/options.c @@ -223,7 +223,7 @@ int mosquitto_tls_insecure_set(struct mosquitto *mosq, bool value) int mosquitto_tls_psk_set(struct mosquitto *mosq, const char *psk, const char *identity, const char *ciphers) { -#ifdef WITH_TLS_PSK +#ifdef FINAL_WITH_TLS_PSK if(!mosq || !psk || !identity) return MOSQ_ERR_INVAL; /* Check for hex only digits */ diff --git a/lib/util_mosq.c b/lib/util_mosq.c index 405cb3900b..d98bbde448 100644 --- a/lib/util_mosq.c +++ b/lib/util_mosq.c @@ -349,7 +349,7 @@ int mosquitto_topic_matches_sub2(const char *sub, size_t sublen, const char *top return MOSQ_ERR_SUCCESS; } -#ifdef WITH_TLS_PSK +#ifdef FINAL_WITH_TLS_PSK int mosquitto__hex2bin(const char *hex, unsigned char *bin, int bin_max_len) { BIGNUM *bn = NULL; diff --git a/lib/util_mosq.h b/lib/util_mosq.h index 8e601a0ffd..d94661e7aa 100644 --- a/lib/util_mosq.h +++ b/lib/util_mosq.h @@ -33,7 +33,7 @@ int mosquitto__check_keepalive(struct mosquitto *mosq); uint16_t mosquitto__mid_generate(struct mosquitto *mosq); FILE *mosquitto__fopen(const char *path, const char *mode, bool restrict_read); -#ifdef WITH_TLS_PSK +#ifdef FINAL_WITH_TLS_PSK int mosquitto__hex2bin(const char *hex, unsigned char *bin, int bin_max_len); #endif diff --git a/src/bridge.c b/src/bridge.c index e35cacced3..6e4b94fa6c 100644 --- a/src/bridge.c +++ b/src/bridge.c @@ -82,7 +82,7 @@ int bridge__new(struct mosquitto_db *db, struct mosquitto__bridge *bridge) new_context->tls_cert_reqs = SSL_VERIFY_PEER; new_context->tls_version = new_context->bridge->tls_version; new_context->tls_insecure = new_context->bridge->tls_insecure; -#ifdef WITH_TLS_PSK +#ifdef FINAL_WITH_TLS_PSK new_context->tls_psk_identity = new_context->bridge->tls_psk_identity; new_context->tls_psk = new_context->bridge->tls_psk; #endif diff --git a/src/conf.c b/src/conf.c index 87294680a2..0968d326cc 100644 --- a/src/conf.c +++ b/src/conf.c @@ -341,7 +341,7 @@ void config__cleanup(struct mosquitto__config *config) #ifdef WITH_TLS mosquitto__free(config->bridges[i].tls_version); mosquitto__free(config->bridges[i].tls_cafile); -#ifdef WITH_TLS_PSK +#ifdef FINAL_WITH_TLS_PSK mosquitto__free(config->bridges[i].tls_psk_identity); mosquitto__free(config->bridges[i].tls_psk); #endif @@ -687,7 +687,7 @@ int config__read(struct mosquitto_db *db, struct mosquitto__config *config, bool log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } -#ifdef WITH_TLS_PSK +#ifdef FINAL_WITH_TLS_PSK if(config->bridges[i].tls_psk && !config->bridges[i].tls_psk_identity){ log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration: missing bridge_identity.\n"); return MOSQ_ERR_INVAL; @@ -921,7 +921,7 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } -#ifdef WITH_TLS_PSK +#ifdef FINAL_WITH_TLS_PSK if(cur_bridge->tls_psk_identity || cur_bridge->tls_psk){ log__printf(NULL, MOSQ_LOG_ERR, "Error: Cannot use both certificate and psk encryption in a single bridge."); return MOSQ_ERR_INVAL; @@ -938,7 +938,7 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } -#ifdef WITH_TLS_PSK +#ifdef FINAL_WITH_TLS_PSK if(cur_bridge->tls_psk_identity || cur_bridge->tls_psk){ log__printf(NULL, MOSQ_LOG_ERR, "Error: Cannot use both certificate and psk encryption in a single bridge."); return MOSQ_ERR_INVAL; @@ -955,7 +955,7 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } -#ifdef WITH_TLS_PSK +#ifdef FINAL_WITH_TLS_PSK if(cur_bridge->tls_psk_identity || cur_bridge->tls_psk){ log__printf(NULL, MOSQ_LOG_ERR, "Error: Cannot use both certificate and psk encryption in a single bridge."); return MOSQ_ERR_INVAL; @@ -966,7 +966,7 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge and/or TLS support not available."); #endif }else if(!strcmp(token, "bridge_identity")){ -#if defined(WITH_BRIDGE) && defined(WITH_TLS_PSK) +#if defined(WITH_BRIDGE) && defined(FINAL_WITH_TLS_PSK) if(reload) continue; // FIXME if(!cur_bridge){ log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); @@ -1001,7 +1001,7 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } -#ifdef WITH_TLS_PSK +#ifdef FINAL_WITH_TLS_PSK if(cur_bridge->tls_psk_identity || cur_bridge->tls_psk){ log__printf(NULL, MOSQ_LOG_ERR, "Error: Cannot use both certificate and psk encryption in a single bridge."); return MOSQ_ERR_INVAL; @@ -1036,7 +1036,7 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif }else if(!strcmp(token, "bridge_psk")){ -#if defined(WITH_BRIDGE) && defined(WITH_TLS_PSK) +#if defined(WITH_BRIDGE) && defined(FINAL_WITH_TLS_PSK) if(reload) continue; // FIXME if(!cur_bridge){ log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); @@ -1692,7 +1692,7 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct log__printf(NULL, MOSQ_LOG_ERR, "Error: Empty protocol value in configuration."); } }else if(!strcmp(token, "psk_file")){ -#ifdef WITH_TLS_PSK +#ifdef FINAL_WITH_TLS_PSK conf__set_cur_security_options(config, cur_listener, &cur_security_options); if(reload){ mosquitto__free(cur_security_options->psk_file); @@ -1703,7 +1703,7 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct log__printf(NULL, MOSQ_LOG_WARNING, "Warning: TLS/TLS-PSK support not available."); #endif }else if(!strcmp(token, "psk_hint")){ -#ifdef WITH_TLS_PSK +#ifdef FINAL_WITH_TLS_PSK if(reload) continue; // Listeners not valid for reloading. if(conf__parse_string(&token, "psk_hint", &cur_listener->psk_hint, saveptr)) return MOSQ_ERR_INVAL; #else diff --git a/src/handle_connect.c b/src/handle_connect.c index 2d300fc072..b9b0fefd8e 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -420,7 +420,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) rc = 1; goto handle_connect_error; } -#ifdef WITH_TLS_PSK +#ifdef FINAL_WITH_TLS_PSK if(context->listener->psk_hint){ /* Client should have provided an identity to get this far. */ if(!context->username){ @@ -429,7 +429,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) goto handle_connect_error; } }else{ -#endif /* WITH_TLS_PSK */ +#endif /* FINAL_WITH_TLS_PSK */ client_cert = SSL_get_peer_certificate(context->ssl); if(!client_cert){ send__connack(context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); @@ -496,9 +496,9 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) } X509_free(client_cert); client_cert = NULL; -#ifdef WITH_TLS_PSK +#ifdef FINAL_WITH_TLS_PSK } -#endif /* WITH_TLS_PSK */ +#endif /* FINAL_WITH_TLS_PSK */ }else{ #endif /* WITH_TLS */ if(username_flag){ diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index bd6ad13655..bf13eebb56 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -463,7 +463,7 @@ struct mosquitto__bridge{ char *tls_certfile; char *tls_keyfile; char *tls_version; -# ifdef WITH_TLS_PSK +# ifdef FINAL_WITH_TLS_PSK char *tls_psk_identity; char *tls_psk; # endif diff --git a/src/net.c b/src/net.c index 21f5ec6893..10f88dbeda 100644 --- a/src/net.c +++ b/src/net.c @@ -247,7 +247,7 @@ static int client_certificate_verify(int preverify_ok, X509_STORE_CTX *ctx) } #endif -#ifdef WITH_TLS_PSK +#ifdef FINAL_WITH_TLS_PSK static unsigned int psk_server_callback(SSL *ssl, const char *identity, unsigned char *psk, unsigned int max_psk_len) { struct mosquitto_db *db; @@ -520,7 +520,7 @@ int net__socket_listen(struct mosquitto__listener *listener) X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK); } -# ifdef WITH_TLS_PSK +# ifdef FINAL_WITH_TLS_PSK }else if(listener->psk_hint){ if(tls_ex_index_context == -1){ tls_ex_index_context = SSL_get_ex_new_index(0, "client context", NULL, NULL, NULL); @@ -543,7 +543,7 @@ int net__socket_listen(struct mosquitto__listener *listener) return 1; } } -# endif /* WITH_TLS_PSK */ +# endif /* FINAL_WITH_TLS_PSK */ } #endif /* WITH_TLS */ return 0; From 89f3d7bb3f4f478d40bed65bc913d873b86ecdd5 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sun, 9 Dec 2018 14:03:01 +0000 Subject: [PATCH 147/254] Don't print connect/disconnect messages when connection_messages false. Closes #772. Closes #613. Closes #537. Thanks to Christopher Maynard, Brandon Arrendondo, and qubeck. --- ChangeLog.txt | 2 ++ src/loop.c | 8 ++++++-- src/net.c | 26 +++++++++++++++++--------- src/websockets.c | 4 +++- 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index b36c1d965f..e7cb78864a 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -19,6 +19,8 @@ Broker: - Don't reload auth_opt_ options on reload, to match the behaviour of the other plugin options. Closes #1068. - Print message on error when installing/uninstalling as a Windows service. +- All non-error connect/disconnect messages are controlled by the + `connection_messages` option. Closes #772. Closes #613. Closes #537. Library: - Fix reconnect delay backoff behaviour. Closes #1027. diff --git a/src/loop.c b/src/loop.c index 6773185a89..8d08474917 100644 --- a/src/loop.c +++ b/src/loop.c @@ -87,7 +87,9 @@ static void temp__expire_websockets_clients(struct mosquitto_db *db) }else{ id = ""; } - log__printf(NULL, MOSQ_LOG_NOTICE, "Client %s has exceeded timeout, disconnecting.", id); + if(db->config->connection_messages == true){ + log__printf(NULL, MOSQ_LOG_NOTICE, "Client %s has exceeded timeout, disconnecting.", id); + } } /* Client has exceeded keepalive*1.5 */ do_disconnect(db, context); @@ -666,7 +668,9 @@ void do_disconnect(struct mosquitto_db *db, struct mosquitto *context) } #ifdef WITH_EPOLL if (context->sock != INVALID_SOCKET && epoll_ctl(db->epollfd, EPOLL_CTL_DEL, context->sock, &ev) == -1) { - log__printf(NULL, MOSQ_LOG_DEBUG, "Error in epoll disconnecting: %s", strerror(errno)); + if(db->config->connection_messages == true){ + log__printf(NULL, MOSQ_LOG_DEBUG, "Error in epoll disconnecting: %s", strerror(errno)); + } } #endif context__disconnect(db, context); diff --git a/src/net.c b/src/net.c index 10f88dbeda..937f6ce14e 100644 --- a/src/net.c +++ b/src/net.c @@ -152,8 +152,10 @@ int net__socket_accept(struct mosquitto_db *db, mosq_sock_t listensock) fromhost(&wrap_req); if(!hosts_access(&wrap_req)){ /* Access is denied */ - if(!net__socket_get_address(new_sock, address, 1024)){ - log__printf(NULL, MOSQ_LOG_NOTICE, "Client connection from %s denied access by tcpd.", address); + if(db->config->connection_messages == true){ + if(!net__socket_get_address(new_sock, address, 1024)){ + log__printf(NULL, MOSQ_LOG_NOTICE, "Client connection from %s denied access by tcpd.", address); + } } COMPAT_CLOSE(new_sock); return -1; @@ -187,7 +189,9 @@ int net__socket_accept(struct mosquitto_db *db, mosq_sock_t listensock) } if(new_context->listener->max_connections > 0 && new_context->listener->client_count > new_context->listener->max_connections){ - log__printf(NULL, MOSQ_LOG_NOTICE, "Client connection from %s denied: max_connections exceeded.", new_context->address); + if(db->config->connection_messages == true){ + log__printf(NULL, MOSQ_LOG_NOTICE, "Client connection from %s denied: max_connections exceeded.", new_context->address); + } context__cleanup(db, new_context, true); return -1; } @@ -217,12 +221,14 @@ int net__socket_accept(struct mosquitto_db *db, mosq_sock_t listensock) }else if(rc == SSL_ERROR_WANT_WRITE){ new_context->want_write = true; }else{ - e = ERR_get_error(); - while(e){ - log__printf(NULL, MOSQ_LOG_NOTICE, - "Client connection from %s failed: %s.", - new_context->address, ERR_error_string(e, ebuf)); + if(db->config->connection_messages == true){ e = ERR_get_error(); + while(e){ + log__printf(NULL, MOSQ_LOG_NOTICE, + "Client connection from %s failed: %s.", + new_context->address, ERR_error_string(e, ebuf)); + e = ERR_get_error(); + } } context__cleanup(db, new_context, true); return -1; @@ -234,7 +240,9 @@ int net__socket_accept(struct mosquitto_db *db, mosq_sock_t listensock) } #endif - log__printf(NULL, MOSQ_LOG_NOTICE, "New connection from %s on port %d.", new_context->address, new_context->listener->port); + if(db->config->connection_messages == true){ + log__printf(NULL, MOSQ_LOG_NOTICE, "New connection from %s on port %d.", new_context->address, new_context->listener->port); + } return new_sock; } diff --git a/src/websockets.c b/src/websockets.c index a57330aabe..6ac446f610 100644 --- a/src/websockets.c +++ b/src/websockets.c @@ -229,7 +229,9 @@ static int callback_mqtt(struct libwebsocket_context *context, return -1; } if(mosq->listener->max_connections > 0 && mosq->listener->client_count > mosq->listener->max_connections){ - log__printf(NULL, MOSQ_LOG_NOTICE, "Client connection from %s denied: max_connections exceeded.", mosq->address); + if(db->config->connection_messages == true){ + log__printf(NULL, MOSQ_LOG_NOTICE, "Client connection from %s denied: max_connections exceeded.", mosq->address); + } mosquitto__free(mosq); u->mosq = NULL; return -1; From afe011866c5625144c3ff0169b7a1db8a134ff57 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sun, 9 Dec 2018 21:51:42 +0000 Subject: [PATCH 148/254] Remove unused variables. --- lib/loop.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/loop.c b/lib/loop.c index 4b27775226..e4a985eb3e 100644 --- a/lib/loop.c +++ b/lib/loop.c @@ -286,9 +286,6 @@ int mosquitto_loop_forever(struct mosquitto *mosq, int timeout, int max_packets) int mosquitto_loop_misc(struct mosquitto *mosq) { - time_t now; - int rc; - if(!mosq) return MOSQ_ERR_INVAL; if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; From a8ca5c83af5757b14e7046b2ce3f3ea674ff65c1 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sun, 9 Dec 2018 22:54:21 +0000 Subject: [PATCH 149/254] Bump version. --- CMakeLists.txt | 2 +- ChangeLog.txt | 2 +- config.mk | 2 +- installer/mosquitto.nsi | 2 +- installer/mosquitto64.nsi | 2 +- lib/mosquitto.h | 2 +- set-version.sh | 2 +- snap/snapcraft.yaml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 161696daf4..265c106d9c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ project(mosquitto) cmake_minimum_required(VERSION 2.8) # Only for version 3 and up. cmake_policy(SET CMP0042 NEW) -set (VERSION 1.5.4) +set (VERSION 1.5.5) add_definitions (-DCMAKE -DVERSION=\"${VERSION}\") diff --git a/ChangeLog.txt b/ChangeLog.txt index e7cb78864a..d7682e4069 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,4 +1,4 @@ -1.5.5 - 201812xx +1.5.5 - 20181211 ================ Security: diff --git a/config.mk b/config.mk index d591cd499c..0ee3fa4459 100644 --- a/config.mk +++ b/config.mk @@ -105,7 +105,7 @@ WITH_BUNDLED_DEPS:=yes # Also bump lib/mosquitto.h, CMakeLists.txt, # installer/mosquitto.nsi, installer/mosquitto64.nsi -VERSION=1.5.4 +VERSION=1.5.5 # Client library SO version. Bump if incompatible API/ABI changes are made. SOVERSION=1 diff --git a/installer/mosquitto.nsi b/installer/mosquitto.nsi index d7db79b825..0574e0b10e 100644 --- a/installer/mosquitto.nsi +++ b/installer/mosquitto.nsi @@ -9,7 +9,7 @@ !define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' Name "Eclipse Mosquitto" -!define VERSION 1.5.4 +!define VERSION 1.5.5 OutFile "mosquitto-${VERSION}-install-windows-x86.exe" InstallDir "$PROGRAMFILES\mosquitto" diff --git a/installer/mosquitto64.nsi b/installer/mosquitto64.nsi index 7ae8dccd0c..5e9706c4b5 100644 --- a/installer/mosquitto64.nsi +++ b/installer/mosquitto64.nsi @@ -9,7 +9,7 @@ !define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' Name "Eclipse Mosquitto" -!define VERSION 1.5.4 +!define VERSION 1.5.5 OutFile "mosquitto-${VERSION}-install-windows-x64.exe" !include "x64.nsh" diff --git a/lib/mosquitto.h b/lib/mosquitto.h index b3600b2c1b..57a22ec341 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -47,7 +47,7 @@ extern "C" { #define LIBMOSQUITTO_MAJOR 1 #define LIBMOSQUITTO_MINOR 5 -#define LIBMOSQUITTO_REVISION 4 +#define LIBMOSQUITTO_REVISION 5 /* LIBMOSQUITTO_VERSION_NUMBER looks like 1002001 for e.g. version 1.2.1. */ #define LIBMOSQUITTO_VERSION_NUMBER (LIBMOSQUITTO_MAJOR*1000000+LIBMOSQUITTO_MINOR*1000+LIBMOSQUITTO_REVISION) diff --git a/set-version.sh b/set-version.sh index 549581892d..ec105f6bdb 100755 --- a/set-version.sh +++ b/set-version.sh @@ -2,7 +2,7 @@ MAJOR=1 MINOR=5 -REVISION=4 +REVISION=5 sed -i "s/^VERSION=.*/VERSION=${MAJOR}.${MINOR}.${REVISION}/" config.mk diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index fa1127ed55..b337fe0be4 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,5 +1,5 @@ name: mosquitto -version: 1.5.4 +version: 1.5.5 summary: Eclipse Mosquitto MQTT broker description: This is a message broker that supports version 3.1 and 3.1.1 of the MQTT protocol. From 66dfa573946425661626e2f574ef125ab01b01f5 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 11 Dec 2018 11:14:15 +0000 Subject: [PATCH 150/254] Don't use home interface until it is not auto connected. --- snap/snapcraft.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 0c0dec007c..b337fe0be4 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -16,11 +16,11 @@ apps: command: launcher.sh daemon: simple restart-condition: always - plugs: [home, network, network-bind] + plugs: [network, network-bind] pub: command: usr/bin/mosquitto_pub - plugs: [home, network] + plugs: [network] sub: command: usr/bin/mosquitto_sub @@ -28,7 +28,6 @@ apps: passwd: command: usr/bin/mosquitto_passwd - plugs: [home] parts: From a0a37d385db4421d7151f1fe969a7b00d4516c24 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 11 Dec 2018 13:23:29 +0000 Subject: [PATCH 151/254] Update docker for 1.5.5. --- docker/1.5/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/1.5/Dockerfile b/docker/1.5/Dockerfile index 5661fb35b5..2c9b15c67f 100644 --- a/docker/1.5/Dockerfile +++ b/docker/1.5/Dockerfile @@ -3,8 +3,8 @@ FROM alpine:3.8 LABEL maintainer="Roger Light " \ description="Eclipse Mosquitto MQTT Broker" -ENV VERSION=1.5.4 \ - DOWNLOAD_SHA256=5fd7f3454fd6d286645d032bc07f44a1c8583cec02ef2422c9eb32e0a89a9b2f \ +ENV VERSION=1.5.5 \ + DOWNLOAD_SHA256=fcdb47e340864c545146681af7253399cc292e41775afd76400fda5b0d23d668 \ GPG_KEYS=A0D6EEA1DCAE49A635A3B2F0779B22DFB3E717B7 \ LWS_VERSION=2.4.2 From 84c5d90f5ccb1a4f7d975bddd0f28655ddfeb2be Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 11 Dec 2018 16:07:18 +0000 Subject: [PATCH 152/254] Website update for 1.5.5. --- www/pages/download.md | 2 +- www/pages/security.md | 3 ++ www/posts/2018/12/version-155-released.md | 60 +++++++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 www/posts/2018/12/version-155-released.md diff --git a/www/pages/download.md b/www/pages/download.md index 2a9b54e027..2aceb0a53a 100644 --- a/www/pages/download.md +++ b/www/pages/download.md @@ -11,7 +11,7 @@ # Source -* [mosquitto-1.5.4.tar.gz](https://mosquitto.org/files/source/mosquitto-1.5.4.tar.gz) (319kB) ([GPG signature](https://mosquitto.org/files/source/mosquitto-1.5.4.tar.gz.asc)) +* [mosquitto-1.5.5.tar.gz](https://mosquitto.org/files/source/mosquitto-1.5.5.tar.gz) (319kB) ([GPG signature](https://mosquitto.org/files/source/mosquitto-1.5.5.tar.gz.asc)) * [mosquitto-1.5.4.tar.gz](https://www.eclipse.org/downloads/download.php?file=/mosquitto/source/mosquitto-1.5.4.tar.gz) (via Eclipse) * [Git source code repository](https://github.com/eclipse/mosquitto) (github.com) diff --git a/www/pages/security.md b/www/pages/security.md index 7696dca90f..43618a25a3 100644 --- a/www/pages/security.md +++ b/www/pages/security.md @@ -19,6 +19,8 @@ follow the steps on [Eclipse Security] page to report it. Listed with most recent first. Further information on security related issues can be found in the [security category]. +* December 2018: No CVE assigned. Affecting versions **1.5** to **1.5.4** + inclusive, fixed in **1.5.5.**. More details at [version-155-released]. * November 2018: No CVE assigned. Affecting versions **1.4** to **1.5.3** inclusive, fixed in **1.5.4**. More details at [version-154-released]. * September 2018: [CVE-2018-12543] affecting versions **1.5** to **1.5.2** @@ -43,6 +45,7 @@ can be found in the [security category]. inclusive, fixed in **1.4.12**. More details at [security-advisory-cve-2017-7650]. +[version-155-released]: /2018/11/version-155-released/ [version-154-released]: /2018/11/version-154-released/ [security-advisory-cve-2018-12543]: /2018/09/security-advisory-cve-2018-12543/ [security-advisory-cve-2017-7651-cve-2017-7652]: /2018/02/security-advisory-cve-2017-7651-cve-2017-7652/ diff --git a/www/posts/2018/12/version-155-released.md b/www/posts/2018/12/version-155-released.md new file mode 100644 index 0000000000..ca01171581 --- /dev/null +++ b/www/posts/2018/12/version-155-released.md @@ -0,0 +1,60 @@ + + +This is a bugfix and security release. + +# Version 1.5.5 changes + +## Security +- If `per_listener_settings` is set to true, then the `acl_file` setting was + ignored for the "default listener" only. This has been fixed. This does not + affect any listeners defined with the `listener` option. Closes [#1073]. + +## Broker +- Add `socket_domain` option to allow listeners to disable IPv6 support. + This is required to work around a problem in libwebsockets that means + sockets only listen on IPv6 by default if IPv6 support is compiled in. + Closes [#1004]. +- When using ADNS, don't ask for all network protocols when connecting, + because this can lead to confusing "Protocol not supported" errors if the + network is down. Closes [#1062]. +- Fix outgoing retained messages not being sent by bridges on initial + connection. Closes [#1040]. +- Don't reload `auth_opt_` options on reload, to match the behaviour of the + other plugin options. Closes [#1068]. +- Print message on error when installing/uninstalling as a Windows service. +- All non-error connect/disconnect messages are controlled by the + `connection_messages` option. Closes [#772]. Closes [#613]. Closes [#537]. + +## Library +- Fix reconnect delay backoff behaviour. Closes [#1027]. +- Don't call `on_disconnect()` twice if keepalive tests fail. Closes [#1067]. + +## Client +- Always print leading zeros in `mosquitto_sub` when output format is hex. + Closes [#1066]. + +## Build +- Fix building where TLS-PSK is not available. Closes [#68]. + + +[#68]: https://github.com/eclipse/mosquitto/issues/68 +[#537]: https://github.com/eclipse/mosquitto/issues/537 +[#613]: https://github.com/eclipse/mosquitto/issues/613 +[#772]: https://github.com/eclipse/mosquitto/issues/772 +[#1004]: https://github.com/eclipse/mosquitto/issues/1004 +[#1027]: https://github.com/eclipse/mosquitto/issues/1027 +[#1040]: https://github.com/eclipse/mosquitto/issues/1040 +[#1062]: https://github.com/eclipse/mosquitto/issues/1062 +[#1066]: https://github.com/eclipse/mosquitto/issues/1066 +[#1067]: https://github.com/eclipse/mosquitto/issues/1067 +[#1068]: https://github.com/eclipse/mosquitto/issues/1068 +[#1073]: https://github.com/eclipse/mosquitto/issues/1073 From 4933f889ff167477de934e44452880a11435e832 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 14 Dec 2018 12:56:49 +0000 Subject: [PATCH 153/254] Fix missing header. --- lib/connect.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/connect.c b/lib/connect.c index 791aadd56b..ad3bb1d086 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -16,6 +16,8 @@ and the Eclipse Distribution License is available at #include "config.h" +#include + #include "mosquitto.h" #include "mosquitto_internal.h" #include "logging_mosq.h" From db7901884fc0dee44c26e2e17bf5829fe8f2f18c Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 14 Dec 2018 13:21:53 +0000 Subject: [PATCH 154/254] Retain-as-published support. --- client/client_shared.c | 5 ++++ client/client_shared.h | 1 + client/sub_client.c | 2 +- lib/actions.c | 13 +++++---- lib/mosquitto.h | 52 +++++++++++++++++++++++++++++++-- lib/mqtt_protocol.h | 8 +++++ lib/send_subscribe.c | 4 +-- man/mosquitto_sub.1.xml | 16 +++++++++- src/bridge.c | 2 +- src/handle_subscribe.c | 7 +++-- src/mosquitto_broker_internal.h | 3 +- src/persist.c | 3 +- src/subs.c | 20 +++++-------- 13 files changed, 108 insertions(+), 28 deletions(-) diff --git a/client/client_shared.c b/client/client_shared.c index 8811220137..b37d3067d4 100644 --- a/client/client_shared.c +++ b/client/client_shared.c @@ -700,6 +700,11 @@ int client_config_line_proc(struct mosq_config *cfg, int pub_or_sub, int argc, c }else{ cfg->pub_mode = MSGMODE_NULL; } + }else if(!strcmp(argv[i], "--retain-as-published")){ + if(pub_or_sub == CLIENT_PUB){ + goto unknown_option; + } + cfg->sub_opts |= MQTT_SUB_OPT_RETAIN_AS_PUBLISHED; }else if(!strcmp(argv[i], "-V") || !strcmp(argv[i], "--protocol-version")){ if(i==argc-1){ fprintf(stderr, "Error: --protocol-version argument given but no version specified.\n\n"); diff --git a/client/client_shared.h b/client/client_shared.h index ade5b274a4..1a8ad2800e 100644 --- a/client/client_shared.h +++ b/client/client_shared.h @@ -86,6 +86,7 @@ struct mosq_config { int msg_count; /* sub */ char *format; /* sub */ int timeout; /* sub */ + int sub_opts; /* sub */ #ifdef WITH_SOCKS char *socks5_host; int socks5_port; diff --git a/client/sub_client.c b/client/sub_client.c index 1a26bcb0bd..62d91ca757 100644 --- a/client/sub_client.c +++ b/client/sub_client.c @@ -90,7 +90,7 @@ void my_connect_callback(struct mosquitto *mosq, void *obj, int result, int flag int i; if(!result){ - mosquitto_subscribe_multiple(mosq, NULL, cfg.topic_count, cfg.topics, cfg.qos, cfg.subscribe_props); + mosquitto_subscribe_multiple(mosq, NULL, cfg.topic_count, cfg.topics, cfg.qos, cfg.sub_opts, cfg.subscribe_props); for(i=0; i 2) return MOSQ_ERR_INVAL; + if((options & 0x30) == 0x30 || (options & 0xC0) != 0) return MOSQ_ERR_INVAL; if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED; if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; @@ -175,11 +177,11 @@ int mosquitto_subscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, in if(rc) return rc; } - return send__subscribe(mosq, mid, 1, (char *const *const)&sub, qos, outgoing_properties); + return send__subscribe(mosq, mid, 1, (char *const *const)&sub, qos|options, outgoing_properties); } -int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, int qos, const mosquitto_property *properties) +int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, int qos, int options, const mosquitto_property *properties) { const mosquitto_property *outgoing_properties = NULL; mosquitto_property local_property; @@ -189,6 +191,7 @@ int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count if(!mosq || !sub_count || !sub) return MOSQ_ERR_INVAL; if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED; if(qos < 0 || qos > 2) return MOSQ_ERR_INVAL; + if((options & 0x30) == 0x30 || (options & 0xC0) != 0) return MOSQ_ERR_INVAL; if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; if(properties){ @@ -209,7 +212,7 @@ int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count if(mosquitto_validate_utf8(sub[i], strlen(sub[i]))) return MOSQ_ERR_MALFORMED_UTF8; } - return send__subscribe(mosq, mid, sub_count, sub, qos, properties); + return send__subscribe(mosq, mid, sub_count, sub, qos|options, properties); } diff --git a/lib/mosquitto.h b/lib/mosquitto.h index c5624c78b5..bb1524bd0d 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -840,6 +840,30 @@ libmosq_EXPORT int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const c * sent. * sub - the subscription pattern. * 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 + * 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 + * 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, + * 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 + * 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, + * pre-existing retained messages will never be sent + * for this subscription. * properties - a valid mosquitto_property list, or NULL. * * Returns: @@ -851,7 +875,7 @@ libmosq_EXPORT int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const c * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. * MOSQ_ERR_PROTOCOL - if any property is invalid for use with SUBSCRIBE. */ -libmosq_EXPORT int mosquitto_subscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, int qos, const mosquitto_property *properties); +libmosq_EXPORT int mosquitto_subscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, int qos, int options, const mosquitto_property *properties); /* * Function: mosquitto_subscribe_multiple @@ -871,6 +895,30 @@ libmosq_EXPORT int mosquitto_subscribe_v5(struct mosquitto *mosq, int *mid, cons * familiar with this, just think of it as a safer "char **", * equivalent to "const char *" for a simple string pointer. * qos - the requested Quality of Service for each subscription. + * options - options to apply to this subscription, OR'd together. Set to 0 to + * use the default options, otherwise choose from the list: + * 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 + * 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, + * 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 + * 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, + * pre-existing retained messages will never be sent + * for this subscription. * properties - a valid mosquitto_property list, or NULL. Only used with MQTT * v5 clients. * @@ -881,7 +929,7 @@ libmosq_EXPORT int mosquitto_subscribe_v5(struct mosquitto *mosq, int *mid, cons * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. * MOSQ_ERR_MALFORMED_UTF8 - if a topic is not valid UTF-8 */ -int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, int qos, const mosquitto_property *properties); +int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, int qos, int options, const mosquitto_property *properties); /* * Function: mosquitto_unsubscribe diff --git a/lib/mqtt_protocol.h b/lib/mqtt_protocol.h index 2d53f6f880..672d50b767 100644 --- a/lib/mqtt_protocol.h +++ b/lib/mqtt_protocol.h @@ -145,6 +145,14 @@ enum mqtt5_property_type { MQTT_PROP_TYPE_STRING_PAIR = 7 }; +enum mqtt5_sub_options { + MQTT_SUB_OPT_NO_LOCAL = 0x04, + MQTT_SUB_OPT_RETAIN_AS_PUBLISHED = 0x08, + MQTT_SUB_OPT_SEND_RETAIN_ALWAYS = 0x00, + MQTT_SUB_OPT_SEND_RETAIN_NEW = 0x10, + MQTT_SUB_OPT_SEND_RETAIN_NEVER = 0x20, +}; + #define MQTT_MAX_PAYLOAD 268435455 #endif diff --git a/lib/send_subscribe.c b/lib/send_subscribe.c index 1fb02b1466..ffe7ef7d68 100644 --- a/lib/send_subscribe.c +++ b/lib/send_subscribe.c @@ -83,11 +83,11 @@ int send__subscribe(struct mosquitto *mosq, int *mid, int topic_count, const cha #ifdef WITH_BROKER # ifdef WITH_BRIDGE - log__printf(mosq, MOSQ_LOG_DEBUG, "Bridge %s sending SUBSCRIBE (Mid: %d, Topic: %s, QoS: %d)", mosq->id, local_mid, topic[0], topic_qos); + log__printf(mosq, MOSQ_LOG_DEBUG, "Bridge %s sending SUBSCRIBE (Mid: %d, Topic: %s, QoS: %d, Options: 0x%02x)", mosq->id, local_mid, topic[0], topic_qos&0x03, topic_qos&0xFC); # endif #else for(i=0; iid, local_mid, topic[i], topic_qos); + log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending SUBSCRIBE (Mid: %d, Topic: %s, QoS: %d, Options: 0x%02x)", mosq->id, local_mid, topic[i], topic_qos&0x03, topic_qos&0xFC); } #endif diff --git a/man/mosquitto_sub.1.xml b/man/mosquitto_sub.1.xml index bffcd6e080..7c4861aba3 100644 --- a/man/mosquitto_sub.1.xml +++ b/man/mosquitto_sub.1.xml @@ -47,6 +47,7 @@ + filter-out unsub-topic @@ -459,7 +460,20 @@ Messages with retain set are "stale", in that it is not known when they were originally published. With this argument in use, the receipt of the first non-stale - message will cause the client to exit. + message will cause the client to exit. See also the + option. + + + + + + If this argument is given, the subscriptions will + have the "retain as published" option set. This means + that the retain flag on an incoming message will be + exactly as set by the publishing client, rather than + indicating whether the message is fresh/stale. + This option is not valid for MQTT v3.1/v3.1.1 + clients. diff --git a/src/bridge.c b/src/bridge.c index 80bed5501e..10c5744caf 100644 --- a/src/bridge.c +++ b/src/bridge.c @@ -312,7 +312,7 @@ int bridge__connect(struct mosquitto_db *db, struct mosquitto *context) for(i=0; ibridge->topic_count; i++){ if(context->bridge->topics[i].direction == bd_out || context->bridge->topics[i].direction == bd_both){ log__printf(NULL, MOSQ_LOG_DEBUG, "Bridge %s doing local SUBSCRIBE on topic %s", context->id, context->bridge->topics[i].local_topic); - if(sub__add(db, context, context->bridge->topics[i].local_topic, context->bridge->topics[i].qos, &db->subs) > 0){ + if(sub__add(db, context, context->bridge->topics[i].local_topic, context->bridge->topics[i].qos, true, &db->subs) > 0){ return 1; } sub__retain_queue(db, context, diff --git a/src/handle_subscribe.c b/src/handle_subscribe.c index ab2de07842..7cf62855d8 100644 --- a/src/handle_subscribe.c +++ b/src/handle_subscribe.c @@ -94,10 +94,13 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) } if(context->protocol == mosq_p_mqtt31 || context->protocol == mosq_p_mqtt311){ qos = subscription_options; + if(context->is_bridge){ + retain_as_published = 1; + } }else{ qos = subscription_options & 0x03; - retain_as_published = subscription_options & 0x04; + retain_as_published = subscription_options & 0x08; retain_handling = (subscription_options & 0x30) >> 4; if(retain_handling == 3){ @@ -148,7 +151,7 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) } if(qos != 0x80){ - rc2 = sub__add(db, context, sub, qos, &db->subs); + rc2 = sub__add(db, context, sub, qos, retain_as_published, &db->subs); if(context->protocol == mosq_p_mqtt311 || context->protocol == mosq_p_mqtt31){ if(rc2 == MOSQ_ERR_SUCCESS || rc2 == MOSQ_ERR_SUB_EXISTS){ if(sub__retain_queue(db, context, sub, qos)) rc = 1; diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index cc0a5eddfb..2156cc4ef4 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -290,6 +290,7 @@ struct mosquitto__subleaf { struct mosquitto__subleaf *next; struct mosquitto *context; int qos; + bool retain_as_published; }; struct mosquitto__subhier { @@ -572,7 +573,7 @@ void sys_tree__update(struct mosquitto_db *db, int interval, time_t start_time); /* ============================================================ * Subscription functions * ============================================================ */ -int sub__add(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int qos, struct mosquitto__subhier **root); +int sub__add(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int qos, bool retain_as_published, struct mosquitto__subhier **root); struct mosquitto__subhier *sub__add_hier_entry(struct mosquitto__subhier *parent, struct mosquitto__subhier **sibling, const char *topic, size_t len); int sub__remove(struct mosquitto_db *db, struct mosquitto *context, const char *sub, struct mosquitto__subhier *root); void sub__tree_print(struct mosquitto__subhier *root, int level); diff --git a/src/persist.c b/src/persist.c index b9e48ba3cc..8cc2de5fff 100644 --- a/src/persist.c +++ b/src/persist.c @@ -935,7 +935,8 @@ static int persist__restore_sub(struct mosquitto_db *db, const char *client_id, context = persist__find_or_add_context(db, client_id, 0); if(!context) return 1; - return sub__add(db, context, sub, qos, &db->subs); + /* FIXME - retain_as_published needs saving */ + return sub__add(db, context, sub, qos, false, &db->subs); } #endif diff --git a/src/subs.c b/src/subs.c index 901cb72b96..d608f36e9d 100644 --- a/src/subs.c +++ b/src/subs.c @@ -123,14 +123,9 @@ static int subs__process(struct mosquitto_db *db, struct mosquitto__subhier *hie }else{ mid = 0; } - if(leaf->context->is_bridge){ - /* If we know the client is a bridge then we should set retain - * even if the message is fresh. If we don't do this, retained - * messages won't be propagated. */ + if(leaf->retain_as_published){ client_retain = retain; }else{ - /* Client is not a bridge and this isn't a stale message so - * retain should be false. */ client_retain = false; } if(db__message_insert(db, leaf->context, mid, mosq_md_out, msg_qos, client_retain, stored) == 1) rc = 1; @@ -245,7 +240,7 @@ static void sub__topic_tokens_free(struct sub__token *tokens) } } -static int sub__add_recurse(struct mosquitto_db *db, struct mosquitto *context, int qos, struct mosquitto__subhier *subhier, struct sub__token *tokens) +static int sub__add_recurse(struct mosquitto_db *db, struct mosquitto *context, int qos, bool retain_as_published, struct mosquitto__subhier *subhier, struct sub__token *tokens) /* FIXME - this function has the potential to leak subhier, audit calling functions. */ { struct mosquitto__subhier *branch; @@ -279,6 +274,7 @@ static int sub__add_recurse(struct mosquitto_db *db, struct mosquitto *context, leaf->next = NULL; leaf->context = context; leaf->qos = qos; + leaf->retain_as_published = retain_as_published; for(i=0; isub_count; i++){ if(!context->subs[i]){ context->subs[i] = subhier; @@ -311,13 +307,13 @@ static int sub__add_recurse(struct mosquitto_db *db, struct mosquitto *context, HASH_FIND(hh, subhier->children, UHPA_ACCESS_TOPIC(tokens), tokens->topic_len, branch); if(branch){ - return sub__add_recurse(db, context, qos, branch, tokens->next); + return sub__add_recurse(db, context, qos, retain_as_published, branch, tokens->next); }else{ /* Not found */ branch = sub__add_hier_entry(subhier, &subhier->children, UHPA_ACCESS_TOPIC(tokens), tokens->topic_len); if(!branch) return MOSQ_ERR_NOMEM; - return sub__add_recurse(db, context, qos, branch, tokens->next); + return sub__add_recurse(db, context, qos, retain_as_published, branch, tokens->next); } } @@ -446,7 +442,7 @@ struct mosquitto__subhier *sub__add_hier_entry(struct mosquitto__subhier *parent } -int sub__add(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int qos, struct mosquitto__subhier **root) +int sub__add(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int qos, bool retain_as_published, struct mosquitto__subhier **root) { int rc = 0; struct mosquitto__subhier *subhier; @@ -468,7 +464,7 @@ int sub__add(struct mosquitto_db *db, struct mosquitto *context, const char *sub } } - rc = sub__add_recurse(db, context, qos, subhier, tokens); + rc = sub__add_recurse(db, context, qos, retain_as_published, subhier, tokens); sub__topic_tokens_free(tokens); @@ -519,7 +515,7 @@ int sub__messages_queue(struct mosquitto_db *db, const char *source_id, const ch /* We have a message that needs to be retained, so ensure that the subscription * tree for its topic exists. */ - sub__add_recurse(db, NULL, 0, subhier, tokens); + sub__add_recurse(db, NULL, 0, false, subhier, tokens); } sub__search(db, subhier, tokens, source_id, topic, qos, retain, *stored, true); } From 291951038480f8d9e26275eb91eae053c1c1b517 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 14 Dec 2018 13:54:26 +0000 Subject: [PATCH 155/254] No local support. --- src/handle_subscribe.c | 12 ++++-------- src/mosquitto_broker_internal.h | 3 ++- src/subs.c | 15 ++++++++------- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/handle_subscribe.c b/src/handle_subscribe.c index 7cf62855d8..aac6ad6d21 100644 --- a/src/handle_subscribe.c +++ b/src/handle_subscribe.c @@ -36,7 +36,6 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) uint8_t subscription_options; uint8_t qos; uint8_t retain_handling = 0; - uint8_t retain_as_published = 0; uint8_t *payload = NULL, *tmp_payload; uint32_t payloadlen = 0; int len; @@ -95,17 +94,14 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) if(context->protocol == mosq_p_mqtt31 || context->protocol == mosq_p_mqtt311){ qos = subscription_options; if(context->is_bridge){ - retain_as_published = 1; + subscription_options = MQTT_SUB_OPT_RETAIN_AS_PUBLISHED | MQTT_SUB_OPT_NO_LOCAL; } }else{ qos = subscription_options & 0x03; - - retain_as_published = subscription_options & 0x08; + subscription_options &= 0xFC; retain_handling = (subscription_options & 0x30) >> 4; - if(retain_handling == 3){ - mosquitto__free(sub); - mosquitto__free(payload); + if(retain_handling == 3 || (subscription_options & 0xC0) != 0){ return MOSQ_ERR_PROTOCOL; } } @@ -151,7 +147,7 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) } if(qos != 0x80){ - rc2 = sub__add(db, context, sub, qos, retain_as_published, &db->subs); + rc2 = sub__add(db, context, sub, qos, subscription_options, &db->subs); if(context->protocol == mosq_p_mqtt311 || context->protocol == mosq_p_mqtt31){ if(rc2 == MOSQ_ERR_SUCCESS || rc2 == MOSQ_ERR_SUB_EXISTS){ if(sub__retain_queue(db, context, sub, qos)) rc = 1; diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index 2156cc4ef4..d80accceeb 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -290,6 +290,7 @@ struct mosquitto__subleaf { struct mosquitto__subleaf *next; struct mosquitto *context; int qos; + bool no_local; bool retain_as_published; }; @@ -573,7 +574,7 @@ void sys_tree__update(struct mosquitto_db *db, int interval, time_t start_time); /* ============================================================ * Subscription functions * ============================================================ */ -int sub__add(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int qos, bool retain_as_published, struct mosquitto__subhier **root); +int sub__add(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int qos, int options, struct mosquitto__subhier **root); struct mosquitto__subhier *sub__add_hier_entry(struct mosquitto__subhier *parent, struct mosquitto__subhier **sibling, const char *topic, size_t len); int sub__remove(struct mosquitto_db *db, struct mosquitto *context, const char *sub, struct mosquitto__subhier *root); void sub__tree_print(struct mosquitto__subhier *root, int level); diff --git a/src/subs.c b/src/subs.c index d608f36e9d..0899383c83 100644 --- a/src/subs.c +++ b/src/subs.c @@ -97,7 +97,7 @@ static int subs__process(struct mosquitto_db *db, struct mosquitto__subhier *hie } } while(source_id && leaf){ - if(!leaf->context->id || (leaf->context->is_bridge && !strcmp(leaf->context->id, source_id))){ + if(!leaf->context->id || leaf->no_local){ leaf = leaf->next; continue; } @@ -240,7 +240,7 @@ static void sub__topic_tokens_free(struct sub__token *tokens) } } -static int sub__add_recurse(struct mosquitto_db *db, struct mosquitto *context, int qos, bool retain_as_published, struct mosquitto__subhier *subhier, struct sub__token *tokens) +static int sub__add_recurse(struct mosquitto_db *db, struct mosquitto *context, int qos, int options, struct mosquitto__subhier *subhier, struct sub__token *tokens) /* FIXME - this function has the potential to leak subhier, audit calling functions. */ { struct mosquitto__subhier *branch; @@ -274,7 +274,8 @@ static int sub__add_recurse(struct mosquitto_db *db, struct mosquitto *context, leaf->next = NULL; leaf->context = context; leaf->qos = qos; - leaf->retain_as_published = retain_as_published; + leaf->no_local = ((options & 0x04) != 0); + leaf->retain_as_published = ((options & 0x08) != 0); for(i=0; isub_count; i++){ if(!context->subs[i]){ context->subs[i] = subhier; @@ -307,13 +308,13 @@ static int sub__add_recurse(struct mosquitto_db *db, struct mosquitto *context, HASH_FIND(hh, subhier->children, UHPA_ACCESS_TOPIC(tokens), tokens->topic_len, branch); if(branch){ - return sub__add_recurse(db, context, qos, retain_as_published, branch, tokens->next); + return sub__add_recurse(db, context, qos, options, branch, tokens->next); }else{ /* Not found */ branch = sub__add_hier_entry(subhier, &subhier->children, UHPA_ACCESS_TOPIC(tokens), tokens->topic_len); if(!branch) return MOSQ_ERR_NOMEM; - return sub__add_recurse(db, context, qos, retain_as_published, branch, tokens->next); + return sub__add_recurse(db, context, qos, options, branch, tokens->next); } } @@ -442,7 +443,7 @@ struct mosquitto__subhier *sub__add_hier_entry(struct mosquitto__subhier *parent } -int sub__add(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int qos, bool retain_as_published, struct mosquitto__subhier **root) +int sub__add(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int qos, int options, struct mosquitto__subhier **root) { int rc = 0; struct mosquitto__subhier *subhier; @@ -464,7 +465,7 @@ int sub__add(struct mosquitto_db *db, struct mosquitto *context, const char *sub } } - rc = sub__add_recurse(db, context, qos, retain_as_published, subhier, tokens); + rc = sub__add_recurse(db, context, qos, options, subhier, tokens); sub__topic_tokens_free(tokens); From 1e6117bcf5b548ea9b01ef4365f4c1bf206867ee Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 14 Dec 2018 14:10:30 +0000 Subject: [PATCH 156/254] Fix duplicate string property tests. --- test/unit/property_read.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/test/unit/property_read.c b/test/unit/property_read.c index 8d9c4433dd..5982ae32fc 100644 --- a/test/unit/property_read.c +++ b/test/unit/property_read.c @@ -45,7 +45,7 @@ static void duplicate_byte_helper(int command, int identifier) payload[3] = identifier; payload[4] = 0; - byte_prop_read_helper(command, payload, 5, MOSQ_ERR_PROTOCOL, identifier, 1); + byte_prop_read_helper(command, payload, 5, MOSQ_ERR_DUPLICATE_PROPERTY, identifier, 1); } static void bad_byte_helper(int command, int identifier) @@ -107,7 +107,7 @@ static void duplicate_int32_helper(int command, int identifier) payload[9] = 0; payload[10] = 0; - int32_prop_read_helper(command, payload, 11, MOSQ_ERR_PROTOCOL, identifier, 1); + int32_prop_read_helper(command, payload, 11, MOSQ_ERR_DUPLICATE_PROPERTY, identifier, 1); } @@ -153,7 +153,7 @@ static void duplicate_int16_helper(int command, int identifier) payload[5] = 0; payload[6] = 0; - int16_prop_read_helper(command, payload, 7, MOSQ_ERR_PROTOCOL, identifier, 1); + int16_prop_read_helper(command, payload, 7, MOSQ_ERR_DUPLICATE_PROPERTY, identifier, 1); } static void string_prop_read_helper( @@ -186,7 +186,7 @@ static void string_prop_read_helper( CU_ASSERT_PTR_EQUAL(properties, NULL); } -static void duplicate_string_helper(int identifier) +static void duplicate_string_helper(int command, int identifier) { uint8_t payload[20]; @@ -201,7 +201,7 @@ static void duplicate_string_helper(int identifier) payload[7] = 1; payload[8] = 'h'; - string_prop_read_helper(CMD_PUBLISH, payload, 9, MOSQ_ERR_PROTOCOL, identifier, ""); + string_prop_read_helper(command, payload, 9, MOSQ_ERR_DUPLICATE_PROPERTY, identifier, ""); } static void bad_string_helper(int identifier) @@ -266,7 +266,7 @@ static void duplicate_binary_helper(int command, int identifier) payload[7] = 1; payload[8] = 'h'; - string_prop_read_helper(command, payload, 9, MOSQ_ERR_PROTOCOL, identifier, ""); + string_prop_read_helper(command, payload, 9, MOSQ_ERR_DUPLICATE_PROPERTY, identifier, ""); } static void string_pair_prop_read_helper( @@ -1004,37 +1004,37 @@ static void TEST_duplicate_topic_alias(void) static void TEST_duplicate_content_type(void) { - duplicate_string_helper(MQTT_PROP_CONTENT_TYPE); + duplicate_string_helper(CMD_PUBLISH, MQTT_PROP_CONTENT_TYPE); } static void TEST_duplicate_response_topic(void) { - duplicate_string_helper(MQTT_PROP_RESPONSE_TOPIC); + duplicate_string_helper(CMD_PUBLISH, MQTT_PROP_RESPONSE_TOPIC); } static void TEST_duplicate_assigned_client_identifier(void) { - duplicate_string_helper(MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER); + duplicate_string_helper(CMD_CONNACK, MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER); } static void TEST_duplicate_authentication_method(void) { - duplicate_string_helper(MQTT_PROP_AUTHENTICATION_METHOD); + duplicate_string_helper(CMD_AUTH, MQTT_PROP_AUTHENTICATION_METHOD); } static void TEST_duplicate_response_information(void) { - duplicate_string_helper(MQTT_PROP_RESPONSE_INFORMATION); + duplicate_string_helper(CMD_CONNACK, MQTT_PROP_RESPONSE_INFORMATION); } static void TEST_duplicate_server_reference(void) { - duplicate_string_helper(MQTT_PROP_SERVER_REFERENCE); + duplicate_string_helper(CMD_CONNACK, MQTT_PROP_SERVER_REFERENCE); } static void TEST_duplicate_reason_string(void) { - duplicate_string_helper(MQTT_PROP_REASON_STRING); + duplicate_string_helper(CMD_PUBACK, MQTT_PROP_REASON_STRING); } static void TEST_duplicate_correlation_data(void) From 679a9a54a592120cade83311c34dacadf0991b0b Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 14 Dec 2018 14:49:22 +0000 Subject: [PATCH 157/254] Tests for user facing property add functions. --- test/unit/Makefile | 1 + test/unit/property_add.c | 614 +++++++++++++++++++++++++++++++++++++++ test/unit/test.c | 2 + 3 files changed, 617 insertions(+) create mode 100644 test/unit/property_add.c diff --git a/test/unit/Makefile b/test/unit/Makefile index 611e20987a..ddc5237535 100644 --- a/test/unit/Makefile +++ b/test/unit/Makefile @@ -8,6 +8,7 @@ TEST_LDFLAGS=-lcunit -coverage TEST_OBJS = test.o \ datatype_read.o \ datatype_write.o \ + property_add.o \ property_read.o \ property_write.o \ stubs.o \ diff --git a/test/unit/property_add.c b/test/unit/property_add.c new file mode 100644 index 0000000000..341c008079 --- /dev/null +++ b/test/unit/property_add.c @@ -0,0 +1,614 @@ +#include +#include + +#include "mqtt_protocol.h" +#include "property_mosq.h" +#include "packet_mosq.h" + +/* ======================================================================== + * BAD IDENTIFIER + * ======================================================================== */ + +static void bad_add_byte_helper(int identifier) +{ + mosquitto_property *proplist = NULL; + int rc; + + rc = mosquitto_property_add_byte(&proplist, identifier, 1); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); + CU_ASSERT_PTR_NULL(proplist); +} + +static void bad_add_int16_helper(int identifier) +{ + mosquitto_property *proplist = NULL; + int rc; + + rc = mosquitto_property_add_int16(&proplist, identifier, 1); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); + CU_ASSERT_PTR_NULL(proplist); +} + +static void bad_add_int32_helper(int identifier) +{ + mosquitto_property *proplist = NULL; + int rc; + + rc = mosquitto_property_add_int32(&proplist, identifier, 1); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); + CU_ASSERT_PTR_NULL(proplist); +} + +static void bad_add_varint_helper(int identifier) +{ + mosquitto_property *proplist = NULL; + int rc; + + rc = mosquitto_property_add_varint(&proplist, identifier, 1); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); + CU_ASSERT_PTR_NULL(proplist); +} + +static void bad_add_binary_helper(int identifier) +{ + mosquitto_property *proplist = NULL; + int rc; + + rc = mosquitto_property_add_binary(&proplist, identifier, "test", 4); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); + CU_ASSERT_PTR_NULL(proplist); +} + +static void bad_add_string_helper(int identifier) +{ + mosquitto_property *proplist = NULL; + int rc; + + rc = mosquitto_property_add_string(&proplist, identifier, "test"); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); + CU_ASSERT_PTR_NULL(proplist); +} + +static void bad_add_string_pair_helper(int identifier) +{ + mosquitto_property *proplist = NULL; + int rc; + + rc = mosquitto_property_add_string_pair(&proplist, identifier, "key", "value"); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); + CU_ASSERT_PTR_NULL(proplist); +} + +static void TEST_add_bad_byte(void) +{ + bad_add_byte_helper(MQTT_PROP_MESSAGE_EXPIRY_INTERVAL); + bad_add_byte_helper(MQTT_PROP_CONTENT_TYPE); + bad_add_byte_helper(MQTT_PROP_RESPONSE_TOPIC); + bad_add_byte_helper(MQTT_PROP_CORRELATION_DATA); + bad_add_byte_helper(MQTT_PROP_SUBSCRIPTION_IDENTIFIER); + bad_add_byte_helper(MQTT_PROP_SESSION_EXPIRY_INTERVAL); + bad_add_byte_helper(MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER); + bad_add_byte_helper(MQTT_PROP_SERVER_KEEP_ALIVE); + bad_add_byte_helper(MQTT_PROP_AUTHENTICATION_METHOD); + bad_add_byte_helper(MQTT_PROP_AUTHENTICATION_DATA); + bad_add_byte_helper(MQTT_PROP_WILL_DELAY_INTERVAL); + bad_add_byte_helper(MQTT_PROP_RESPONSE_INFORMATION); + bad_add_byte_helper(MQTT_PROP_SERVER_REFERENCE); + bad_add_byte_helper(MQTT_PROP_REASON_STRING); + bad_add_byte_helper(MQTT_PROP_RECEIVE_MAXIMUM); + bad_add_byte_helper(MQTT_PROP_TOPIC_ALIAS_MAXIMUM); + bad_add_byte_helper(MQTT_PROP_TOPIC_ALIAS); + bad_add_byte_helper(MQTT_PROP_USER_PROPERTY); + bad_add_byte_helper(MQTT_PROP_MAXIMUM_PACKET_SIZE); +} + +static void TEST_add_bad_int16(void) +{ + bad_add_int16_helper(MQTT_PROP_PAYLOAD_FORMAT_INDICATOR); + bad_add_int16_helper(MQTT_PROP_MESSAGE_EXPIRY_INTERVAL); + bad_add_int16_helper(MQTT_PROP_CONTENT_TYPE); + bad_add_int16_helper(MQTT_PROP_RESPONSE_TOPIC); + bad_add_int16_helper(MQTT_PROP_CORRELATION_DATA); + bad_add_int16_helper(MQTT_PROP_SUBSCRIPTION_IDENTIFIER); + bad_add_int16_helper(MQTT_PROP_SESSION_EXPIRY_INTERVAL); + bad_add_int16_helper(MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER); + bad_add_int16_helper(MQTT_PROP_AUTHENTICATION_METHOD); + bad_add_int16_helper(MQTT_PROP_AUTHENTICATION_DATA); + bad_add_int16_helper(MQTT_PROP_REQUEST_PROBLEM_INFORMATION); + bad_add_int16_helper(MQTT_PROP_WILL_DELAY_INTERVAL); + bad_add_int16_helper(MQTT_PROP_REQUEST_RESPONSE_INFORMATION); + bad_add_int16_helper(MQTT_PROP_RESPONSE_INFORMATION); + bad_add_int16_helper(MQTT_PROP_SERVER_REFERENCE); + bad_add_int16_helper(MQTT_PROP_REASON_STRING); + bad_add_int16_helper(MQTT_PROP_MAXIMUM_QOS); + bad_add_int16_helper(MQTT_PROP_RETAIN_AVAILABLE); + bad_add_int16_helper(MQTT_PROP_USER_PROPERTY); + bad_add_int16_helper(MQTT_PROP_MAXIMUM_PACKET_SIZE); + bad_add_int16_helper(MQTT_PROP_WILDCARD_SUB_AVAILABLE); + bad_add_int16_helper(MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE); + bad_add_int16_helper(MQTT_PROP_SHARED_SUB_AVAILABLE); +} + +static void TEST_add_bad_int32(void) +{ + bad_add_int32_helper(MQTT_PROP_PAYLOAD_FORMAT_INDICATOR); + bad_add_int32_helper(MQTT_PROP_CONTENT_TYPE); + bad_add_int32_helper(MQTT_PROP_RESPONSE_TOPIC); + bad_add_int32_helper(MQTT_PROP_CORRELATION_DATA); + bad_add_int32_helper(MQTT_PROP_SUBSCRIPTION_IDENTIFIER); + bad_add_int32_helper(MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER); + bad_add_int32_helper(MQTT_PROP_SERVER_KEEP_ALIVE); + bad_add_int32_helper(MQTT_PROP_AUTHENTICATION_METHOD); + bad_add_int32_helper(MQTT_PROP_AUTHENTICATION_DATA); + bad_add_int32_helper(MQTT_PROP_REQUEST_PROBLEM_INFORMATION); + bad_add_int32_helper(MQTT_PROP_REQUEST_RESPONSE_INFORMATION); + bad_add_int32_helper(MQTT_PROP_RESPONSE_INFORMATION); + bad_add_int32_helper(MQTT_PROP_SERVER_REFERENCE); + bad_add_int32_helper(MQTT_PROP_REASON_STRING); + bad_add_int32_helper(MQTT_PROP_RECEIVE_MAXIMUM); + bad_add_int32_helper(MQTT_PROP_TOPIC_ALIAS_MAXIMUM); + bad_add_int32_helper(MQTT_PROP_TOPIC_ALIAS); + bad_add_int32_helper(MQTT_PROP_MAXIMUM_QOS); + bad_add_int32_helper(MQTT_PROP_RETAIN_AVAILABLE); + bad_add_int32_helper(MQTT_PROP_USER_PROPERTY); + bad_add_int32_helper(MQTT_PROP_WILDCARD_SUB_AVAILABLE); + bad_add_int32_helper(MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE); + bad_add_int32_helper(MQTT_PROP_SHARED_SUB_AVAILABLE); +} + +static void TEST_add_bad_varint(void) +{ + bad_add_varint_helper(MQTT_PROP_PAYLOAD_FORMAT_INDICATOR); + bad_add_varint_helper(MQTT_PROP_MESSAGE_EXPIRY_INTERVAL); + bad_add_varint_helper(MQTT_PROP_CONTENT_TYPE); + bad_add_varint_helper(MQTT_PROP_RESPONSE_TOPIC); + bad_add_varint_helper(MQTT_PROP_CORRELATION_DATA); + bad_add_varint_helper(MQTT_PROP_SESSION_EXPIRY_INTERVAL); + bad_add_varint_helper(MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER); + bad_add_varint_helper(MQTT_PROP_SERVER_KEEP_ALIVE); + bad_add_varint_helper(MQTT_PROP_AUTHENTICATION_METHOD); + bad_add_varint_helper(MQTT_PROP_AUTHENTICATION_DATA); + bad_add_varint_helper(MQTT_PROP_REQUEST_PROBLEM_INFORMATION); + bad_add_varint_helper(MQTT_PROP_WILL_DELAY_INTERVAL); + bad_add_varint_helper(MQTT_PROP_REQUEST_RESPONSE_INFORMATION); + bad_add_varint_helper(MQTT_PROP_RESPONSE_INFORMATION); + bad_add_varint_helper(MQTT_PROP_SERVER_REFERENCE); + bad_add_varint_helper(MQTT_PROP_REASON_STRING); + bad_add_varint_helper(MQTT_PROP_RECEIVE_MAXIMUM); + bad_add_varint_helper(MQTT_PROP_TOPIC_ALIAS_MAXIMUM); + bad_add_varint_helper(MQTT_PROP_TOPIC_ALIAS); + bad_add_varint_helper(MQTT_PROP_MAXIMUM_QOS); + bad_add_varint_helper(MQTT_PROP_RETAIN_AVAILABLE); + bad_add_varint_helper(MQTT_PROP_USER_PROPERTY); + bad_add_varint_helper(MQTT_PROP_MAXIMUM_PACKET_SIZE); + bad_add_varint_helper(MQTT_PROP_WILDCARD_SUB_AVAILABLE); + bad_add_varint_helper(MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE); + bad_add_varint_helper(MQTT_PROP_SHARED_SUB_AVAILABLE); +} + +static void TEST_add_bad_binary(void) +{ + bad_add_binary_helper(MQTT_PROP_PAYLOAD_FORMAT_INDICATOR); + bad_add_binary_helper(MQTT_PROP_MESSAGE_EXPIRY_INTERVAL); + bad_add_binary_helper(MQTT_PROP_CONTENT_TYPE); + bad_add_binary_helper(MQTT_PROP_RESPONSE_TOPIC); + bad_add_binary_helper(MQTT_PROP_SUBSCRIPTION_IDENTIFIER); + bad_add_binary_helper(MQTT_PROP_SESSION_EXPIRY_INTERVAL); + bad_add_binary_helper(MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER); + bad_add_binary_helper(MQTT_PROP_SERVER_KEEP_ALIVE); + bad_add_binary_helper(MQTT_PROP_AUTHENTICATION_METHOD); + bad_add_binary_helper(MQTT_PROP_REQUEST_PROBLEM_INFORMATION); + bad_add_binary_helper(MQTT_PROP_WILL_DELAY_INTERVAL); + bad_add_binary_helper(MQTT_PROP_REQUEST_RESPONSE_INFORMATION); + bad_add_binary_helper(MQTT_PROP_RESPONSE_INFORMATION); + bad_add_binary_helper(MQTT_PROP_SERVER_REFERENCE); + bad_add_binary_helper(MQTT_PROP_REASON_STRING); + bad_add_binary_helper(MQTT_PROP_RECEIVE_MAXIMUM); + bad_add_binary_helper(MQTT_PROP_TOPIC_ALIAS_MAXIMUM); + bad_add_binary_helper(MQTT_PROP_TOPIC_ALIAS); + bad_add_binary_helper(MQTT_PROP_MAXIMUM_QOS); + bad_add_binary_helper(MQTT_PROP_RETAIN_AVAILABLE); + bad_add_binary_helper(MQTT_PROP_USER_PROPERTY); + bad_add_binary_helper(MQTT_PROP_MAXIMUM_PACKET_SIZE); + bad_add_binary_helper(MQTT_PROP_WILDCARD_SUB_AVAILABLE); + bad_add_binary_helper(MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE); + bad_add_binary_helper(MQTT_PROP_SHARED_SUB_AVAILABLE); +} + +static void TEST_add_bad_string(void) +{ + bad_add_string_helper(MQTT_PROP_PAYLOAD_FORMAT_INDICATOR); + bad_add_string_helper(MQTT_PROP_MESSAGE_EXPIRY_INTERVAL); + bad_add_string_helper(MQTT_PROP_CORRELATION_DATA); + bad_add_string_helper(MQTT_PROP_SUBSCRIPTION_IDENTIFIER); + bad_add_string_helper(MQTT_PROP_SESSION_EXPIRY_INTERVAL); + bad_add_string_helper(MQTT_PROP_SERVER_KEEP_ALIVE); + bad_add_string_helper(MQTT_PROP_AUTHENTICATION_DATA); + bad_add_string_helper(MQTT_PROP_REQUEST_PROBLEM_INFORMATION); + bad_add_string_helper(MQTT_PROP_WILL_DELAY_INTERVAL); + bad_add_string_helper(MQTT_PROP_REQUEST_RESPONSE_INFORMATION); + bad_add_string_helper(MQTT_PROP_RECEIVE_MAXIMUM); + bad_add_string_helper(MQTT_PROP_TOPIC_ALIAS_MAXIMUM); + bad_add_string_helper(MQTT_PROP_TOPIC_ALIAS); + bad_add_string_helper(MQTT_PROP_MAXIMUM_QOS); + bad_add_string_helper(MQTT_PROP_RETAIN_AVAILABLE); + bad_add_string_helper(MQTT_PROP_USER_PROPERTY); + bad_add_string_helper(MQTT_PROP_MAXIMUM_PACKET_SIZE); + bad_add_string_helper(MQTT_PROP_WILDCARD_SUB_AVAILABLE); + bad_add_string_helper(MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE); + bad_add_string_helper(MQTT_PROP_SHARED_SUB_AVAILABLE); +} + +static void TEST_add_bad_string_pair(void) +{ + bad_add_string_pair_helper(MQTT_PROP_PAYLOAD_FORMAT_INDICATOR); + bad_add_string_pair_helper(MQTT_PROP_MESSAGE_EXPIRY_INTERVAL); + bad_add_string_pair_helper(MQTT_PROP_CONTENT_TYPE); + bad_add_string_pair_helper(MQTT_PROP_RESPONSE_TOPIC); + bad_add_string_pair_helper(MQTT_PROP_CORRELATION_DATA); + bad_add_string_pair_helper(MQTT_PROP_SUBSCRIPTION_IDENTIFIER); + bad_add_string_pair_helper(MQTT_PROP_SESSION_EXPIRY_INTERVAL); + bad_add_string_pair_helper(MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER); + bad_add_string_pair_helper(MQTT_PROP_SERVER_KEEP_ALIVE); + bad_add_string_pair_helper(MQTT_PROP_AUTHENTICATION_METHOD); + bad_add_string_pair_helper(MQTT_PROP_AUTHENTICATION_DATA); + bad_add_string_pair_helper(MQTT_PROP_REQUEST_PROBLEM_INFORMATION); + bad_add_string_pair_helper(MQTT_PROP_WILL_DELAY_INTERVAL); + bad_add_string_pair_helper(MQTT_PROP_REQUEST_RESPONSE_INFORMATION); + bad_add_string_pair_helper(MQTT_PROP_RESPONSE_INFORMATION); + bad_add_string_pair_helper(MQTT_PROP_SERVER_REFERENCE); + bad_add_string_pair_helper(MQTT_PROP_REASON_STRING); + bad_add_string_pair_helper(MQTT_PROP_RECEIVE_MAXIMUM); + bad_add_string_pair_helper(MQTT_PROP_TOPIC_ALIAS_MAXIMUM); + bad_add_string_pair_helper(MQTT_PROP_TOPIC_ALIAS); + bad_add_string_pair_helper(MQTT_PROP_MAXIMUM_QOS); + bad_add_string_pair_helper(MQTT_PROP_RETAIN_AVAILABLE); + bad_add_string_pair_helper(MQTT_PROP_MAXIMUM_PACKET_SIZE); + bad_add_string_pair_helper(MQTT_PROP_WILDCARD_SUB_AVAILABLE); + bad_add_string_pair_helper(MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE); + bad_add_string_pair_helper(MQTT_PROP_SHARED_SUB_AVAILABLE); +} + +/* ======================================================================== + * SINGLE ADD + * ======================================================================== */ + +static void single_add_byte_helper(int identifier) +{ + mosquitto_property *proplist = NULL; + int rc; + + rc = mosquitto_property_add_byte(&proplist, identifier, 1); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + if(proplist){ + CU_ASSERT_EQUAL(proplist->identifier, identifier); + CU_ASSERT_EQUAL(proplist->value.i8, 1); + CU_ASSERT_PTR_NULL(proplist->next); + + mosquitto_property_free_all(&proplist); + } +} + +static void single_add_int16_helper(int identifier) +{ + mosquitto_property *proplist = NULL; + int rc; + + rc = mosquitto_property_add_int16(&proplist, identifier, 11234); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + if(proplist){ + CU_ASSERT_EQUAL(proplist->identifier, identifier); + CU_ASSERT_EQUAL(proplist->value.i16, 11234); + CU_ASSERT_PTR_NULL(proplist->next); + + mosquitto_property_free_all(&proplist); + } +} + +static void single_add_int32_helper(int identifier) +{ + mosquitto_property *proplist = NULL; + int rc; + + rc = mosquitto_property_add_int32(&proplist, identifier, 765432); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + if(proplist){ + CU_ASSERT_EQUAL(proplist->identifier, identifier); + CU_ASSERT_EQUAL(proplist->value.i32, 765432); + CU_ASSERT_PTR_NULL(proplist->next); + + mosquitto_property_free_all(&proplist); + } +} + +static void single_add_varint_helper(int identifier) +{ + mosquitto_property *proplist = NULL; + int rc; + + rc = mosquitto_property_add_varint(&proplist, identifier, 139123999); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + if(proplist){ + CU_ASSERT_EQUAL(proplist->identifier, identifier); + CU_ASSERT_EQUAL(proplist->value.varint, 139123999); + CU_ASSERT_PTR_NULL(proplist->next); + + mosquitto_property_free_all(&proplist); + } +} + +static void single_add_binary_helper(int identifier) +{ + mosquitto_property *proplist = NULL; + int rc; + + rc = mosquitto_property_add_binary(&proplist, identifier, "test", 4); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + if(proplist){ + CU_ASSERT_EQUAL(proplist->identifier, identifier); + CU_ASSERT_EQUAL(proplist->value.bin.len, 4); + CU_ASSERT_NSTRING_EQUAL(proplist->value.bin.v, "test", 4); + CU_ASSERT_PTR_NULL(proplist->next); + + mosquitto_property_free_all(&proplist); + } +} + +static void single_add_string_helper(int identifier) +{ + mosquitto_property *proplist = NULL; + int rc; + + rc = mosquitto_property_add_string(&proplist, identifier, "string"); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + if(proplist){ + CU_ASSERT_EQUAL(proplist->identifier, identifier); + CU_ASSERT_STRING_EQUAL(proplist->value.s.v, "string"); + CU_ASSERT_EQUAL(proplist->value.s.len, strlen("string")); + CU_ASSERT_PTR_NULL(proplist->next); + + mosquitto_property_free_all(&proplist); + } +} + +static void single_add_string_pair_helper(int identifier) +{ + mosquitto_property *proplist = NULL; + int rc; + + rc = mosquitto_property_add_string_pair(&proplist, identifier, "key", "value"); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + if(proplist){ + CU_ASSERT_EQUAL(proplist->identifier, identifier); + CU_ASSERT_STRING_EQUAL(proplist->name.v, "key"); + CU_ASSERT_EQUAL(proplist->name.len, strlen("key")); + CU_ASSERT_STRING_EQUAL(proplist->value.s.v, "value"); + CU_ASSERT_EQUAL(proplist->value.s.len, strlen("value")); + CU_ASSERT_PTR_NULL(proplist->next); + + mosquitto_property_free_all(&proplist); + } +} + +static void TEST_add_single_byte(void) +{ + single_add_byte_helper(MQTT_PROP_PAYLOAD_FORMAT_INDICATOR); + single_add_byte_helper(MQTT_PROP_REQUEST_PROBLEM_INFORMATION); + single_add_byte_helper(MQTT_PROP_REQUEST_RESPONSE_INFORMATION); + single_add_byte_helper(MQTT_PROP_MAXIMUM_QOS); + single_add_byte_helper(MQTT_PROP_RETAIN_AVAILABLE); + single_add_byte_helper(MQTT_PROP_WILDCARD_SUB_AVAILABLE); + single_add_byte_helper(MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE); + single_add_byte_helper(MQTT_PROP_SHARED_SUB_AVAILABLE); +} + +static void TEST_add_single_int16(void) +{ + single_add_int16_helper(MQTT_PROP_SERVER_KEEP_ALIVE); + single_add_int16_helper(MQTT_PROP_RECEIVE_MAXIMUM); + single_add_int16_helper(MQTT_PROP_TOPIC_ALIAS_MAXIMUM); + single_add_int16_helper(MQTT_PROP_TOPIC_ALIAS); +} + +static void TEST_add_single_int32(void) +{ + single_add_int32_helper(MQTT_PROP_MESSAGE_EXPIRY_INTERVAL); + single_add_int32_helper(MQTT_PROP_SESSION_EXPIRY_INTERVAL); + single_add_int32_helper(MQTT_PROP_WILL_DELAY_INTERVAL); + single_add_int32_helper(MQTT_PROP_MAXIMUM_PACKET_SIZE); +} + +static void TEST_add_single_varint(void) +{ + single_add_varint_helper(MQTT_PROP_SUBSCRIPTION_IDENTIFIER); +} + +static void TEST_add_single_binary(void) +{ + single_add_binary_helper(MQTT_PROP_CORRELATION_DATA); + single_add_binary_helper(MQTT_PROP_AUTHENTICATION_DATA); +} + +static void TEST_add_single_string(void) +{ + single_add_string_helper(MQTT_PROP_CONTENT_TYPE); + single_add_string_helper(MQTT_PROP_RESPONSE_TOPIC); + single_add_string_helper(MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER); + single_add_string_helper(MQTT_PROP_AUTHENTICATION_METHOD); + single_add_string_helper(MQTT_PROP_RESPONSE_INFORMATION); + single_add_string_helper(MQTT_PROP_SERVER_REFERENCE); + single_add_string_helper(MQTT_PROP_REASON_STRING); +} + +static void TEST_add_single_string_pair(void) +{ + single_add_string_pair_helper(MQTT_PROP_USER_PROPERTY); +} + +/* ======================================================================== + * ADD ALL PROPERTIES FOR A COMMAND + * ======================================================================== */ + +static void TEST_add_all_connect(void) +{ + mosquitto_property *proplist = NULL; + mosquitto_property *p; + int count; + int rc; + + rc = mosquitto_property_add_int32(&proplist, MQTT_PROP_SESSION_EXPIRY_INTERVAL, 86400); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + rc = mosquitto_property_add_string(&proplist, MQTT_PROP_AUTHENTICATION_METHOD, "basic"); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + rc = mosquitto_property_add_binary(&proplist, MQTT_PROP_AUTHENTICATION_DATA, "password", strlen("password")); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + rc = mosquitto_property_add_byte(&proplist, MQTT_PROP_REQUEST_PROBLEM_INFORMATION, 1); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + rc = mosquitto_property_add_byte(&proplist, MQTT_PROP_REQUEST_RESPONSE_INFORMATION, 1); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + rc = mosquitto_property_add_int16(&proplist, MQTT_PROP_RECEIVE_MAXIMUM, 1024); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + rc = mosquitto_property_add_int16(&proplist, MQTT_PROP_TOPIC_ALIAS_MAXIMUM, 64); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + rc = mosquitto_property_add_string_pair(&proplist, MQTT_PROP_USER_PROPERTY, "user-agent", "mosquitto/test"); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + rc = mosquitto_property_add_int32(&proplist, MQTT_PROP_MAXIMUM_PACKET_SIZE, 200000000); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + + p = proplist; + count = 0; + while(p){ + count++; + p = p->next; + } + CU_ASSERT_EQUAL(count, 9); + + mosquitto_property_free_all(&proplist); +} + + +static void TEST_add_all_connack(void) +{ + mosquitto_property *proplist = NULL; + mosquitto_property *p; + int count; + int rc; + + rc = mosquitto_property_add_int32(&proplist, MQTT_PROP_SESSION_EXPIRY_INTERVAL, 86400); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + rc = mosquitto_property_add_string(&proplist, MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER, "clientid"); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + rc = mosquitto_property_add_int16(&proplist, MQTT_PROP_SERVER_KEEP_ALIVE, 900); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + rc = mosquitto_property_add_string(&proplist, MQTT_PROP_AUTHENTICATION_METHOD, "basic"); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + rc = mosquitto_property_add_binary(&proplist, MQTT_PROP_AUTHENTICATION_DATA, "password", strlen("password")); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + rc = mosquitto_property_add_string(&proplist, MQTT_PROP_RESPONSE_INFORMATION, "response"); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + rc = mosquitto_property_add_string(&proplist, MQTT_PROP_SERVER_REFERENCE, "localhost"); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + rc = mosquitto_property_add_string(&proplist, MQTT_PROP_REASON_STRING, "reason"); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + rc = mosquitto_property_add_int16(&proplist, MQTT_PROP_RECEIVE_MAXIMUM, 1024); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + rc = mosquitto_property_add_int16(&proplist, MQTT_PROP_TOPIC_ALIAS_MAXIMUM, 64); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + rc = mosquitto_property_add_byte(&proplist, MQTT_PROP_MAXIMUM_QOS, 1); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + rc = mosquitto_property_add_byte(&proplist, MQTT_PROP_RETAIN_AVAILABLE, 0); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + rc = mosquitto_property_add_string_pair(&proplist, MQTT_PROP_USER_PROPERTY, "user-agent", "mosquitto/test"); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + rc = mosquitto_property_add_int32(&proplist, MQTT_PROP_MAXIMUM_PACKET_SIZE, 200000000); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + rc = mosquitto_property_add_byte(&proplist, MQTT_PROP_WILDCARD_SUB_AVAILABLE, 0); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + rc = mosquitto_property_add_byte(&proplist, MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE, 0); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + rc = mosquitto_property_add_byte(&proplist, MQTT_PROP_SHARED_SUB_AVAILABLE, 0); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist); + + p = proplist; + count = 0; + while(p){ + count++; + p = p->next; + } + CU_ASSERT_EQUAL(count, 17); + + mosquitto_property_free_all(&proplist); +} + +/* ======================================================================== + * TEST SUITE SETUP + * ======================================================================== */ + +int init_property_add_tests(void) +{ + CU_pSuite test_suite = NULL; + + test_suite = CU_add_suite("Property add", NULL, NULL); + if(!test_suite){ + printf("Error adding CUnit Property add test suite.\n"); + return 1; + } + + if(0 + || !CU_add_test(test_suite, "Add bad byte", TEST_add_bad_byte) + || !CU_add_test(test_suite, "Add bad int16", TEST_add_bad_int16) + || !CU_add_test(test_suite, "Add bad int32", TEST_add_bad_int32) + || !CU_add_test(test_suite, "Add bad varint", TEST_add_bad_varint) + || !CU_add_test(test_suite, "Add bad binary", TEST_add_bad_binary) + || !CU_add_test(test_suite, "Add bad string", TEST_add_bad_string) + || !CU_add_test(test_suite, "Add bad string pair", TEST_add_bad_string_pair) + || !CU_add_test(test_suite, "Add single byte", TEST_add_single_byte) + || !CU_add_test(test_suite, "Add single int16", TEST_add_single_int16) + || !CU_add_test(test_suite, "Add single int32", TEST_add_single_int32) + || !CU_add_test(test_suite, "Add single varint", TEST_add_single_varint) + || !CU_add_test(test_suite, "Add single binary", TEST_add_single_binary) + || !CU_add_test(test_suite, "Add single string", TEST_add_single_string) + || !CU_add_test(test_suite, "Add single string pair", TEST_add_single_string_pair) + || !CU_add_test(test_suite, "Add all CONNECT", TEST_add_all_connect) + || !CU_add_test(test_suite, "Add all CONNACK", TEST_add_all_connack) + ){ + + printf("Error adding Property Add CUnit tests.\n"); + return 1; + } + + return 0; +} diff --git a/test/unit/test.c b/test/unit/test.c index 9e29f39132..6ae5cad3b8 100644 --- a/test/unit/test.c +++ b/test/unit/test.c @@ -5,6 +5,7 @@ int init_datatype_read_tests(void); int init_datatype_write_tests(void); +int init_property_add_tests(void); int init_property_read_tests(void); int init_property_write_tests(void); int init_utf8_tests(void); @@ -22,6 +23,7 @@ int main(int argc, char *argv[]) || init_utf8_tests() || init_datatype_read_tests() || init_datatype_write_tests() + || init_property_add_tests() || init_property_read_tests() || init_property_write_tests() || init_util_topic_tests() From 699e5c762f1a9d2778b2dbcd3f30c33c99cc2d1d Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 14 Dec 2018 19:09:31 +0000 Subject: [PATCH 158/254] Tests for user facing read functions. --- test/unit/Makefile | 1 + test/unit/property_user_read.c | 510 +++++++++++++++++++++++++++++++++ test/unit/test.c | 2 + 3 files changed, 513 insertions(+) create mode 100644 test/unit/property_user_read.c diff --git a/test/unit/Makefile b/test/unit/Makefile index ddc5237535..b627cbde6e 100644 --- a/test/unit/Makefile +++ b/test/unit/Makefile @@ -10,6 +10,7 @@ TEST_OBJS = test.o \ datatype_write.o \ property_add.o \ property_read.o \ + property_user_read.o \ property_write.o \ stubs.o \ util_topic_test.o \ diff --git a/test/unit/property_user_read.c b/test/unit/property_user_read.c new file mode 100644 index 0000000000..065237b2bd --- /dev/null +++ b/test/unit/property_user_read.c @@ -0,0 +1,510 @@ +#include +#include + +#include "mqtt_protocol.h" +#include "property_mosq.h" +#include "packet_mosq.h" + +static void generate_full_proplist(mosquitto_property **proplist) +{ + int rc; + + /* This isn't a valid proplist for sending, because it contains every + * property. Very useful for testing though. */ + rc = mosquitto_property_add_byte(proplist, MQTT_PROP_PAYLOAD_FORMAT_INDICATOR, 1); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_int32(proplist, MQTT_PROP_MESSAGE_EXPIRY_INTERVAL, 3600); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_string(proplist, MQTT_PROP_CONTENT_TYPE, "application/json"); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_string(proplist, MQTT_PROP_RESPONSE_TOPIC, "response/topic"); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_binary(proplist, MQTT_PROP_CORRELATION_DATA, "correlation-data", strlen("correlation-data")); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_varint(proplist, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 63); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_int32(proplist, MQTT_PROP_SESSION_EXPIRY_INTERVAL, 86400); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_string(proplist, MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER, "mosquitto-test"); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_int16(proplist, MQTT_PROP_SERVER_KEEP_ALIVE, 180); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_string(proplist, MQTT_PROP_AUTHENTICATION_METHOD, "basic"); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_binary(proplist, MQTT_PROP_AUTHENTICATION_DATA, "password", strlen("password")); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_byte(proplist, MQTT_PROP_REQUEST_PROBLEM_INFORMATION, 1); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_int32(proplist, MQTT_PROP_WILL_DELAY_INTERVAL, 1800); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_byte(proplist, MQTT_PROP_REQUEST_RESPONSE_INFORMATION, 1); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_string(proplist, MQTT_PROP_RESPONSE_INFORMATION, "response"); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_string(proplist, MQTT_PROP_SERVER_REFERENCE, "localhost"); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_string(proplist, MQTT_PROP_REASON_STRING, "reason"); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_int16(proplist, MQTT_PROP_RECEIVE_MAXIMUM, 1024); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_int16(proplist, MQTT_PROP_TOPIC_ALIAS_MAXIMUM, 64); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_int16(proplist, MQTT_PROP_TOPIC_ALIAS, 15); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_byte(proplist, MQTT_PROP_MAXIMUM_QOS, 0); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_byte(proplist, MQTT_PROP_RETAIN_AVAILABLE, 0); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_string_pair(proplist, MQTT_PROP_USER_PROPERTY, "user-agent", "mosquitto/test"); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_int32(proplist, MQTT_PROP_MAXIMUM_PACKET_SIZE, 200000000); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_byte(proplist, MQTT_PROP_WILDCARD_SUB_AVAILABLE, 0); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_byte(proplist, MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE, 0); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_byte(proplist, MQTT_PROP_SHARED_SUB_AVAILABLE, 0); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); +} + +static void generate_partial_proplist(mosquitto_property **proplist) +{ + int rc; + + // BYTE MISSING: MQTT_PROP_PAYLOAD_FORMAT_INDICATOR + rc = mosquitto_property_add_int32(proplist, MQTT_PROP_MESSAGE_EXPIRY_INTERVAL, 3600); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + // STRING MISSING: MQTT_PROP_CONTENT_TYPE + rc = mosquitto_property_add_string(proplist, MQTT_PROP_RESPONSE_TOPIC, "response/topic"); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + // BINARY MISSING: MQTT_PROP_CORRELATION_DATA + // VARINT MISSING: MQTT_PROP_SUBSCRIPTION_IDENTIFIER + // INT32 MISSING: MQTT_PROP_SESSION_EXPIRY_INTERVAL + rc = mosquitto_property_add_string(proplist, MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER, "mosquitto-test"); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + // INT16 MISSING: MQTT_PROP_SERVER_KEEP_ALIVE + rc = mosquitto_property_add_string(proplist, MQTT_PROP_AUTHENTICATION_METHOD, "basic"); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_binary(proplist, MQTT_PROP_AUTHENTICATION_DATA, "password", strlen("password")); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_byte(proplist, MQTT_PROP_REQUEST_PROBLEM_INFORMATION, 1); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_int32(proplist, MQTT_PROP_WILL_DELAY_INTERVAL, 1800); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_byte(proplist, MQTT_PROP_REQUEST_RESPONSE_INFORMATION, 1); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_string(proplist, MQTT_PROP_RESPONSE_INFORMATION, "response"); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_string(proplist, MQTT_PROP_SERVER_REFERENCE, "localhost"); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_string(proplist, MQTT_PROP_REASON_STRING, "reason"); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_int16(proplist, MQTT_PROP_RECEIVE_MAXIMUM, 1024); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_int16(proplist, MQTT_PROP_TOPIC_ALIAS_MAXIMUM, 64); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_int16(proplist, MQTT_PROP_TOPIC_ALIAS, 15); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_byte(proplist, MQTT_PROP_MAXIMUM_QOS, 0); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_byte(proplist, MQTT_PROP_RETAIN_AVAILABLE, 0); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + // STRING PAIR MISSING: MQTT_PROP_USER_PROPERTY + rc = mosquitto_property_add_int32(proplist, MQTT_PROP_MAXIMUM_PACKET_SIZE, 200000000); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_byte(proplist, MQTT_PROP_WILDCARD_SUB_AVAILABLE, 0); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_byte(proplist, MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE, 0); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + rc = mosquitto_property_add_byte(proplist, MQTT_PROP_SHARED_SUB_AVAILABLE, 0); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); +} + +/* ======================================================================== + * SINGLE READ + * ======================================================================== */ + +static void read_byte_helper(const mosquitto_property *proplist, int identifier, uint8_t expected_value) +{ + const mosquitto_property *prop; + uint8_t value; + + prop = mosquitto_property_read_byte(proplist, identifier, &value, false); + CU_ASSERT_PTR_NOT_NULL(prop); + CU_ASSERT_EQUAL(value, expected_value); +} + +static void read_int16_helper(const mosquitto_property *proplist, int identifier, uint16_t expected_value) +{ + const mosquitto_property *prop; + uint16_t value; + + prop = mosquitto_property_read_int16(proplist, identifier, &value, false); + CU_ASSERT_PTR_NOT_NULL(prop); + CU_ASSERT_EQUAL(value, expected_value); +} + +static void read_int32_helper(const mosquitto_property *proplist, int identifier, uint32_t expected_value) +{ + const mosquitto_property *prop; + uint32_t value; + + prop = mosquitto_property_read_int32(proplist, identifier, &value, false); + CU_ASSERT_PTR_NOT_NULL(prop); + CU_ASSERT_EQUAL(value, expected_value); +} + +static void read_varint_helper(const mosquitto_property *proplist, int identifier, uint32_t expected_value) +{ + const mosquitto_property *prop; + uint32_t value; + + prop = mosquitto_property_read_varint(proplist, identifier, &value, false); + CU_ASSERT_PTR_NOT_NULL(prop); + CU_ASSERT_EQUAL(value, expected_value); +} + +static void read_binary_helper(const mosquitto_property *proplist, int identifier, void *expected_value, int expected_length) +{ + const mosquitto_property *prop; + void *value; + int length; + + prop = mosquitto_property_read_binary(proplist, identifier, &value, &length, false); + CU_ASSERT_PTR_NOT_NULL(prop); + CU_ASSERT_EQUAL(length, expected_length); + CU_ASSERT_NSTRING_EQUAL(value, expected_value, expected_length); + free(value); +} + +static void read_string_helper(const mosquitto_property *proplist, int identifier, char *expected_value) +{ + const mosquitto_property *prop; + char *value; + + prop = mosquitto_property_read_string(proplist, identifier, &value, false); + CU_ASSERT_PTR_NOT_NULL(prop); + CU_ASSERT_STRING_EQUAL(value, expected_value); + free(value); +} + +static void read_string_pair_helper(const mosquitto_property *proplist, int identifier, char *expected_key, char *expected_value) +{ + const mosquitto_property *prop; + char *key, *value; + + prop = mosquitto_property_read_string_pair(proplist, identifier, &key, &value, false); + CU_ASSERT_PTR_NOT_NULL(prop); + CU_ASSERT_STRING_EQUAL(key, expected_key); + CU_ASSERT_STRING_EQUAL(value, expected_value); + free(key); + free(value); +} + + +static void TEST_read_single_byte(void) +{ + int rc; + mosquitto_property *proplist = NULL, *proplist_copy = NULL; + + generate_full_proplist(&proplist); + if(!proplist) return; + + read_byte_helper(proplist, MQTT_PROP_PAYLOAD_FORMAT_INDICATOR, 1); + read_byte_helper(proplist, MQTT_PROP_REQUEST_PROBLEM_INFORMATION, 1); + read_byte_helper(proplist, MQTT_PROP_REQUEST_RESPONSE_INFORMATION, 1); + read_byte_helper(proplist, MQTT_PROP_MAXIMUM_QOS, 0); + read_byte_helper(proplist, MQTT_PROP_RETAIN_AVAILABLE, 0); + read_byte_helper(proplist, MQTT_PROP_WILDCARD_SUB_AVAILABLE, 0); + read_byte_helper(proplist, MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE, 0); + read_byte_helper(proplist, MQTT_PROP_SHARED_SUB_AVAILABLE, 0); + + rc = mosquitto_property_copy_all(&proplist_copy, proplist); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist_copy); + + read_byte_helper(proplist_copy, MQTT_PROP_PAYLOAD_FORMAT_INDICATOR, 1); + read_byte_helper(proplist_copy, MQTT_PROP_REQUEST_PROBLEM_INFORMATION, 1); + read_byte_helper(proplist_copy, MQTT_PROP_REQUEST_RESPONSE_INFORMATION, 1); + read_byte_helper(proplist_copy, MQTT_PROP_MAXIMUM_QOS, 0); + read_byte_helper(proplist_copy, MQTT_PROP_RETAIN_AVAILABLE, 0); + read_byte_helper(proplist_copy, MQTT_PROP_WILDCARD_SUB_AVAILABLE, 0); + read_byte_helper(proplist_copy, MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE, 0); + read_byte_helper(proplist_copy, MQTT_PROP_SHARED_SUB_AVAILABLE, 0); + + mosquitto_property_free_all(&proplist); + mosquitto_property_free_all(&proplist_copy); +} + +static void TEST_read_single_int16(void) +{ + int rc; + mosquitto_property *proplist = NULL, *proplist_copy = NULL; + + generate_full_proplist(&proplist); + if(!proplist) return; + + read_int16_helper(proplist, MQTT_PROP_SERVER_KEEP_ALIVE, 180); + read_int16_helper(proplist, MQTT_PROP_RECEIVE_MAXIMUM, 1024); + read_int16_helper(proplist, MQTT_PROP_TOPIC_ALIAS_MAXIMUM, 64); + read_int16_helper(proplist, MQTT_PROP_TOPIC_ALIAS, 15); + + rc = mosquitto_property_copy_all(&proplist_copy, proplist); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist_copy); + + read_int16_helper(proplist_copy, MQTT_PROP_SERVER_KEEP_ALIVE, 180); + read_int16_helper(proplist_copy, MQTT_PROP_RECEIVE_MAXIMUM, 1024); + read_int16_helper(proplist_copy, MQTT_PROP_TOPIC_ALIAS_MAXIMUM, 64); + read_int16_helper(proplist_copy, MQTT_PROP_TOPIC_ALIAS, 15); + + mosquitto_property_free_all(&proplist); + mosquitto_property_free_all(&proplist_copy); +} + +static void TEST_read_single_int32(void) +{ + int rc; + mosquitto_property *proplist = NULL, *proplist_copy = NULL; + + generate_full_proplist(&proplist); + if(!proplist) return; + + read_int32_helper(proplist, MQTT_PROP_MESSAGE_EXPIRY_INTERVAL, 3600); + read_int32_helper(proplist, MQTT_PROP_SESSION_EXPIRY_INTERVAL, 86400); + read_int32_helper(proplist, MQTT_PROP_WILL_DELAY_INTERVAL, 1800); + read_int32_helper(proplist, MQTT_PROP_MAXIMUM_PACKET_SIZE, 200000000); + + rc = mosquitto_property_copy_all(&proplist_copy, proplist); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist_copy); + + read_int32_helper(proplist_copy, MQTT_PROP_MESSAGE_EXPIRY_INTERVAL, 3600); + read_int32_helper(proplist_copy, MQTT_PROP_SESSION_EXPIRY_INTERVAL, 86400); + read_int32_helper(proplist_copy, MQTT_PROP_WILL_DELAY_INTERVAL, 1800); + read_int32_helper(proplist_copy, MQTT_PROP_MAXIMUM_PACKET_SIZE, 200000000); + + mosquitto_property_free_all(&proplist); + mosquitto_property_free_all(&proplist_copy); +} + +static void TEST_read_single_varint(void) +{ + int rc; + mosquitto_property *proplist = NULL, *proplist_copy = NULL; + + generate_full_proplist(&proplist); + if(!proplist) return; + + read_varint_helper(proplist, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 63); + + rc = mosquitto_property_copy_all(&proplist_copy, proplist); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist_copy); + + read_varint_helper(proplist_copy, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, 63); + + mosquitto_property_free_all(&proplist); + mosquitto_property_free_all(&proplist_copy); +} + +static void TEST_read_single_binary(void) +{ + int rc; + mosquitto_property *proplist = NULL, *proplist_copy = NULL; + + generate_full_proplist(&proplist); + if(!proplist) return; + + read_binary_helper(proplist, MQTT_PROP_CORRELATION_DATA, "correlation-data", strlen("correlation-data")); + read_binary_helper(proplist, MQTT_PROP_AUTHENTICATION_DATA, "password", strlen("password")); + + rc = mosquitto_property_copy_all(&proplist_copy, proplist); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist_copy); + + read_binary_helper(proplist_copy, MQTT_PROP_CORRELATION_DATA, "correlation-data", strlen("correlation-data")); + read_binary_helper(proplist_copy, MQTT_PROP_AUTHENTICATION_DATA, "password", strlen("password")); + + mosquitto_property_free_all(&proplist); + mosquitto_property_free_all(&proplist_copy); +} + +static void TEST_read_single_string(void) +{ + int rc; + mosquitto_property *proplist = NULL, *proplist_copy = NULL; + + generate_full_proplist(&proplist); + if(!proplist) return; + + read_string_helper(proplist, MQTT_PROP_CONTENT_TYPE, "application/json"); + read_string_helper(proplist, MQTT_PROP_RESPONSE_TOPIC, "response/topic"); + read_string_helper(proplist, MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER, "mosquitto-test"); + read_string_helper(proplist, MQTT_PROP_AUTHENTICATION_METHOD, "basic"); + read_string_helper(proplist, MQTT_PROP_RESPONSE_INFORMATION, "response"); + read_string_helper(proplist, MQTT_PROP_SERVER_REFERENCE, "localhost"); + read_string_helper(proplist, MQTT_PROP_REASON_STRING, "reason"); + + rc = mosquitto_property_copy_all(&proplist_copy, proplist); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist_copy); + + read_string_helper(proplist_copy, MQTT_PROP_CONTENT_TYPE, "application/json"); + read_string_helper(proplist_copy, MQTT_PROP_RESPONSE_TOPIC, "response/topic"); + read_string_helper(proplist_copy, MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER, "mosquitto-test"); + read_string_helper(proplist_copy, MQTT_PROP_AUTHENTICATION_METHOD, "basic"); + read_string_helper(proplist_copy, MQTT_PROP_RESPONSE_INFORMATION, "response"); + read_string_helper(proplist_copy, MQTT_PROP_SERVER_REFERENCE, "localhost"); + read_string_helper(proplist_copy, MQTT_PROP_REASON_STRING, "reason"); + + mosquitto_property_free_all(&proplist); + mosquitto_property_free_all(&proplist_copy); +} + +static void TEST_read_single_string_pair(void) +{ + int rc; + mosquitto_property *proplist = NULL, *proplist_copy = NULL; + + generate_full_proplist(&proplist); + if(!proplist) return; + + read_string_pair_helper(proplist, MQTT_PROP_USER_PROPERTY, "user-agent", "mosquitto/test"); + + rc = mosquitto_property_copy_all(&proplist_copy, proplist); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist_copy); + + read_string_pair_helper(proplist_copy, MQTT_PROP_USER_PROPERTY, "user-agent", "mosquitto/test"); + + mosquitto_property_free_all(&proplist); + mosquitto_property_free_all(&proplist_copy); +} + +/* ======================================================================== + * MISSING READ + * ======================================================================== */ + +static void missing_read_helper(mosquitto_property *proplist) +{ + const mosquitto_property *prop; + uint8_t byte_value; + uint16_t int16_value; + uint32_t int32_value; + char *key, *value; + int length; + + /* MISSING */ + prop = mosquitto_property_read_byte(proplist, MQTT_PROP_MESSAGE_EXPIRY_INTERVAL, &byte_value, false); + CU_ASSERT_PTR_NULL(prop); + + /* NOT MISSING */ + prop = mosquitto_property_read_int32(proplist, MQTT_PROP_WILL_DELAY_INTERVAL, &int32_value, false); + CU_ASSERT_PTR_NOT_NULL(prop); + CU_ASSERT_EQUAL(int32_value, 1800); + + /* MISSING */ + prop = mosquitto_property_read_string(proplist, MQTT_PROP_CONTENT_TYPE, &value, false); + CU_ASSERT_PTR_NULL(prop); + + /* NOT MISSING */ + prop = mosquitto_property_read_string(proplist, MQTT_PROP_RESPONSE_TOPIC, &value, false); + CU_ASSERT_PTR_NOT_NULL(prop); + CU_ASSERT_STRING_EQUAL(value, "response/topic"); + free(value); + + /* MISSING */ + prop = mosquitto_property_read_binary(proplist, MQTT_PROP_CORRELATION_DATA, (void **)&value, &length, false); + CU_ASSERT_PTR_NULL(prop); + + /* NOT MISSING */ + prop = mosquitto_property_read_byte(proplist, MQTT_PROP_REQUEST_PROBLEM_INFORMATION, &byte_value, false); + CU_ASSERT_PTR_NOT_NULL(prop); + CU_ASSERT_EQUAL(byte_value, 1); + + /* MISSING */ + prop = mosquitto_property_read_varint(proplist, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, &int32_value, false); + CU_ASSERT_PTR_NULL(prop); + + /* NOT MISSING */ + prop = mosquitto_property_read_string(proplist, MQTT_PROP_SERVER_REFERENCE, &value, false); + CU_ASSERT_PTR_NOT_NULL(prop); + CU_ASSERT_STRING_EQUAL(value, "localhost"); + free(value); + + /* MISSING */ + prop = mosquitto_property_read_int32(proplist, MQTT_PROP_SESSION_EXPIRY_INTERVAL, &int32_value, false); + CU_ASSERT_PTR_NULL(prop); + + /* NOT MISSING */ + prop = mosquitto_property_read_binary(proplist, MQTT_PROP_AUTHENTICATION_DATA, (void **)&value, &length, false); + CU_ASSERT_PTR_NOT_NULL(prop); + CU_ASSERT_NSTRING_EQUAL(value, "password", strlen("password")); + CU_ASSERT_EQUAL(length, strlen("password")); + free(value); + + /* MISSING */ + prop = mosquitto_property_read_int16(proplist, MQTT_PROP_SERVER_KEEP_ALIVE, &int16_value, false); + CU_ASSERT_PTR_NULL(prop); + + /* NOT MISSING */ + prop = mosquitto_property_read_int16(proplist, MQTT_PROP_RECEIVE_MAXIMUM, &int16_value, false); + CU_ASSERT_PTR_NOT_NULL(prop); + CU_ASSERT_EQUAL(int16_value, 1024); + + /* MISSING */ + prop = mosquitto_property_read_string_pair(proplist, MQTT_PROP_USER_PROPERTY, &key, &value, false); + CU_ASSERT_PTR_NULL(prop); +} + + +static void TEST_read_missing(void) +{ + mosquitto_property *proplist = NULL, *proplist_copy = NULL; + int rc; + + generate_partial_proplist(&proplist); + if(!proplist) return; + + missing_read_helper(proplist); + rc = mosquitto_property_copy_all(&proplist_copy, proplist); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_PTR_NOT_NULL(proplist_copy); + missing_read_helper(proplist_copy); + + mosquitto_property_free_all(&proplist); + mosquitto_property_free_all(&proplist_copy); +} + +/* ======================================================================== + * TEST SUITE SETUP + * ======================================================================== */ + +int init_property_user_read_tests(void) +{ + CU_pSuite test_suite = NULL; + + test_suite = CU_add_suite("Property user read", NULL, NULL); + if(!test_suite){ + printf("Error adding CUnit Property user read test suite.\n"); + return 1; + } + + if(0 + || !CU_add_test(test_suite, "Read single byte", TEST_read_single_byte) + || !CU_add_test(test_suite, "Read single int16", TEST_read_single_int16) + || !CU_add_test(test_suite, "Read single int32", TEST_read_single_int32) + || !CU_add_test(test_suite, "Read single varint", TEST_read_single_varint) + || !CU_add_test(test_suite, "Read single binary", TEST_read_single_binary) + || !CU_add_test(test_suite, "Read single string", TEST_read_single_string) + || !CU_add_test(test_suite, "Read single string pair", TEST_read_single_string_pair) + || !CU_add_test(test_suite, "Read missing", TEST_read_missing) + ){ + + printf("Error adding Property Add CUnit tests.\n"); + return 1; + } + + return 0; +} diff --git a/test/unit/test.c b/test/unit/test.c index 6ae5cad3b8..17a3702396 100644 --- a/test/unit/test.c +++ b/test/unit/test.c @@ -7,6 +7,7 @@ int init_datatype_read_tests(void); int init_datatype_write_tests(void); int init_property_add_tests(void); int init_property_read_tests(void); +int init_property_user_read_tests(void); int init_property_write_tests(void); int init_utf8_tests(void); int init_util_topic_tests(void); @@ -25,6 +26,7 @@ int main(int argc, char *argv[]) || init_datatype_write_tests() || init_property_add_tests() || init_property_read_tests() + || init_property_user_read_tests() || init_property_write_tests() || init_util_topic_tests() ){ From 8b368aeb6be15427cff976fcfc1ec9189ae81561 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 14 Dec 2018 19:12:55 +0000 Subject: [PATCH 159/254] Fix memory leaks in tests. --- test/unit/property_write.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/unit/property_write.c b/test/unit/property_write.c index 6cc341ceb7..c689ba75a2 100644 --- a/test/unit/property_write.c +++ b/test/unit/property_write.c @@ -42,6 +42,7 @@ static void byte_prop_write_helper( mosquitto_property_free_all(&properties); } CU_ASSERT_PTR_EQUAL(properties, NULL); + free(packet.payload); } @@ -82,6 +83,7 @@ static void int32_prop_write_helper( mosquitto_property_free_all(&properties); } CU_ASSERT_PTR_EQUAL(properties, NULL); + free(packet.payload); } @@ -122,6 +124,7 @@ static void int16_prop_write_helper( mosquitto_property_free_all(&properties); } CU_ASSERT_PTR_EQUAL(properties, NULL); + free(packet.payload); } static void string_prop_write_helper( @@ -164,6 +167,7 @@ static void string_prop_write_helper( } CU_ASSERT_PTR_EQUAL(properties, NULL); free(property.value.s.v); + free(packet.payload); } @@ -209,6 +213,7 @@ static void binary_prop_write_helper( } CU_ASSERT_PTR_EQUAL(properties, NULL); free(property.value.bin.v); + free(packet.payload); } static void string_pair_prop_write_helper( @@ -261,6 +266,7 @@ static void string_pair_prop_write_helper( CU_ASSERT_PTR_NULL(properties); free(property.value.s.v); free(property.name.v); + free(packet.payload); } static void varint_prop_write_helper( @@ -308,6 +314,7 @@ static void varint_prop_write_helper( mosquitto_property_free_all(&properties); } CU_ASSERT_PTR_NULL(properties); + free(packet.payload); } /* ======================================================================== From bc1349c0d731f851881c1f8f699c43f8d5fc028f Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 14 Dec 2018 19:31:49 +0000 Subject: [PATCH 160/254] Tests for user facing mosquitto_string_to_property_info function. --- lib/property_mosq.c | 2 ++ test/unit/property_user_read.c | 55 ++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/lib/property_mosq.c b/lib/property_mosq.c index ae2d02bb5c..c8dde7f1b5 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -512,6 +512,8 @@ int mosquitto_property_check_command(int command, int identifier) int mosquitto_string_to_property_info(const char *propname, int *identifier, int *type) { + if(!propname) return MOSQ_ERR_INVAL; + if(!strcasecmp(propname, "payload-format-indicator")){ *identifier = MQTT_PROP_PAYLOAD_FORMAT_INDICATOR; *type = MQTT_PROP_TYPE_BYTE; diff --git a/test/unit/property_user_read.c b/test/unit/property_user_read.c index 065237b2bd..42a8c08d9b 100644 --- a/test/unit/property_user_read.c +++ b/test/unit/property_user_read.c @@ -477,6 +477,60 @@ static void TEST_read_missing(void) mosquitto_property_free_all(&proplist_copy); } +/* ======================================================================== + * STRING TO PROPERTY INFO + * ======================================================================== */ + +static void string_to_property_info_helper(const char *str, int rc_expected, int identifier_expected, int type_expected) +{ + int rc; + int identifier, type; + + rc = mosquitto_string_to_property_info(str, &identifier, &type); + CU_ASSERT_EQUAL(rc, rc_expected); + if(rc == MOSQ_ERR_SUCCESS){ + CU_ASSERT_EQUAL(identifier, identifier_expected); + CU_ASSERT_EQUAL(type, type_expected); + } +} + +static void TEST_string_to_property_info(void) +{ + string_to_property_info_helper("payload-format-indicator", MOSQ_ERR_SUCCESS, MQTT_PROP_PAYLOAD_FORMAT_INDICATOR, MQTT_PROP_TYPE_BYTE); + string_to_property_info_helper("message-expiry-interval", MOSQ_ERR_SUCCESS, MQTT_PROP_MESSAGE_EXPIRY_INTERVAL, MQTT_PROP_TYPE_INT32); + string_to_property_info_helper("content-type", MOSQ_ERR_SUCCESS, MQTT_PROP_CONTENT_TYPE, MQTT_PROP_TYPE_STRING); + string_to_property_info_helper("response-topic", MOSQ_ERR_SUCCESS, MQTT_PROP_RESPONSE_TOPIC, MQTT_PROP_TYPE_STRING); + string_to_property_info_helper("correlation-data", MOSQ_ERR_SUCCESS, MQTT_PROP_CORRELATION_DATA, MQTT_PROP_TYPE_BINARY); + string_to_property_info_helper("subscription-identifier", MOSQ_ERR_SUCCESS, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, MQTT_PROP_TYPE_VARINT); + string_to_property_info_helper("session-expiry-interval", MOSQ_ERR_SUCCESS, MQTT_PROP_SESSION_EXPIRY_INTERVAL, MQTT_PROP_TYPE_INT32); + string_to_property_info_helper("assigned-client-identifier", MOSQ_ERR_SUCCESS, MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER, MQTT_PROP_TYPE_STRING); + string_to_property_info_helper("server-keep-alive", MOSQ_ERR_SUCCESS, MQTT_PROP_SERVER_KEEP_ALIVE, MQTT_PROP_TYPE_INT16); + string_to_property_info_helper("authentication-method", MOSQ_ERR_SUCCESS, MQTT_PROP_AUTHENTICATION_METHOD, MQTT_PROP_TYPE_STRING); + string_to_property_info_helper("authentication-data", MOSQ_ERR_SUCCESS, MQTT_PROP_AUTHENTICATION_DATA, MQTT_PROP_TYPE_BINARY); + string_to_property_info_helper("request-problem-information", MOSQ_ERR_SUCCESS, MQTT_PROP_REQUEST_PROBLEM_INFORMATION, MQTT_PROP_TYPE_BYTE); + string_to_property_info_helper("will-delay-interval", MOSQ_ERR_SUCCESS, MQTT_PROP_WILL_DELAY_INTERVAL, MQTT_PROP_TYPE_INT32); + string_to_property_info_helper("request-response-information", MOSQ_ERR_SUCCESS, MQTT_PROP_REQUEST_RESPONSE_INFORMATION, MQTT_PROP_TYPE_BYTE); + string_to_property_info_helper("response-information", MOSQ_ERR_SUCCESS, MQTT_PROP_RESPONSE_INFORMATION, MQTT_PROP_TYPE_STRING); + string_to_property_info_helper("server-reference", MOSQ_ERR_SUCCESS, MQTT_PROP_SERVER_REFERENCE, MQTT_PROP_TYPE_STRING); + string_to_property_info_helper("reason-string", MOSQ_ERR_SUCCESS, MQTT_PROP_REASON_STRING, MQTT_PROP_TYPE_STRING); + string_to_property_info_helper("receive-maximum", MOSQ_ERR_SUCCESS, MQTT_PROP_RECEIVE_MAXIMUM, MQTT_PROP_TYPE_INT16); + string_to_property_info_helper("topic-alias-maximum", MOSQ_ERR_SUCCESS, MQTT_PROP_TOPIC_ALIAS_MAXIMUM, MQTT_PROP_TYPE_INT16); + string_to_property_info_helper("topic-alias", MOSQ_ERR_SUCCESS, MQTT_PROP_TOPIC_ALIAS, MQTT_PROP_TYPE_INT16); + string_to_property_info_helper("maximum-qos", MOSQ_ERR_SUCCESS, MQTT_PROP_MAXIMUM_QOS, MQTT_PROP_TYPE_BYTE); + string_to_property_info_helper("retain-available", MOSQ_ERR_SUCCESS, MQTT_PROP_RETAIN_AVAILABLE, MQTT_PROP_TYPE_BYTE); + string_to_property_info_helper("user-property", MOSQ_ERR_SUCCESS, MQTT_PROP_USER_PROPERTY, MQTT_PROP_TYPE_STRING_PAIR); + string_to_property_info_helper("maximum-packet-size", MOSQ_ERR_SUCCESS, MQTT_PROP_MAXIMUM_PACKET_SIZE, MQTT_PROP_TYPE_INT32); + string_to_property_info_helper("wildcard-subscription-available", MOSQ_ERR_SUCCESS, MQTT_PROP_WILDCARD_SUB_AVAILABLE, MQTT_PROP_TYPE_BYTE); + string_to_property_info_helper("subscription-identifier-available", MOSQ_ERR_SUCCESS, MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE, MQTT_PROP_TYPE_BYTE); + string_to_property_info_helper("shared-subscription-available", MOSQ_ERR_SUCCESS, MQTT_PROP_SHARED_SUB_AVAILABLE, MQTT_PROP_TYPE_BYTE); + + string_to_property_info_helper("payload-format-indicator1", MOSQ_ERR_INVAL, 0, 0); + string_to_property_info_helper("payload", MOSQ_ERR_INVAL, 0, 0); + string_to_property_info_helper("", MOSQ_ERR_INVAL, 0, 0); + string_to_property_info_helper(NULL, MOSQ_ERR_INVAL, 0, 0); +} + + /* ======================================================================== * TEST SUITE SETUP * ======================================================================== */ @@ -500,6 +554,7 @@ int init_property_user_read_tests(void) || !CU_add_test(test_suite, "Read single string", TEST_read_single_string) || !CU_add_test(test_suite, "Read single string pair", TEST_read_single_string_pair) || !CU_add_test(test_suite, "Read missing", TEST_read_missing) + || !CU_add_test(test_suite, "String to property info", TEST_string_to_property_info) ){ printf("Error adding Property Add CUnit tests.\n"); From 94fdc9cb44c829ff79c74e1daa6f7d04283dfffd Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 18 Dec 2018 10:15:28 +0000 Subject: [PATCH 161/254] Disallow UTF-8 control characters. --- lib/utf8_mosq.c | 4 ++++ test/unit/utf8.c | 32 ++++++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/lib/utf8_mosq.c b/lib/utf8_mosq.c index b08c9a4366..1edaceb2be 100644 --- a/lib/utf8_mosq.c +++ b/lib/utf8_mosq.c @@ -99,6 +99,10 @@ int mosquitto_validate_utf8(const char *str, int len) if((codepoint & 0xFFFF) == 0xFFFE || (codepoint & 0xFFFF) == 0xFFFF){ return MOSQ_ERR_MALFORMED_UTF8; } + /* Check for control characters */ + if(codepoint <= 0x001F || (codepoint >= 0x007F && codepoint <= 0x009F)){ + return MOSQ_ERR_MALFORMED_UTF8; + } } return MOSQ_ERR_SUCCESS; } diff --git a/test/unit/utf8.c b/test/unit/utf8.c index 09f1a1a469..52c339983f 100644 --- a/test/unit/utf8.c +++ b/test/unit/utf8.c @@ -56,13 +56,13 @@ static void TEST_utf8_boundary_conditions(void) /* 2 Boundary condition test cases */ /* 2.1 First possible sequence of a certain length */ utf8_helper_len("2.1.1 1 byte (U-00000000): \"\0\"", 39, MOSQ_ERR_MALFORMED_UTF8); - utf8_helper("2.1.2 2 bytes (U-00000080): \"€\"", MOSQ_ERR_SUCCESS); + utf8_helper("2.1.2 2 bytes (U-00000080): \"€\"", MOSQ_ERR_MALFORMED_UTF8); /* control char */ utf8_helper("2.1.3 3 bytes (U-00000800): \"à €\"", MOSQ_ERR_SUCCESS); utf8_helper("2.1.4 4 bytes (U-00010000): \"ð€€\"", MOSQ_ERR_SUCCESS); /* 2.2 Last possible sequence of a certain length */ - utf8_helper("2.2.1 1 byte (U-0000007F): \"\"", MOSQ_ERR_SUCCESS); + utf8_helper("2.2.1 1 byte (U-0000007F): \"\"", MOSQ_ERR_MALFORMED_UTF8); /* control char */ utf8_helper("2.2.2 2 bytes (U-000007FF): \"ß¿\"", MOSQ_ERR_SUCCESS); /* Non character */ utf8_helper("2.2.3 3 bytes (U-0000FFFF): \"ï¿¿\"", MOSQ_ERR_MALFORMED_UTF8); @@ -398,6 +398,33 @@ static void TEST_utf8_illegal_code_positions(void) } +void TEST_utf8_control_characters(void) +{ + char buf[10]; + int i; + + /* U+0001 to U+001F are single byte control characters */ + for(i=0x01; i<0x20; i++){ + buf[0] = i; + buf[1] = '\0'; + utf8_helper(buf, MOSQ_ERR_MALFORMED_UTF8); + } + + /* U+007F is a single byte control character */ + buf[0] = 0x7F; + buf[1] = '\0'; + utf8_helper(buf, MOSQ_ERR_MALFORMED_UTF8); + + /* U+007F to U+009F are two byte control characters */ + for(i=0x80; i<0xA0; i++){ + buf[0] = 0xC2; + buf[1] = i-0x80; + buf[2] = '\0'; + utf8_helper(buf, MOSQ_ERR_MALFORMED_UTF8); + } + +} + /* ======================================================================== * TEST SUITE SETUP * ======================================================================== */ @@ -420,6 +447,7 @@ int init_utf8_tests(void) || !CU_add_test(test_suite, "UTF-8 malformed sequences", TEST_utf8_malformed_sequences) || !CU_add_test(test_suite, "UTF-8 overlong encoding", TEST_utf8_overlong_encoding) || !CU_add_test(test_suite, "UTF-8 illegal code positions", TEST_utf8_illegal_code_positions) + || !CU_add_test(test_suite, "UTF-8 control characters", TEST_utf8_control_characters) ){ printf("Error adding UTF-8 CUnit tests.\n"); From 72fdb590b167192b75bed8f070c5508504f6259b Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 19 Dec 2018 10:45:40 +0000 Subject: [PATCH 162/254] Fix no local and retain as published for local bridges. --- src/bridge.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/bridge.c b/src/bridge.c index 10c5744caf..8006c2d938 100644 --- a/src/bridge.c +++ b/src/bridge.c @@ -29,6 +29,7 @@ and the Eclipse Distribution License is available at #include #endif +#include "mqtt_protocol.h" #include "mosquitto.h" #include "mosquitto_broker_internal.h" #include "mosquitto_internal.h" @@ -144,7 +145,12 @@ int bridge__connect_step1(struct mosquitto_db *db, struct mosquitto *context) for(i=0; ibridge->topic_count; i++){ if(context->bridge->topics[i].direction == bd_out || context->bridge->topics[i].direction == bd_both){ log__printf(NULL, MOSQ_LOG_DEBUG, "Bridge %s doing local SUBSCRIBE on topic %s", context->id, context->bridge->topics[i].local_topic); - if(sub__add(db, context, context->bridge->topics[i].local_topic, context->bridge->topics[i].qos, &db->subs) > 0){ + if(sub__add(db, + context, + context->bridge->topics[i].local_topic, + context->bridge->topics[i].qos, + MQTT_SUB_OPT_NO_LOCAL | MQTT_SUB_OPT_RETAIN_AS_PUBLISHED, + &db->subs) > 0){ return 1; } sub__retain_queue(db, context, @@ -312,7 +318,13 @@ int bridge__connect(struct mosquitto_db *db, struct mosquitto *context) for(i=0; ibridge->topic_count; i++){ if(context->bridge->topics[i].direction == bd_out || context->bridge->topics[i].direction == bd_both){ log__printf(NULL, MOSQ_LOG_DEBUG, "Bridge %s doing local SUBSCRIBE on topic %s", context->id, context->bridge->topics[i].local_topic); - if(sub__add(db, context, context->bridge->topics[i].local_topic, context->bridge->topics[i].qos, true, &db->subs) > 0){ + if(sub__add(db, + context, + context->bridge->topics[i].local_topic, + context->bridge->topics[i].qos, + MQTT_SUB_OPT_NO_LOCAL | MQTT_SUB_OPT_RETAIN_AS_PUBLISHED, + &db->subs) > 0){ + return 1; } sub__retain_queue(db, context, From 31e6dbbe741cb9b9131619ae6fba1739a375135c Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 19 Dec 2018 12:54:04 +0000 Subject: [PATCH 163/254] Tests and fixes for subscription options. --- src/handle_subscribe.c | 12 ++- src/subs.c | 4 +- .../02-subpub-qos0-retain-as-publish.py | 53 +++++++++++++ test/broker/02-subpub-qos0-send-retain.py | 76 +++++++++++++++++++ test/broker/02-subpub-qos1-nolocal.py | 58 ++++++++++++++ test/broker/Makefile | 3 + test/broker/mosq_test_helper.py | 1 + test/broker/ptest.py | 3 + test/mqtt5_opts.py | 5 ++ 9 files changed, 209 insertions(+), 6 deletions(-) create mode 100755 test/broker/02-subpub-qos0-retain-as-publish.py create mode 100755 test/broker/02-subpub-qos0-send-retain.py create mode 100755 test/broker/02-subpub-qos1-nolocal.py create mode 100644 test/mqtt5_opts.py diff --git a/src/handle_subscribe.c b/src/handle_subscribe.c index aac6ad6d21..4d59da6f0d 100644 --- a/src/handle_subscribe.c +++ b/src/handle_subscribe.c @@ -100,8 +100,8 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) qos = subscription_options & 0x03; subscription_options &= 0xFC; - retain_handling = (subscription_options & 0x30) >> 4; - if(retain_handling == 3 || (subscription_options & 0xC0) != 0){ + retain_handling = (subscription_options & 0x30); + if(retain_handling == 0x30 || (subscription_options & 0xC0) != 0){ return MOSQ_ERR_PROTOCOL; } } @@ -148,13 +148,17 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) if(qos != 0x80){ rc2 = sub__add(db, context, sub, qos, subscription_options, &db->subs); + if(rc2 > 0){ + mosquitto__free(sub); + return rc2; + } if(context->protocol == mosq_p_mqtt311 || context->protocol == mosq_p_mqtt31){ if(rc2 == MOSQ_ERR_SUCCESS || rc2 == MOSQ_ERR_SUB_EXISTS){ if(sub__retain_queue(db, context, sub, qos)) rc = 1; } }else{ - if((rc2 == MOSQ_ERR_SUCCESS && retain_handling == 0) - || (rc2 == MOSQ_ERR_SUB_EXISTS && retain_handling == 1)){ + if((retain_handling == MQTT_SUB_OPT_SEND_RETAIN_ALWAYS) + || (rc2 == MOSQ_ERR_SUCCESS && retain_handling == MQTT_SUB_OPT_SEND_RETAIN_NEW)){ if(sub__retain_queue(db, context, sub, qos)) rc = 1; } diff --git a/src/subs.c b/src/subs.c index 0899383c83..3e3bf3be11 100644 --- a/src/subs.c +++ b/src/subs.c @@ -258,12 +258,12 @@ static int sub__add_recurse(struct mosquitto_db *db, struct mosquitto *context, * need to update QoS. Return MOSQ_ERR_SUB_EXISTS to * indicate this to the calling function. */ leaf->qos = qos; - if(context->protocol == mosq_p_mqtt31){ + if(context->protocol == mosq_p_mqtt31 || context->protocol == mosq_p_mqtt5){ return MOSQ_ERR_SUB_EXISTS; }else{ /* mqttv311/mqttv5 requires retained messages are resent on * resubscribe. */ - return 0; + return MOSQ_ERR_SUCCESS; } } last_leaf = leaf; diff --git a/test/broker/02-subpub-qos0-retain-as-publish.py b/test/broker/02-subpub-qos0-retain-as-publish.py new file mode 100755 index 0000000000..d6436eeff1 --- /dev/null +++ b/test/broker/02-subpub-qos0-retain-as-publish.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +# Test whether a client subscribed to a topic with retain-as-published set works as expected. +# MQTT v5 + +from mosq_test_helper import * + +rc = 1 +keepalive = 60 +connect_packet = mosq_test.gen_connect("subpub-qos1-test", keepalive=keepalive, proto_ver=5) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +mid = 530 +subscribe1_packet = mosq_test.gen_subscribe(mid, "subpub/normal", 0, proto_ver=5) +suback1_packet = mosq_test.gen_suback(mid, 0, proto_ver=5) + +mid = 531 +subscribe2_packet = mosq_test.gen_subscribe(mid, "subpub/rap", 0 | mqtt5_opts.MQTT_SUB_OPT_RETAIN_AS_PUBLISHED, proto_ver=5) +suback2_packet = mosq_test.gen_suback(mid, 0, proto_ver=5) + +publish1_packet = mosq_test.gen_publish("subpub/normal", qos=0, retain=True, payload="message", proto_ver=5) +publish2_packet = mosq_test.gen_publish("subpub/rap", qos=0, retain=True, payload="message", proto_ver=5) + +publish1r_packet = mosq_test.gen_publish("subpub/normal", qos=0, retain=False, payload="message", proto_ver=5) +publish2r_packet = mosq_test.gen_publish("subpub/rap", qos=0, retain=True, payload="message", proto_ver=5) + +mid = 1 +publish3_packet = mosq_test.gen_publish("subpub/receive", qos=1, mid=mid, payload="success", proto_ver=5) + + +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) + + mosq_test.do_send_receive(sock, subscribe1_packet, suback1_packet, "suback1") + mosq_test.do_send_receive(sock, subscribe2_packet, suback2_packet, "suback2") + + mosq_test.do_send_receive(sock, publish1_packet, publish1r_packet, "publish1") + mosq_test.do_send_receive(sock, publish2_packet, publish2r_packet, "publish2") + rc = 0 + + sock.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/02-subpub-qos0-send-retain.py b/test/broker/02-subpub-qos0-send-retain.py new file mode 100755 index 0000000000..ed9ba735b1 --- /dev/null +++ b/test/broker/02-subpub-qos0-send-retain.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python + +# Test whether "send retain" subscribe options work +# MQTT v5 + +from mosq_test_helper import * + +rc = 1 +keepalive = 60 +connect_packet = mosq_test.gen_connect("subpub-test", keepalive=keepalive, proto_ver=5) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +mid = 530 +subscribe1_packet = mosq_test.gen_subscribe(mid, "subpub/always", 0 | mqtt5_opts.MQTT_SUB_OPT_SEND_RETAIN_ALWAYS, proto_ver=5) +suback1_packet = mosq_test.gen_suback(mid, 0, proto_ver=5) + +mid = 531 +subscribe2_packet = mosq_test.gen_subscribe(mid, "subpub/new", 0 | mqtt5_opts.MQTT_SUB_OPT_SEND_RETAIN_NEW, proto_ver=5) +suback2_packet = mosq_test.gen_suback(mid, 0, proto_ver=5) + +mid = 532 +subscribe3_packet = mosq_test.gen_subscribe(mid, "subpub/never", 0 | mqtt5_opts.MQTT_SUB_OPT_SEND_RETAIN_NEVER, proto_ver=5) +suback3_packet = mosq_test.gen_suback(mid, 0, proto_ver=5) + + +publish1_packet = mosq_test.gen_publish("subpub/always", qos=0, retain=True, payload="message", proto_ver=5) +publish2_packet = mosq_test.gen_publish("subpub/new", qos=0, retain=True, payload="message", proto_ver=5) +publish3_packet = mosq_test.gen_publish("subpub/never", qos=0, retain=True, payload="message", proto_ver=5) + +publish1r1_packet = mosq_test.gen_publish("subpub/always", qos=0, retain=True, payload="message", proto_ver=5) +publish1r2_packet = mosq_test.gen_publish("subpub/always", qos=0, retain=True, payload="message", proto_ver=5) +publish2r1_packet = mosq_test.gen_publish("subpub/new", qos=0, retain=True, payload="message", proto_ver=5) +publish2r2_packet = mosq_test.gen_publish("subpub/new", qos=0, retain=False, payload="message", proto_ver=5) +publish3r1_packet = mosq_test.gen_publish("subpub/never", qos=0, retain=False, payload="message", proto_ver=5) +publish3r2_packet = mosq_test.gen_publish("subpub/never", qos=0, retain=False, payload="message", proto_ver=5) + + +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=5, port=port) + + sock.send(publish1_packet) + sock.send(publish2_packet) + sock.send(publish3_packet) + + # Don't expect a message after this + mosq_test.do_send_receive(sock, subscribe3_packet, suback3_packet, "suback3") + # Don't expect a message after this + mosq_test.do_send_receive(sock, subscribe3_packet, suback3_packet, "suback3") + + # Expect a message after this, because it is the first subscribe + mosq_test.do_send_receive(sock, subscribe2_packet, suback2_packet, "suback2") + if mosq_test.expect_packet(sock, "publish2r1", publish2r1_packet): + # Don't expect a message after this, it is the second subscribe + mosq_test.do_send_receive(sock, subscribe2_packet, suback2_packet, "suback2") + + # Always expect a message after this + mosq_test.do_send_receive(sock, subscribe1_packet, suback1_packet, "suback1") + if mosq_test.expect_packet(sock, "publish1r1", publish1r1_packet): + # Always expect a message after this + mosq_test.do_send_receive(sock, subscribe1_packet, suback1_packet, "suback1") + if mosq_test.expect_packet(sock, "publish1r1", publish1r2_packet): + rc = 0 + + sock.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/02-subpub-qos1-nolocal.py b/test/broker/02-subpub-qos1-nolocal.py new file mode 100755 index 0000000000..d66be515e9 --- /dev/null +++ b/test/broker/02-subpub-qos1-nolocal.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python + +# Test whether a client subscribed to a topic does not receive its own message +# sent to that topic if no local is set. +# MQTT v5 + +from mosq_test_helper import * + +rc = 1 +keepalive = 60 +connect_packet = mosq_test.gen_connect("subpub-qos1-test", keepalive=keepalive, proto_ver=5) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +mid = 530 +subscribe_packet = mosq_test.gen_subscribe(mid, "subpub/qos1", 1 | mqtt5_opts.MQTT_SUB_OPT_NO_LOCAL, proto_ver=5) +suback_packet = mosq_test.gen_suback(mid, 1, proto_ver=5) + +mid = 531 +subscribe2_packet = mosq_test.gen_subscribe(mid, "subpub/receive", 1, proto_ver=5) +suback2_packet = mosq_test.gen_suback(mid, 1, proto_ver=5) + +mid = 300 +publish_packet = mosq_test.gen_publish("subpub/qos1", qos=1, mid=mid, payload="message", proto_ver=5) +puback_packet = mosq_test.gen_puback(mid, proto_ver=5) + +mid = 301 +publish2_packet = mosq_test.gen_publish("subpub/receive", qos=1, mid=mid, payload="success", proto_ver=5) +puback2_packet = mosq_test.gen_puback(mid, proto_ver=5) + +mid = 1 +publish3_packet = mosq_test.gen_publish("subpub/receive", qos=1, mid=mid, payload="success", proto_ver=5) + + +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) + + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback") + mosq_test.do_send_receive(sock, subscribe2_packet, suback2_packet, "suback2") + + mosq_test.do_send_receive(sock, publish_packet, puback_packet, "puback") + mosq_test.do_send_receive(sock, publish2_packet, puback2_packet, "puback2") + + if mosq_test.expect_packet(sock, "publish3", publish3_packet): + rc = 0 + + sock.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index 3105c62ad1..1d80d79d9a 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -49,6 +49,9 @@ endif ./02-subpub-qos0-v5.py ./02-subpub-qos1-v5.py ./02-subpub-qos2-v5.py + ./02-subpub-qos1-nolocal.py + ./02-subpub-qos0-retain-as-publish.py + ./02-subpub-qos0-send-retain.py ./02-unsubscribe-qos0.py ./02-unsubscribe-qos1.py ./02-unsubscribe-qos2.py diff --git a/test/broker/mosq_test_helper.py b/test/broker/mosq_test_helper.py index 0e861dba07..9b8f2113b6 100644 --- a/test/broker/mosq_test_helper.py +++ b/test/broker/mosq_test_helper.py @@ -6,6 +6,7 @@ sys.path.insert(0, cmd_subfolder) import mosq_test +import mqtt5_opts import mqtt5_props import socket diff --git a/test/broker/ptest.py b/test/broker/ptest.py index 2804dfd86f..68f1ed25f6 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -32,6 +32,9 @@ (1, './02-subpub-qos0-v5.py'), (1, './02-subpub-qos1-v5.py'), (1, './02-subpub-qos2-v5.py'), + (1, './02-subpub-qos1-nolocal.py'), + (1, './02-subpub-qos0-retain-as-publish.py'), + (1, './02-subpub-qos0-send-retain.py'), (1, './02-unsubscribe-qos0.py'), (1, './02-unsubscribe-qos1.py'), (1, './02-unsubscribe-qos2.py'), diff --git a/test/mqtt5_opts.py b/test/mqtt5_opts.py new file mode 100644 index 0000000000..55675a738a --- /dev/null +++ b/test/mqtt5_opts.py @@ -0,0 +1,5 @@ +MQTT_SUB_OPT_NO_LOCAL = 0x04 +MQTT_SUB_OPT_RETAIN_AS_PUBLISHED = 0x08 +MQTT_SUB_OPT_SEND_RETAIN_ALWAYS = 0x00 +MQTT_SUB_OPT_SEND_RETAIN_NEW = 0x10 +MQTT_SUB_OPT_SEND_RETAIN_NEVER = 0x20 From ec1178806c1bb3cd31e0099ff1904f8e4689742b Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 19 Dec 2018 14:38:49 +0000 Subject: [PATCH 164/254] Fix bridge tests. --- src/subs.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/subs.c b/src/subs.c index 3e3bf3be11..acc8714a07 100644 --- a/src/subs.c +++ b/src/subs.c @@ -53,6 +53,7 @@ and the Eclipse Distribution License is available at #include "mosquitto_broker_internal.h" #include "memory_mosq.h" +#include "mqtt_protocol.h" #include "util_mosq.h" struct sub__token { @@ -97,7 +98,7 @@ static int subs__process(struct mosquitto_db *db, struct mosquitto__subhier *hie } } while(source_id && leaf){ - if(!leaf->context->id || leaf->no_local){ + if(!leaf->context->id || (leaf->no_local && !strcmp(leaf->context->id, source_id))){ leaf = leaf->next; continue; } @@ -274,8 +275,8 @@ static int sub__add_recurse(struct mosquitto_db *db, struct mosquitto *context, leaf->next = NULL; leaf->context = context; leaf->qos = qos; - leaf->no_local = ((options & 0x04) != 0); - leaf->retain_as_published = ((options & 0x08) != 0); + leaf->no_local = ((options & MQTT_SUB_OPT_NO_LOCAL) != 0); + leaf->retain_as_published = ((options & MQTT_SUB_OPT_RETAIN_AS_PUBLISHED) != 0); for(i=0; isub_count; i++){ if(!context->subs[i]){ context->subs[i] = subhier; From dab6452a1d2ac8df4fa14b02f92650568da3bf0f Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 19 Dec 2018 21:58:59 +0000 Subject: [PATCH 165/254] Add test for duplicate CONNECT. --- src/handle_connect.c | 1 + test/broker/01-connect-duplicate-v5.py | 32 ++++++++++++++++++++++++++ test/broker/01-connect-duplicate.py | 32 ++++++++++++++++++++++++++ test/broker/Makefile | 2 ++ test/broker/ptest.py | 2 ++ 5 files changed, 69 insertions(+) create mode 100755 test/broker/01-connect-duplicate-v5.py create mode 100755 test/broker/01-connect-duplicate.py diff --git a/src/handle_connect.c b/src/handle_connect.c index 342cac566b..aac409be50 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -196,6 +196,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) /* Don't accept multiple CONNECT commands. */ if(context->state != mosq_cs_new){ + log__printf(NULL, MOSQ_LOG_NOTICE, "Bad client %s sending multiple CONNECT messages.", context->id); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } diff --git a/test/broker/01-connect-duplicate-v5.py b/test/broker/01-connect-duplicate-v5.py new file mode 100755 index 0000000000..a7640e7cf9 --- /dev/null +++ b/test/broker/01-connect-duplicate-v5.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python + +# Test whether a duplicate CONNECT is rejected. MQTT v5 + +from mosq_test_helper import * + +rc = 1 +keepalive = 10 +connect_packet = mosq_test.gen_connect("connect-test", keepalive=keepalive, proto_ver=5) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +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, port=port) + sock.settimeout(3) + sock.send(connect_packet) + data = sock.recv(1) + if len(data) == 0: + rc = 0 +except socket.error: + rc = 0 +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/01-connect-duplicate.py b/test/broker/01-connect-duplicate.py new file mode 100755 index 0000000000..d99297b667 --- /dev/null +++ b/test/broker/01-connect-duplicate.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python + +# Test whether a duplicate CONNECT is rejected. + +from mosq_test_helper import * + +rc = 1 +keepalive = 10 +connect_packet = mosq_test.gen_connect("connect-test", keepalive=keepalive) +connack_packet = mosq_test.gen_connack(rc=0) + +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, port=port) + sock.settimeout(3) + sock.send(connect_packet) + data = sock.recv(1) + if len(data) == 0: + rc = 0 +except socket.error: + rc = 0 +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index 681387e6af..102a74740e 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -18,6 +18,8 @@ ptest : test-compile test : test-compile 01 02 03 04 05 06 07 08 09 10 11 12 01 : + ./01-connect-duplicate.py + ./01-connect-duplicate-v5.py ./01-connect-success.py ./01-connect-success-v5.py ./01-connect-invalid-protonum.py diff --git a/test/broker/ptest.py b/test/broker/ptest.py index 42ca336f65..41f690b252 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -7,6 +7,8 @@ max_running = 10 tests = [ #(ports required, 'path'), + (1, './01-connect-duplicate.py'), + (1, './01-connect-duplicate-v5.py'), (1, './01-connect-success.py'), (1, './01-connect-success-v5.py'), (1, './01-connect-invalid-protonum.py'), From ef724e6d3378ad7624480ede59ff0be042cf00cd Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 19 Dec 2018 22:17:56 +0000 Subject: [PATCH 166/254] Add test for first packet not being CONNECT. --- test/broker/01-connect-bad-packet.py | 35 ++++++++++++++++++++++++++++ test/broker/Makefile | 1 + test/broker/ptest.py | 1 + 3 files changed, 37 insertions(+) create mode 100755 test/broker/01-connect-bad-packet.py diff --git a/test/broker/01-connect-bad-packet.py b/test/broker/01-connect-bad-packet.py new file mode 100755 index 0000000000..723e07e588 --- /dev/null +++ b/test/broker/01-connect-bad-packet.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python + +# Test whether a first packet of non-CONNECT is rejected. + +from mosq_test_helper import * + +rc = 1 +mid = 2 +publish_packet = mosq_test.gen_publish("pub/qos1/test", qos=1, mid=mid, payload="message") +puback_packet = mosq_test.gen_puback(mid) + + +port = mosq_test.get_port() +broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port) + +try: + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.settimeout(5) + sock.connect(("localhost", port)) + sock.send(publish_packet) + data = sock.recv(1) + sock.close() + if len(data) == 0: + rc = 0 +except socket.error: + rc = 0 +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index 102a74740e..4336e50b87 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -18,6 +18,7 @@ ptest : test-compile test : test-compile 01 02 03 04 05 06 07 08 09 10 11 12 01 : + ./01-connect-bad-packet.py ./01-connect-duplicate.py ./01-connect-duplicate-v5.py ./01-connect-success.py diff --git a/test/broker/ptest.py b/test/broker/ptest.py index 41f690b252..4ae7cdca41 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -7,6 +7,7 @@ max_running = 10 tests = [ #(ports required, 'path'), + (1, './01-connect-bad-packet.py'), (1, './01-connect-duplicate.py'), (1, './01-connect-duplicate-v5.py'), (1, './01-connect-success.py'), From 7c3666d593ee8a45d3a0c6f2e02c4c75c850651c Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 20 Dec 2018 15:32:43 +0000 Subject: [PATCH 167/254] Subscription identifier support. --- client/client_props.c | 2 +- lib/actions.c | 4 +-- lib/connect.c | 2 +- lib/messages_mosq.c | 4 +-- lib/property_mosq.c | 8 +++--- lib/property_mosq.h | 2 +- lib/send_connect.c | 4 +-- lib/send_disconnect.c | 2 +- lib/send_mosq.c | 2 +- lib/send_mosq.h | 4 +-- lib/send_publish.c | 21 ++++++++++------ lib/send_subscribe.c | 2 +- lib/send_unsubscribe.c | 2 +- src/bridge.c | 4 ++- src/database.c | 20 ++++++++++----- src/handle_connack.c | 7 +++--- src/handle_publish.c | 4 +-- src/handle_subscribe.c | 20 ++++++++++++--- src/mosquitto_broker_internal.h | 10 +++++--- src/persist.c | 4 +-- src/send_connack.c | 7 +----- src/send_suback.c | 2 +- src/send_unsuback.c | 2 +- src/subs.c | 43 ++++++++++++++++++++------------- test/mosq_test.py | 1 - 25 files changed, 109 insertions(+), 74 deletions(-) diff --git a/client/client_props.c b/client/client_props.c index 71dcc2d4c1..7415bc06cf 100644 --- a/client/client_props.c +++ b/client/client_props.c @@ -123,7 +123,7 @@ int cfg_parse_property(struct mosq_config *cfg, int argc, char *argv[], int *idx break; case CMD_SUBSCRIBE: - if(identifier != MQTT_PROP_USER_PROPERTY){ + if(identifier != MQTT_PROP_SUBSCRIPTION_IDENTIFIER && identifier != MQTT_PROP_USER_PROPERTY){ fprintf(stderr, "Error: %s property not supported for %s in --property argument.\n\n", propname, cmdname); return MOSQ_ERR_NOT_SUPPORTED; } diff --git a/lib/actions.c b/lib/actions.c index 57a48d5491..7c0e8c27a6 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -93,7 +93,7 @@ int mosquitto_publish_v5(struct mosquitto *mosq, int *mid, const char *topic, in } if(qos == 0){ - return send__publish(mosq, local_mid, topic, payloadlen, payload, qos, retain, false, outgoing_properties); + return send__publish(mosq, local_mid, topic, payloadlen, payload, qos, retain, false, outgoing_properties, NULL); }else{ message = mosquitto__calloc(1, sizeof(struct mosquitto_message_all)); if(!message) return MOSQ_ERR_NOMEM; @@ -133,7 +133,7 @@ int mosquitto_publish_v5(struct mosquitto *mosq, int *mid, const char *topic, in message->state = mosq_ms_wait_for_pubrec; } pthread_mutex_unlock(&mosq->out_message_mutex); - return send__publish(mosq, message->msg.mid, message->msg.topic, message->msg.payloadlen, message->msg.payload, message->msg.qos, message->msg.retain, message->dup, outgoing_properties); + return send__publish(mosq, message->msg.mid, message->msg.topic, message->msg.payloadlen, message->msg.payload, message->msg.qos, message->msg.retain, message->dup, outgoing_properties, NULL); }else{ message->state = mosq_ms_invalid; pthread_mutex_unlock(&mosq->out_message_mutex); diff --git a/lib/connect.c b/lib/connect.c index ad3bb1d086..5beed13a2c 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -168,7 +168,7 @@ static int mosquitto__reconnect(struct mosquitto *mosq, bool blocking, const mos local_property.next = NULL; outgoing_properties = &local_property; } - rc = mosquitto_property_check_all(CMD_DISCONNECT, outgoing_properties); + rc = mosquitto_property_check_all(CMD_CONNECT, outgoing_properties); if(rc) return rc; } diff --git a/lib/messages_mosq.c b/lib/messages_mosq.c index 2a737d9b77..9d494788f6 100644 --- a/lib/messages_mosq.c +++ b/lib/messages_mosq.c @@ -264,7 +264,7 @@ int message__remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_dir }else if(cur->msg.qos == 2){ cur->state = mosq_ms_wait_for_pubrec; } - rc = send__publish(mosq, cur->msg.mid, cur->msg.topic, cur->msg.payloadlen, cur->msg.payload, cur->msg.qos, cur->msg.retain, cur->dup, NULL); + rc = send__publish(mosq, cur->msg.mid, cur->msg.topic, cur->msg.payloadlen, cur->msg.payload, cur->msg.qos, cur->msg.retain, cur->dup, NULL, NULL); if(rc){ pthread_mutex_unlock(&mosq->out_message_mutex); return rc; @@ -334,7 +334,7 @@ void message__retry_check_actual(struct mosquitto *mosq, struct mosquitto_messag case mosq_ms_publish_qos2: messages->timestamp = now; messages->dup = true; - send__publish(mosq, messages->msg.mid, messages->msg.topic, messages->msg.payloadlen, messages->msg.payload, messages->msg.qos, messages->msg.retain, messages->dup, NULL); + send__publish(mosq, messages->msg.mid, messages->msg.topic, messages->msg.payloadlen, messages->msg.payload, messages->msg.qos, messages->msg.retain, messages->dup, NULL, NULL); break; case mosq_ms_wait_for_pubrel: messages->timestamp = now; diff --git a/lib/property_mosq.c b/lib/property_mosq.c index c8dde7f1b5..e9399fd571 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -397,13 +397,15 @@ int property__write(struct mosquitto__packet *packet, const mosquitto_property * } -int property__write_all(struct mosquitto__packet *packet, const mosquitto_property *properties) +int property__write_all(struct mosquitto__packet *packet, const mosquitto_property *properties, bool write_len) { int rc; const mosquitto_property *p; - rc = packet__write_varint(packet, property__get_length_all(properties)); - if(rc) return rc; + if(write_len){ + rc = packet__write_varint(packet, property__get_length_all(properties)); + if(rc) return rc; + } p = properties; while(p){ diff --git a/lib/property_mosq.h b/lib/property_mosq.h index d31ce85e5e..d965d8a3e6 100644 --- a/lib/property_mosq.h +++ b/lib/property_mosq.h @@ -41,7 +41,7 @@ struct mqtt5__property { int property__read_all(int command, struct mosquitto__packet *packet, mosquitto_property **property); -int property__write_all(struct mosquitto__packet *packet, const mosquitto_property *property); +int property__write_all(struct mosquitto__packet *packet, const mosquitto_property *property, bool write_len); void property__free(mosquitto_property **property); int property__get_length(const mosquitto_property *property); diff --git a/lib/send_connect.c b/lib/send_connect.c index 5b50e2c7f3..99778634c4 100644 --- a/lib/send_connect.c +++ b/lib/send_connect.c @@ -141,7 +141,7 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session if(mosq->protocol == mosq_p_mqtt5){ /* Write properties */ - property__write_all(packet, properties); + property__write_all(packet, properties, true); } /* Payload */ @@ -153,7 +153,7 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session if(will){ if(mosq->protocol == mosq_p_mqtt5){ /* Write will properties */ - property__write_all(packet, mosq->will->properties); + property__write_all(packet, mosq->will->properties, true); } packet__write_string(packet, mosq->will->msg.topic, strlen(mosq->will->msg.topic)); packet__write_string(packet, (const char *)mosq->will->msg.payload, mosq->will->msg.payloadlen); diff --git a/lib/send_disconnect.c b/lib/send_disconnect.c index 120ef82fe4..c0959fbb6f 100644 --- a/lib/send_disconnect.c +++ b/lib/send_disconnect.c @@ -67,7 +67,7 @@ int send__disconnect(struct mosquitto *mosq, uint8_t reason_code, const mosquitt } if(mosq->protocol == mosq_p_mqtt5){ packet__write_byte(packet, reason_code); - property__write_all(packet, properties); + property__write_all(packet, properties, true); } return packet__queue(mosq, packet); diff --git a/lib/send_mosq.c b/lib/send_mosq.c index 3899589cd4..8b54b99610 100644 --- a/lib/send_mosq.c +++ b/lib/send_mosq.c @@ -144,7 +144,7 @@ int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid if(mosq->protocol == mosq_p_mqtt5){ packet__write_byte(packet, reason_code); - property__write_all(packet, properties); + property__write_all(packet, properties, true); } return packet__queue(mosq, packet); diff --git a/lib/send_mosq.h b/lib/send_mosq.h index c26615bed8..897f2eb82d 100644 --- a/lib/send_mosq.h +++ b/lib/send_mosq.h @@ -21,7 +21,7 @@ and the Eclipse Distribution License is available at int send__simple_command(struct mosquitto *mosq, uint8_t command); int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup, uint8_t reason_code, const mosquitto_property *properties); -int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const mosquitto_property *properties); +int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const mosquitto_property *cmsg_props, const mosquitto_property *store_props); int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session, const mosquitto_property *properties); int send__disconnect(struct mosquitto *mosq, uint8_t reason_code, const mosquitto_property *properties); @@ -29,7 +29,7 @@ int send__pingreq(struct mosquitto *mosq); int send__pingresp(struct mosquitto *mosq); int send__puback(struct mosquitto *mosq, uint16_t mid); int send__pubcomp(struct mosquitto *mosq, uint16_t mid); -int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const mosquitto_property *properties); +int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const mosquitto_property *cmsg_props, const mosquitto_property *store_props); int send__pubrec(struct mosquitto *mosq, uint16_t mid); int send__pubrel(struct mosquitto *mosq, uint16_t mid); int send__subscribe(struct mosquitto *mosq, int *mid, int topic_count, char *const *const topic, int topic_qos, const mosquitto_property *properties); diff --git a/lib/send_publish.c b/lib/send_publish.c index ee25d3b499..c1d81e0e0f 100644 --- a/lib/send_publish.c +++ b/lib/send_publish.c @@ -37,7 +37,7 @@ and the Eclipse Distribution License is available at #include "send_mosq.h" -int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const mosquitto_property *properties) +int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const mosquitto_property *cmsg_props, const mosquitto_property *store_props) { #ifdef WITH_BROKER size_t len; @@ -110,7 +110,7 @@ int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint3 } log__printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBLISH to %s (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes))", mosq->id, dup, qos, retain, mid, mapped_topic, (long)payloadlen); G_PUB_BYTES_SENT_INC(payloadlen); - rc = send__real_publish(mosq, mid, mapped_topic, payloadlen, payload, qos, retain, dup, properties); + rc = send__real_publish(mosq, mid, mapped_topic, payloadlen, payload, qos, retain, dup, cmsg_props, store_props); mosquitto__free(mapped_topic); return rc; } @@ -124,15 +124,15 @@ int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint3 log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBLISH (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes))", mosq->id, dup, qos, retain, mid, topic, (long)payloadlen); #endif - return send__real_publish(mosq, mid, topic, payloadlen, payload, qos, retain, dup, properties); + return send__real_publish(mosq, mid, topic, payloadlen, payload, qos, retain, dup, cmsg_props, store_props); } -int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const mosquitto_property *properties) +int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const mosquitto_property *cmsg_props, const mosquitto_property *store_props) { struct mosquitto__packet *packet = NULL; int packetlen; - int proplen, varbytes; + int proplen = 0, varbytes; int rc; assert(mosq); @@ -144,11 +144,14 @@ int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, } if(qos > 0) packetlen += 2; /* For message id */ if(mosq->protocol == mosq_p_mqtt5){ - proplen = property__get_length_all(properties); + proplen = 0; + proplen += property__get_length_all(cmsg_props); + proplen += property__get_length_all(store_props); varbytes = packet__varint_bytes(proplen); if(varbytes > 4){ /* FIXME - Properties too big, don't publish any - should remove some first really */ - properties = NULL; + cmsg_props = NULL; + store_props = NULL; }else{ packetlen += proplen + varbytes; } @@ -175,7 +178,9 @@ int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, } if(mosq->protocol == mosq_p_mqtt5){ - property__write_all(packet, properties); + packet__write_varint(packet, proplen); + property__write_all(packet, cmsg_props, false); + property__write_all(packet, store_props, false); } /* Payload */ diff --git a/lib/send_subscribe.c b/lib/send_subscribe.c index ffe7ef7d68..4095e4aff2 100644 --- a/lib/send_subscribe.c +++ b/lib/send_subscribe.c @@ -72,7 +72,7 @@ int send__subscribe(struct mosquitto *mosq, int *mid, int topic_count, const cha packet__write_uint16(packet, local_mid); if(mosq->protocol == mosq_p_mqtt5){ - property__write_all(packet, properties); + property__write_all(packet, properties, true); } /* Payload */ diff --git a/lib/send_unsubscribe.c b/lib/send_unsubscribe.c index a3e75251bd..6e0623df1e 100644 --- a/lib/send_unsubscribe.c +++ b/lib/send_unsubscribe.c @@ -70,7 +70,7 @@ int send__unsubscribe(struct mosquitto *mosq, int *mid, const char *topic, const if(mosq->protocol == mosq_p_mqtt5){ /* We don't use User Property yet. */ - property__write_all(packet, properties); + property__write_all(packet, properties, true); } /* Payload */ diff --git a/src/bridge.c b/src/bridge.c index 365658e602..46dbf51cf1 100644 --- a/src/bridge.c +++ b/src/bridge.c @@ -149,6 +149,7 @@ int bridge__connect_step1(struct mosquitto_db *db, struct mosquitto *context) context, context->bridge->topics[i].local_topic, context->bridge->topics[i].qos, + 0, MQTT_SUB_OPT_NO_LOCAL | MQTT_SUB_OPT_RETAIN_AS_PUBLISHED, &db->subs) > 0){ return 1; @@ -322,6 +323,7 @@ int bridge__connect(struct mosquitto_db *db, struct mosquitto *context) context, context->bridge->topics[i].local_topic, context->bridge->topics[i].qos, + 0, MQTT_SUB_OPT_NO_LOCAL | MQTT_SUB_OPT_RETAIN_AS_PUBLISHED, &db->subs) > 0){ @@ -329,7 +331,7 @@ int bridge__connect(struct mosquitto_db *db, struct mosquitto *context) } sub__retain_queue(db, context, context->bridge->topics[i].local_topic, - context->bridge->topics[i].qos); + context->bridge->topics[i].qos, 0); } } diff --git a/src/database.c b/src/database.c index eb5547f7b2..666c58efe1 100644 --- a/src/database.c +++ b/src/database.c @@ -336,7 +336,7 @@ int db__message_delete(struct mosquitto_db *db, struct mosquitto *context, uint1 return MOSQ_ERR_SUCCESS; } -int db__message_insert(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, int qos, bool retain, struct mosquitto_msg_store *stored) +int db__message_insert(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, int qos, bool retain, struct mosquitto_msg_store *stored, mosquitto_property *properties) { struct mosquitto_client_msg *msg; struct mosquitto_client_msg **msgs, **last_msg; @@ -362,6 +362,7 @@ int db__message_insert(struct mosquitto_db *db, struct mosquitto *context, uint1 for(i=0; idest_id_count; i++){ if(!strcmp(stored->dest_ids[i], context->id)){ /* We have already sent this message to this client. */ + mosquitto_property_free_all(&properties); return MOSQ_ERR_SUCCESS; } } @@ -370,9 +371,11 @@ int db__message_insert(struct mosquitto_db *db, struct mosquitto *context, uint1 /* Client is not connected only queue messages with QoS>0. */ if(qos == 0 && !db->config->queue_qos0_messages){ if(!context->bridge){ + mosquitto_property_free_all(&properties); return 2; }else{ if(context->bridge->start_type != bst_lazy){ + mosquitto_property_free_all(&properties); return 2; } } @@ -397,6 +400,7 @@ int db__message_insert(struct mosquitto_db *db, struct mosquitto *context, uint1 if(qos == 2){ state = mosq_ms_wait_for_pubrel; }else{ + mosquitto_property_free_all(&properties); return 1; } } @@ -412,6 +416,7 @@ int db__message_insert(struct mosquitto_db *db, struct mosquitto *context, uint1 context->id); } G_MSGS_DROPPED_INC(); + mosquitto_property_free_all(&properties); return 2; } }else{ @@ -425,6 +430,7 @@ int db__message_insert(struct mosquitto_db *db, struct mosquitto *context, uint1 "Outgoing messages are being dropped for client %s.", context->id); } + mosquitto_property_free_all(&properties); return 2; } } @@ -448,6 +454,7 @@ int db__message_insert(struct mosquitto_db *db, struct mosquitto *context, uint1 msg->dup = false; msg->qos = qos; msg->retain = retain; + msg->properties = properties; if (state == mosq_ms_queued){ msgs = &(context->queued_msgs); @@ -875,7 +882,7 @@ int db__message_write(struct mosquitto_db *db, struct mosquitto *context) uint32_t payloadlen; const void *payload; int msg_count = 0; - mosquitto_property *properties; + mosquitto_property *cmsg_props = NULL, *store_props = NULL; time_t now; if(!context || context->sock == INVALID_SOCKET @@ -903,11 +910,12 @@ int db__message_write(struct mosquitto_db *db, struct mosquitto *context) qos = tail->qos; payloadlen = tail->store->payloadlen; payload = UHPA_ACCESS_PAYLOAD(tail->store); - properties = tail->store->properties; + cmsg_props = tail->properties; + store_props = tail->store->properties; switch(tail->state){ case mosq_ms_publish_qos0: - rc = send__publish(context, mid, topic, payloadlen, payload, qos, retain, retries, properties); + rc = send__publish(context, mid, topic, payloadlen, payload, qos, retain, retries, cmsg_props, store_props); if(!rc){ db__message_remove(db, context, &tail, last); }else{ @@ -916,7 +924,7 @@ int db__message_write(struct mosquitto_db *db, struct mosquitto *context) break; case mosq_ms_publish_qos1: - rc = send__publish(context, mid, topic, payloadlen, payload, qos, retain, retries, properties); + rc = send__publish(context, mid, topic, payloadlen, payload, qos, retain, retries, cmsg_props, store_props); if(!rc){ tail->timestamp = mosquitto_time(); tail->dup = 1; /* Any retry attempts are a duplicate. */ @@ -929,7 +937,7 @@ int db__message_write(struct mosquitto_db *db, struct mosquitto *context) break; case mosq_ms_publish_qos2: - rc = send__publish(context, mid, topic, payloadlen, payload, qos, retain, retries, properties); + rc = send__publish(context, mid, topic, payloadlen, payload, qos, retain, retries, cmsg_props, store_props); if(!rc){ tail->timestamp = mosquitto_time(); tail->dup = 1; /* Any retry attempts are a duplicate. */ diff --git a/src/handle_connack.c b/src/handle_connack.c index bc6e37a879..9ef568123c 100644 --- a/src/handle_connack.c +++ b/src/handle_connack.c @@ -59,7 +59,7 @@ int handle__connack(struct mosquitto_db *db, struct mosquitto *context) if(context->bridge->notification_topic){ if(!context->bridge->notifications_local_only){ if(send__real_publish(context, mosquitto__mid_generate(context), - context->bridge->notification_topic, 1, ¬ification_payload, 1, true, 0, NULL)){ + context->bridge->notification_topic, 1, ¬ification_payload, 1, true, 0, NULL, NULL)){ return 1; } @@ -74,7 +74,7 @@ int handle__connack(struct mosquitto_db *db, struct mosquitto *context) notification_payload = '1'; if(!context->bridge->notifications_local_only){ if(send__real_publish(context, mosquitto__mid_generate(context), - notification_topic, 1, ¬ification_payload, 1, true, 0, NULL)){ + notification_topic, 1, ¬ification_payload, 1, true, 0, NULL, NULL)){ mosquitto__free(notification_topic); return 1; @@ -107,11 +107,12 @@ int handle__connack(struct mosquitto_db *db, struct mosquitto *context) context, context->bridge->topics[i].local_topic, context->bridge->topics[i].qos, + 0, MQTT_SUB_OPT_NO_LOCAL | MQTT_SUB_OPT_RETAIN_AS_PUBLISHED, &db->subs)) return 1; sub__retain_queue(db, context, context->bridge->topics[i].local_topic, - context->bridge->topics[i].qos); + context->bridge->topics[i].qos, 0); } } } diff --git a/src/handle_publish.c b/src/handle_publish.c index f328a77e9b..3b02c1af73 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -279,7 +279,7 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) break; case 2: if(!dup){ - res = db__message_insert(db, context, mid, mosq_md_in, qos, retain, stored); + res = db__message_insert(db, context, mid, mosq_md_in, qos, retain, stored, NULL); }else{ res = 0; } @@ -308,7 +308,7 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) if(db__message_store(db, context->id, mid, NULL, qos, 0, NULL, false, &stored, 0, NULL, 0)){ return 1; } - res = db__message_insert(db, context, mid, mosq_md_in, qos, false, stored); + res = db__message_insert(db, context, mid, mosq_md_in, qos, false, stored, NULL); }else{ res = 0; } diff --git a/src/handle_subscribe.c b/src/handle_subscribe.c index 4d59da6f0d..1f8412f785 100644 --- a/src/handle_subscribe.c +++ b/src/handle_subscribe.c @@ -34,6 +34,7 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) uint16_t mid; char *sub; uint8_t subscription_options; + uint32_t subscription_identifier = 0; uint8_t qos; uint8_t retain_handling = 0; uint8_t *payload = NULL, *tmp_payload; @@ -57,9 +58,20 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) if(context->protocol == mosq_p_mqtt5){ rc = property__read_all(CMD_SUBSCRIBE, &context->in_packet, &properties); if(rc) return rc; + + if(mosquitto_property_read_varint(properties, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, + &subscription_identifier, false)){ + + /* If the identifier was force set to 0, this is an error */ + if(subscription_identifier == 0){ + mosquitto_property_free_all(&properties); + return MOSQ_ERR_PROTOCOL; + } + } + mosquitto_property_free_all(&properties); + /* Note - User Property not handled */ } - mosquitto_property_free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ while(context->in_packet.pos < context->in_packet.remaining_length){ sub = NULL; @@ -147,20 +159,20 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) } if(qos != 0x80){ - rc2 = sub__add(db, context, sub, qos, subscription_options, &db->subs); + rc2 = sub__add(db, context, sub, qos, subscription_identifier, subscription_options, &db->subs); if(rc2 > 0){ mosquitto__free(sub); return rc2; } if(context->protocol == mosq_p_mqtt311 || context->protocol == mosq_p_mqtt31){ if(rc2 == MOSQ_ERR_SUCCESS || rc2 == MOSQ_ERR_SUB_EXISTS){ - if(sub__retain_queue(db, context, sub, qos)) rc = 1; + if(sub__retain_queue(db, context, sub, qos, 0)) rc = 1; } }else{ if((retain_handling == MQTT_SUB_OPT_SEND_RETAIN_ALWAYS) || (rc2 == MOSQ_ERR_SUCCESS && retain_handling == MQTT_SUB_OPT_SEND_RETAIN_NEW)){ - if(sub__retain_queue(db, context, sub, qos)) rc = 1; + if(sub__retain_queue(db, context, sub, qos, subscription_identifier)) rc = 1; } } diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index 9cf0246e6d..cd5eddb8e2 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -290,7 +290,8 @@ struct mosquitto__subleaf { struct mosquitto__subleaf *prev; struct mosquitto__subleaf *next; struct mosquitto *context; - int qos; + uint32_t identifier; + uint8_t qos; bool no_local; bool retain_as_published; }; @@ -333,6 +334,7 @@ struct mosquitto_msg_store{ struct mosquitto_client_msg{ struct mosquitto_client_msg *next; struct mosquitto_msg_store *store; + mosquitto_property *properties; time_t timestamp; uint16_t mid; uint8_t qos; @@ -554,7 +556,7 @@ void db__limits_set(int inflight, unsigned long inflight_bytes, int queued, unsi /* Return the number of in-flight messages in count. */ int db__message_count(int *count); int db__message_delete(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir); -int db__message_insert(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, int qos, bool retain, struct mosquitto_msg_store *stored); +int db__message_insert(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, int qos, bool retain, struct mosquitto_msg_store *stored, mosquitto_property *properties); int db__message_release(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir); int db__message_update(struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, enum mosquitto_msg_state state); int db__message_write(struct mosquitto_db *db, struct mosquitto *context); @@ -575,12 +577,12 @@ void sys_tree__update(struct mosquitto_db *db, int interval, time_t start_time); /* ============================================================ * Subscription functions * ============================================================ */ -int sub__add(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int qos, int options, struct mosquitto__subhier **root); +int sub__add(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int qos, uint32_t identifier, int options, struct mosquitto__subhier **root); struct mosquitto__subhier *sub__add_hier_entry(struct mosquitto__subhier *parent, struct mosquitto__subhier **sibling, const char *topic, size_t len); int sub__remove(struct mosquitto_db *db, struct mosquitto *context, const char *sub, struct mosquitto__subhier *root); void sub__tree_print(struct mosquitto__subhier *root, int level); int sub__clean_session(struct mosquitto_db *db, struct mosquitto *context); -int sub__retain_queue(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int sub_qos); +int sub__retain_queue(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int sub_qos, uint32_t subscription_identifier); int sub__messages_queue(struct mosquitto_db *db, const char *source_id, const char *topic, int qos, int retain, struct mosquitto_msg_store **stored); /* ============================================================ diff --git a/src/persist.c b/src/persist.c index b8b3e4b86b..a48028a7e0 100644 --- a/src/persist.c +++ b/src/persist.c @@ -935,8 +935,8 @@ static int persist__restore_sub(struct mosquitto_db *db, const char *client_id, context = persist__find_or_add_context(db, client_id, 0); if(!context) return 1; - /* FIXME - retain_as_published needs saving */ - return sub__add(db, context, sub, qos, false, &db->subs); + /* FIXME - identifer, options need saving */ + return sub__add(db, context, sub, qos, 0, 0, &db->subs); } #endif diff --git a/src/send_connack.c b/src/send_connack.c index 1c20820c34..d51179b0ee 100644 --- a/src/send_connack.c +++ b/src/send_connack.c @@ -62,11 +62,6 @@ int send__connack(struct mosquitto_db *db, struct mosquitto *context, int ack, i mosquitto__free(packet); return rc; } - rc = mosquitto_property_add_byte(&connack_props, MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE, 0); - if(rc){ - mosquitto__free(packet); - return rc; - } proplen = property__get_length_all(connack_props); varbytes = packet__varint_bytes(proplen); @@ -80,7 +75,7 @@ int send__connack(struct mosquitto_db *db, struct mosquitto *context, int ack, i packet__write_byte(packet, ack); packet__write_byte(packet, reason_code); if(context->protocol == mosq_p_mqtt5){ - property__write_all(packet, connack_props); + property__write_all(packet, connack_props, true); } mosquitto_property_free_all(&connack_props); diff --git a/src/send_suback.c b/src/send_suback.c index 49daeebce9..98c13bc781 100644 --- a/src/send_suback.c +++ b/src/send_suback.c @@ -52,7 +52,7 @@ int send__suback(struct mosquitto *context, uint16_t mid, uint32_t payloadlen, c if(context->protocol == mosq_p_mqtt5){ /* We don't use Reason String or User Property yet. */ - property__write_all(packet, properties); + property__write_all(packet, properties, true); } if(payloadlen){ diff --git a/src/send_unsuback.c b/src/send_unsuback.c index 59fc50a373..ee0c833395 100644 --- a/src/send_unsuback.c +++ b/src/send_unsuback.c @@ -53,7 +53,7 @@ int send__unsuback(struct mosquitto *mosq, uint16_t mid, const mosquitto_propert packet__write_uint16(packet, mid); if(mosq->protocol == mosq_p_mqtt5){ - property__write_all(packet, properties); + property__write_all(packet, properties, true); } return packet__queue(mosq, packet); diff --git a/src/subs.c b/src/subs.c index acc8714a07..04bb2231fe 100644 --- a/src/subs.c +++ b/src/subs.c @@ -70,6 +70,7 @@ static int subs__process(struct mosquitto_db *db, struct mosquitto__subhier *hie uint16_t mid; struct mosquitto__subleaf *leaf; bool client_retain; + mosquitto_property *properties = NULL; leaf = hier->subs; @@ -129,7 +130,10 @@ static int subs__process(struct mosquitto_db *db, struct mosquitto__subhier *hie }else{ client_retain = false; } - if(db__message_insert(db, leaf->context, mid, mosq_md_out, msg_qos, client_retain, stored) == 1) rc = 1; + if(leaf->identifier){ + mosquitto_property_add_varint(&properties, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, leaf->identifier); + } + if(db__message_insert(db, leaf->context, mid, mosq_md_out, msg_qos, client_retain, stored, properties) == 1) rc = 1; }else{ return 1; /* Application error */ } @@ -241,7 +245,7 @@ static void sub__topic_tokens_free(struct sub__token *tokens) } } -static int sub__add_recurse(struct mosquitto_db *db, struct mosquitto *context, int qos, int options, struct mosquitto__subhier *subhier, struct sub__token *tokens) +static int sub__add_recurse(struct mosquitto_db *db, struct mosquitto *context, int qos, uint32_t identifier, int options, struct mosquitto__subhier *subhier, struct sub__token *tokens) /* FIXME - this function has the potential to leak subhier, audit calling functions. */ { struct mosquitto__subhier *branch; @@ -275,6 +279,7 @@ static int sub__add_recurse(struct mosquitto_db *db, struct mosquitto *context, leaf->next = NULL; leaf->context = context; leaf->qos = qos; + leaf->identifier = identifier; leaf->no_local = ((options & MQTT_SUB_OPT_NO_LOCAL) != 0); leaf->retain_as_published = ((options & MQTT_SUB_OPT_RETAIN_AS_PUBLISHED) != 0); for(i=0; isub_count; i++){ @@ -309,13 +314,13 @@ static int sub__add_recurse(struct mosquitto_db *db, struct mosquitto *context, HASH_FIND(hh, subhier->children, UHPA_ACCESS_TOPIC(tokens), tokens->topic_len, branch); if(branch){ - return sub__add_recurse(db, context, qos, options, branch, tokens->next); + return sub__add_recurse(db, context, qos, identifier, options, branch, tokens->next); }else{ /* Not found */ branch = sub__add_hier_entry(subhier, &subhier->children, UHPA_ACCESS_TOPIC(tokens), tokens->topic_len); if(!branch) return MOSQ_ERR_NOMEM; - return sub__add_recurse(db, context, qos, options, branch, tokens->next); + return sub__add_recurse(db, context, qos, identifier, options, branch, tokens->next); } } @@ -444,7 +449,7 @@ struct mosquitto__subhier *sub__add_hier_entry(struct mosquitto__subhier *parent } -int sub__add(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int qos, int options, struct mosquitto__subhier **root) +int sub__add(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int qos, uint32_t identifier, int options, struct mosquitto__subhier **root) { int rc = 0; struct mosquitto__subhier *subhier; @@ -466,7 +471,7 @@ int sub__add(struct mosquitto_db *db, struct mosquitto *context, const char *sub } } - rc = sub__add_recurse(db, context, qos, options, subhier, tokens); + rc = sub__add_recurse(db, context, qos, identifier, options, subhier, tokens); sub__topic_tokens_free(tokens); @@ -517,7 +522,7 @@ int sub__messages_queue(struct mosquitto_db *db, const char *source_id, const ch /* We have a message that needs to be retained, so ensure that the subscription * tree for its topic exists. */ - sub__add_recurse(db, NULL, 0, false, subhier, tokens); + sub__add_recurse(db, NULL, 0, 0, 0, subhier, tokens); } sub__search(db, subhier, tokens, source_id, topic, qos, retain, *stored, true); } @@ -641,11 +646,12 @@ void sub__tree_print(struct mosquitto__subhier *root, int level) } } -static int retain__process(struct mosquitto_db *db, struct mosquitto_msg_store *retained, struct mosquitto *context, const char *sub, int sub_qos) +static int retain__process(struct mosquitto_db *db, struct mosquitto_msg_store *retained, struct mosquitto *context, const char *sub, int sub_qos, uint32_t subscription_identifier) { int rc = 0; int qos; uint16_t mid; + mosquitto_property *properties = NULL; rc = mosquitto_acl_check(db, context, retained->topic, retained->payloadlen, UHPA_ACCESS(retained->payload, retained->payloadlen), retained->qos, retained->retain, MOSQ_ACL_READ); @@ -666,10 +672,13 @@ static int retain__process(struct mosquitto_db *db, struct mosquitto_msg_store * }else{ mid = 0; } - return db__message_insert(db, context, mid, mosq_md_out, qos, true, retained); + if(subscription_identifier > 0){ + mosquitto_property_add_varint(&properties, MQTT_PROP_SUBSCRIPTION_IDENTIFIER, subscription_identifier); + } + return db__message_insert(db, context, mid, mosq_md_out, qos, true, retained, properties); } -static int retain__search(struct mosquitto_db *db, struct mosquitto__subhier *subhier, struct sub__token *tokens, struct mosquitto *context, const char *sub, int sub_qos, int level) +static int retain__search(struct mosquitto_db *db, struct mosquitto__subhier *subhier, struct sub__token *tokens, struct mosquitto *context, const char *sub, int sub_qos, uint32_t subscription_identifier, int level) { struct mosquitto__subhier *branch, *branch_tmp; int flag = 0; @@ -685,25 +694,25 @@ static int retain__search(struct mosquitto_db *db, struct mosquitto__subhier *su */ flag = -1; if(branch->retained){ - retain__process(db, branch->retained, context, sub, sub_qos); + retain__process(db, branch->retained, context, sub, sub_qos, subscription_identifier); } if(branch->children){ - retain__search(db, branch, tokens, context, sub, sub_qos, level+1); + retain__search(db, branch, tokens, context, sub, sub_qos, subscription_identifier, level+1); } }else if(strcmp(UHPA_ACCESS_TOPIC(branch), "+") && (!strcmp(UHPA_ACCESS_TOPIC(branch), UHPA_ACCESS_TOPIC(tokens)) || !strcmp(UHPA_ACCESS_TOPIC(tokens), "+"))){ if(tokens->next){ - if(retain__search(db, branch, tokens->next, context, sub, sub_qos, level+1) == -1 + if(retain__search(db, branch, tokens->next, context, sub, sub_qos, subscription_identifier, level+1) == -1 || (!branch_tmp && tokens->next && !strcmp(UHPA_ACCESS_TOPIC(tokens->next), "#") && level>0)){ if(branch->retained){ - retain__process(db, branch->retained, context, sub, sub_qos); + retain__process(db, branch->retained, context, sub, sub_qos, subscription_identifier); } } }else{ if(branch->retained){ - retain__process(db, branch->retained, context, sub, sub_qos); + retain__process(db, branch->retained, context, sub, sub_qos, subscription_identifier); } } } @@ -711,7 +720,7 @@ static int retain__search(struct mosquitto_db *db, struct mosquitto__subhier *su return flag; } -int sub__retain_queue(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int sub_qos) +int sub__retain_queue(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int sub_qos, uint32_t subscription_identifier) { struct mosquitto__subhier *subhier; struct sub__token *tokens = NULL, *tail; @@ -725,7 +734,7 @@ int sub__retain_queue(struct mosquitto_db *db, struct mosquitto *context, const HASH_FIND(hh, db->subs, UHPA_ACCESS_TOPIC(tokens), tokens->topic_len, subhier); if(subhier){ - retain__search(db, subhier, tokens, context, sub, sub_qos, 0); + retain__search(db, subhier, tokens, context, sub, sub_qos, subscription_identifier, 0); } while(tokens){ tail = tokens->next; diff --git a/test/mosq_test.py b/test/mosq_test.py index 8d29d1a560..a2db51fd38 100644 --- a/test/mosq_test.py +++ b/test/mosq_test.py @@ -368,7 +368,6 @@ def gen_connect(client_id, clean_session=True, keepalive=60, username=None, pass def gen_connack(resv=0, rc=0, proto_ver=4, properties=""): if proto_ver == 5: properties += mqtt5_props.gen_byte_prop(mqtt5_props.PROP_SHARED_SUB_AVAILABLE, 0) - properties += mqtt5_props.gen_byte_prop(mqtt5_props.PROP_SUBSCRIPTION_ID_AVAILABLE, 0) properties = mqtt5_props.prop_finalise(properties) packet = struct.pack('!BBBB', 32, 2+len(properties), resv, rc) + properties From 19fbbd872638904d6900ea4390e5e97e05e1bd11 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 20 Dec 2018 18:45:01 +0000 Subject: [PATCH 168/254] Update details of CVE-2018-20145. --- ChangeLog.txt | 1 + www/pages/security.md | 3 ++- www/posts/2018/12/version-155-released.md | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index d7682e4069..ba8864db75 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -5,6 +5,7 @@ Security: - If `per_listener_settings` is set to true, then the `acl_file` setting was ignored for the "default listener" only. This has been fixed. This does not affect any listeners defined with the `listener` option. Closes #1073. + This is now tracked as CVE-2018-20145. Broker: - Add `socket_domain` option to allow listeners to disable IPv6 support. diff --git a/www/pages/security.md b/www/pages/security.md index 43618a25a3..b8abf73dfa 100644 --- a/www/pages/security.md +++ b/www/pages/security.md @@ -19,7 +19,7 @@ follow the steps on [Eclipse Security] page to report it. Listed with most recent first. Further information on security related issues can be found in the [security category]. -* December 2018: No CVE assigned. Affecting versions **1.5** to **1.5.4** +* December 2018: [CVE-2018-20145]. Affecting versions **1.5** to **1.5.4** inclusive, fixed in **1.5.5.**. More details at [version-155-released]. * November 2018: No CVE assigned. Affecting versions **1.4** to **1.5.3** inclusive, fixed in **1.5.4**. More details at [version-154-released]. @@ -55,6 +55,7 @@ can be found in the [security category]. [Eclipse Security]: https://www.eclipse.org/security/ [security category]: /blog/categories/security/ +[CVE-2018-20145]: https://nvd.nist.gov/vuln/detail/CVE-2018-20145 [CVE-2018-12543]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-12543 [CVE-2017-9868]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-9868 [CVE-2017-7655]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7652 diff --git a/www/posts/2018/12/version-155-released.md b/www/posts/2018/12/version-155-released.md index ca01171581..b2d5f96e91 100644 --- a/www/posts/2018/12/version-155-released.md +++ b/www/posts/2018/12/version-155-released.md @@ -17,6 +17,7 @@ This is a bugfix and security release. - If `per_listener_settings` is set to true, then the `acl_file` setting was ignored for the "default listener" only. This has been fixed. This does not affect any listeners defined with the `listener` option. Closes [#1073]. + This is now tracked as [CVE-2018-20145]. ## Broker - Add `socket_domain` option to allow listeners to disable IPv6 support. @@ -46,6 +47,7 @@ This is a bugfix and security release. - Fix building where TLS-PSK is not available. Closes [#68]. +[CVE-2018-20145]: https://nvd.nist.gov/vuln/detail/CVE-2018-20145 [#68]: https://github.com/eclipse/mosquitto/issues/68 [#537]: https://github.com/eclipse/mosquitto/issues/537 [#613]: https://github.com/eclipse/mosquitto/issues/613 From c1baf211859efe1d8648d5e933510e34ce7ec26b Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sun, 23 Dec 2018 21:39:15 +0000 Subject: [PATCH 169/254] Add tests for subscription identifiers. --- test/broker/02-subpub-qos0-subscription-id.py | 68 +++++++++++++++++++ test/broker/Makefile | 1 + test/broker/ptest.py | 1 + test/mosq_test.py | 10 ++- test/mqtt5_props.py | 4 ++ 5 files changed, 81 insertions(+), 3 deletions(-) create mode 100755 test/broker/02-subpub-qos0-subscription-id.py diff --git a/test/broker/02-subpub-qos0-subscription-id.py b/test/broker/02-subpub-qos0-subscription-id.py new file mode 100755 index 0000000000..4841af7589 --- /dev/null +++ b/test/broker/02-subpub-qos0-subscription-id.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python + +# Do subscription identifiers work as expected? +# MQTT v5 + +from mosq_test_helper import * + +rc = 1 +keepalive = 60 +connect_packet = mosq_test.gen_connect("subpub-test", keepalive=keepalive, proto_ver=5) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +mid = 1 +props = mqtt5_props.gen_varint_prop(mqtt5_props.PROP_SUBSCRIPTION_IDENTIFIER, 1) +props = mqtt5_props.prop_finalise(props) +subscribe1_packet = mosq_test.gen_subscribe(mid, "subpub/id1", 0, proto_ver=5, properties=props) +suback1_packet = mosq_test.gen_suback(mid, 0, proto_ver=5) + +mid = 2 +props = mqtt5_props.gen_varint_prop(mqtt5_props.PROP_SUBSCRIPTION_IDENTIFIER, 14) +props = mqtt5_props.prop_finalise(props) +subscribe2_packet = mosq_test.gen_subscribe(mid, "subpub/+/id2", 0, proto_ver=5, properties=props) +suback2_packet = mosq_test.gen_suback(mid, 0, proto_ver=5) + +mid = 3 +subscribe3_packet = mosq_test.gen_subscribe(mid, "subpub/noid", 0, proto_ver=5) +suback3_packet = mosq_test.gen_suback(mid, 0, proto_ver=5) + +publish1_packet = mosq_test.gen_publish("subpub/id1", qos=0, payload="message1", proto_ver=5) + +props = mqtt5_props.gen_varint_prop(mqtt5_props.PROP_SUBSCRIPTION_IDENTIFIER, 1) +props = mqtt5_props.prop_finalise(props) +publish1r_packet = mosq_test.gen_publish("subpub/id1", qos=0, payload="message1", proto_ver=5, properties=props) + +publish2_packet = mosq_test.gen_publish("subpub/test/id2", qos=0, payload="message2", proto_ver=5) +props = mqtt5_props.gen_varint_prop(mqtt5_props.PROP_SUBSCRIPTION_IDENTIFIER, 14) +props = mqtt5_props.prop_finalise(props) +publish2r_packet = mosq_test.gen_publish("subpub/test/id2", qos=0, payload="message2", proto_ver=5, properties=props) + +publish3_packet = mosq_test.gen_publish("subpub/noid", qos=0, payload="message3", proto_ver=5) + + +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) + + mosq_test.do_send_receive(sock, subscribe1_packet, suback1_packet, "suback1") + mosq_test.do_send_receive(sock, subscribe2_packet, suback2_packet, "suback2") + mosq_test.do_send_receive(sock, subscribe3_packet, suback3_packet, "suback3") + + mosq_test.do_send_receive(sock, publish3_packet, publish3_packet, "publish3") + mosq_test.do_send_receive(sock, publish2_packet, publish2r_packet, "publish2") + mosq_test.do_send_receive(sock, publish1_packet, publish1r_packet, "publish1") + + rc = 0 + + sock.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index 4336e50b87..fa77f88e70 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -55,6 +55,7 @@ endif ./02-subpub-qos1-nolocal.py ./02-subpub-qos0-retain-as-publish.py ./02-subpub-qos0-send-retain.py + ./02-subpub-qos0-subscription-id.py ./02-unsubscribe-qos0.py ./02-unsubscribe-qos1.py ./02-unsubscribe-qos2.py diff --git a/test/broker/ptest.py b/test/broker/ptest.py index 4ae7cdca41..494eda3911 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -38,6 +38,7 @@ (1, './02-subpub-qos1-nolocal.py'), (1, './02-subpub-qos0-retain-as-publish.py'), (1, './02-subpub-qos0-send-retain.py'), + (1, './02-subpub-qos0-subscription-id.py'), (1, './02-unsubscribe-qos0.py'), (1, './02-unsubscribe-qos1.py'), (1, './02-unsubscribe-qos2.py'), diff --git a/test/mosq_test.py b/test/mosq_test.py index a2db51fd38..abea7af509 100644 --- a/test/mosq_test.py +++ b/test/mosq_test.py @@ -438,10 +438,14 @@ def gen_pubrel(mid, dup=False, proto_ver=4, reason_code=0): def gen_pubcomp(mid, proto_ver=4, reason_code=0): return _gen_command_with_mid(112, mid, proto_ver, reason_code) -def gen_subscribe(mid, topic, qos, proto_ver=4): +def gen_subscribe(mid, topic, qos, proto_ver=4, properties=""): if proto_ver == 5: - pack_format = "!BBHBH"+str(len(topic))+"sB" - return struct.pack(pack_format, 130, 2+1+2+len(topic)+1, mid, 0, len(topic), topic, qos) + if properties == "": + pack_format = "!BBHBH"+str(len(topic))+"sB" + return struct.pack(pack_format, 130, 2+1+2+len(topic)+1, mid, 0, len(topic), topic, qos) + else: + pack_format = "!BBH"+str(len(properties))+"s"+"H"+str(len(topic))+"sB" + return struct.pack(pack_format, 130, 2+1+2+len(topic)+len(properties), mid, properties, len(topic), topic, qos) else: pack_format = "!BBHH"+str(len(topic))+"sB" return struct.pack(pack_format, 130, 2+2+len(topic)+1, mid, len(topic), topic, qos) diff --git a/test/mqtt5_props.py b/test/mqtt5_props.py index bdd5b1b31e..9f30732450 100644 --- a/test/mqtt5_props.py +++ b/test/mqtt5_props.py @@ -48,6 +48,10 @@ def gen_string_pair_prop(identifier, s1, s2): prop = struct.pack('!BH%dsH%ds'%(len(s1), len(s2)), identifier, len(s1), s1, len(s2), s2) return prop +def gen_varint_prop(identifier, val): + v = pack_varint(val) + return struct.pack("!B"+str(len(v))+"s", identifier, v) + def pack_varint(varint): s = "" while True: From 659cd2a3b15961cb55d64fd176368b436b4613ea Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sun, 23 Dec 2018 21:49:39 +0000 Subject: [PATCH 170/254] Read reason code for PUBREC/PUBREL. --- lib/handle_pubackcomp.c | 4 ++++ lib/handle_pubrec.c | 4 ++++ lib/handle_pubrel.c | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/lib/handle_pubackcomp.c b/lib/handle_pubackcomp.c index 0ed07ff1e2..4c4f319f10 100644 --- a/lib/handle_pubackcomp.c +++ b/lib/handle_pubackcomp.c @@ -42,6 +42,7 @@ int handle__pubackcomp(struct mosquitto_db *db, struct mosquitto *mosq, const ch int handle__pubackcomp(struct mosquitto *mosq, const char *type) #endif { + uint8_t reason_code; uint16_t mid; int rc; mosquitto_property *properties = NULL; @@ -52,6 +53,9 @@ int handle__pubackcomp(struct mosquitto *mosq, const char *type) if(mid == 0) return MOSQ_ERR_PROTOCOL; if(mosq->protocol == mosq_p_mqtt5){ + rc = packet__read_byte(&mosq->in_packet, &reason_code); + if(rc) return rc; + rc = property__read_all(CMD_PUBACK, &mosq->in_packet, &properties); if(rc) return rc; } diff --git a/lib/handle_pubrec.c b/lib/handle_pubrec.c index 4bd580293f..56879265c5 100644 --- a/lib/handle_pubrec.c +++ b/lib/handle_pubrec.c @@ -37,6 +37,7 @@ and the Eclipse Distribution License is available at int handle__pubrec(struct mosquitto *mosq) { + uint8_t reason_code; uint16_t mid; int rc; mosquitto_property *properties = NULL; @@ -47,6 +48,9 @@ int handle__pubrec(struct mosquitto *mosq) if(mid == 0) return MOSQ_ERR_PROTOCOL; if(mosq->protocol == mosq_p_mqtt5){ + rc = packet__read_byte(&mosq->in_packet, &reason_code); + if(rc) return rc; + rc = property__read_all(CMD_PUBREC, &mosq->in_packet, &properties); if(rc) return rc; /* Immediately free, we don't do anything with Reason String or User Property at the moment */ diff --git a/lib/handle_pubrel.c b/lib/handle_pubrel.c index 8c60645903..2ec6dc8b05 100644 --- a/lib/handle_pubrel.c +++ b/lib/handle_pubrel.c @@ -38,6 +38,7 @@ and the Eclipse Distribution License is available at int handle__pubrel(struct mosquitto_db *db, struct mosquitto *mosq) { + uint8_t reason_code; uint16_t mid; #ifndef WITH_BROKER struct mosquitto_message_all *message = NULL; @@ -56,6 +57,9 @@ int handle__pubrel(struct mosquitto_db *db, struct mosquitto *mosq) if(mid == 0) return MOSQ_ERR_PROTOCOL; if(mosq->protocol == mosq_p_mqtt5){ + rc = packet__read_byte(&mosq->in_packet, &reason_code); + if(rc) return rc; + rc = property__read_all(CMD_PUBREL, &mosq->in_packet, &properties); if(rc) return rc; } From 00c4fd137a952832e162deb4052627e66d6b5b5c Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sat, 29 Dec 2018 21:27:24 +0000 Subject: [PATCH 171/254] More UTF-8 tests. --- test/unit/utf8.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/unit/utf8.c b/test/unit/utf8.c index 52c339983f..1982da87a9 100644 --- a/test/unit/utf8.c +++ b/test/unit/utf8.c @@ -425,6 +425,26 @@ void TEST_utf8_control_characters(void) } + +void TEST_utf8_mqtt_1_5_4_2(void) +{ + char buf[10] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', '\0'}; + + utf8_helper_len(buf, 9, MOSQ_ERR_SUCCESS); + + buf[3] = '\0'; + utf8_helper_len(buf, 9, MOSQ_ERR_MALFORMED_UTF8); +} + + +void TEST_utf8_mqtt_1_5_4_3(void) +{ + char buf[10] = {'a', 'b', 0xEF, 0xBB, 0xBF, 'f', 'g', 'h', 'i', '\0'}; + + utf8_helper_len(buf, 9, MOSQ_ERR_SUCCESS); +} + + /* ======================================================================== * TEST SUITE SETUP * ======================================================================== */ @@ -448,6 +468,8 @@ int init_utf8_tests(void) || !CU_add_test(test_suite, "UTF-8 overlong encoding", TEST_utf8_overlong_encoding) || !CU_add_test(test_suite, "UTF-8 illegal code positions", TEST_utf8_illegal_code_positions) || !CU_add_test(test_suite, "UTF-8 control characters", TEST_utf8_control_characters) + || !CU_add_test(test_suite, "UTF-8 MQTT-1.5.4-2", TEST_utf8_mqtt_1_5_4_2) + || !CU_add_test(test_suite, "UTF-8 MQTT-1.5.4-3", TEST_utf8_mqtt_1_5_4_3) ){ printf("Error adding UTF-8 CUnit tests.\n"); From 16e83bfe5d55cdda6c662916756303bf77f564ee Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sun, 30 Dec 2018 21:17:31 +0000 Subject: [PATCH 172/254] Process receive maximum (as max_inflight_messages). --- lib/mosquitto_internal.h | 2 +- src/conf.c | 18 +++++++++--------- src/context.c | 1 + src/database.c | 18 ++++++++---------- src/mosquitto_broker_internal.h | 3 ++- src/property_broker.c | 10 ++++++++++ 6 files changed, 31 insertions(+), 21 deletions(-) diff --git a/lib/mosquitto_internal.h b/lib/mosquitto_internal.h index 55a537a77b..5eff5d0627 100644 --- a/lib/mosquitto_internal.h +++ b/lib/mosquitto_internal.h @@ -279,11 +279,11 @@ struct mosquitto { char threaded; struct mosquitto__packet *out_packet_last; int inflight_messages; - int max_inflight_messages; # ifdef WITH_SRV ares_channel achan; # endif #endif + int max_inflight_messages; #ifdef WITH_BROKER UT_hash_handle hh_id; diff --git a/src/conf.c b/src/conf.c index b18af7b176..0ae70ee491 100644 --- a/src/conf.c +++ b/src/conf.c @@ -53,7 +53,6 @@ struct config_recurse { int log_type_set; unsigned long max_inflight_bytes; unsigned long max_queued_bytes; - int max_inflight_messages; int max_queued_messages; }; @@ -213,6 +212,7 @@ static void config__init_reload(struct mosquitto_db *db, struct mosquitto__confi #endif config->log_timestamp = true; config->max_keepalive = 65535; + config->max_inflight_messages = 20; config->persistence = false; mosquitto__free(config->persistence_location); config->persistence_location = NULL; @@ -598,7 +598,6 @@ int config__read(struct mosquitto_db *db, struct mosquitto__config *config, bool cr.log_type = MOSQ_LOG_NONE; cr.log_type_set = 0; cr.max_inflight_bytes = 0; - cr.max_inflight_messages = 20; cr.max_queued_bytes = 0; cr.max_queued_messages = 100; @@ -681,7 +680,7 @@ int config__read(struct mosquitto_db *db, struct mosquitto__config *config, bool config->user = "mosquitto"; } - db__limits_set(cr.max_inflight_messages, cr.max_inflight_bytes, cr.max_queued_messages, cr.max_queued_bytes); + db__limits_set(cr.max_inflight_bytes, cr.max_queued_messages, cr.max_queued_bytes); #ifdef WITH_BRIDGE for(i=0; ibridge_count; i++){ @@ -1511,13 +1510,14 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct log__printf(NULL, MOSQ_LOG_ERR, "Error: Empty max_inflight_bytes value in configuration."); } }else if(!strcmp(token, "max_inflight_messages")){ - token = strtok_r(NULL, " ", &saveptr); - if(token){ - cr->max_inflight_messages = atoi(token); - if(cr->max_inflight_messages < 0) cr->max_inflight_messages = 0; - }else{ - log__printf(NULL, MOSQ_LOG_ERR, "Error: Empty max_inflight_messages value in configuration."); + if(conf__parse_int(&token, "max_inflight_messages", &tmp_int, saveptr)) return MOSQ_ERR_INVAL; + if(tmp_int < 0 || tmp_int == 65535){ + tmp_int = 0; + }else if(tmp_int > 65535){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: max_inflight_messages must be <= 65535."); + return MOSQ_ERR_INVAL; } + config->max_inflight_messages = tmp_int; }else if(!strcmp(token, "max_keepalive")){ if(conf__parse_int(&token, "max_keepalive", &tmp_int, saveptr)) return MOSQ_ERR_INVAL; if(tmp_int < 10 || tmp_int > 65535){ diff --git a/src/context.c b/src/context.c index c7fa9da39d..a93b8e3033 100644 --- a/src/context.c +++ b/src/context.c @@ -76,6 +76,7 @@ struct mosquitto *context__init(struct mosquitto_db *db, mosq_sock_t sock) context->last_inflight_msg = NULL; context->queued_msgs = NULL; context->last_queued_msg = NULL; + context->max_inflight_messages = db->config->max_inflight_messages; context->msg_bytes = 0; context->msg_bytes12 = 0; context->msg_count = 0; diff --git a/src/database.c b/src/database.c index 666c58efe1..d93d3c0867 100644 --- a/src/database.c +++ b/src/database.c @@ -25,7 +25,6 @@ and the Eclipse Distribution License is available at #include "sys_tree.h" #include "time_mosq.h" -static int max_inflight = 20; static unsigned long max_inflight_bytes = 0; static int max_queued = 100; static unsigned long max_queued_bytes = 0; @@ -38,14 +37,14 @@ static unsigned long max_queued_bytes = 0; */ static bool db__ready_for_flight(struct mosquitto *context, int qos) { - if(qos == 0 || (max_inflight == 0 && max_inflight_bytes == 0)){ + if(qos == 0 || (context->max_inflight_messages == 0 && max_inflight_bytes == 0)){ return true; } bool valid_bytes = context->msg_bytes12 < max_inflight_bytes; - bool valid_count = context->msg_count12 < max_inflight; + bool valid_count = context->msg_count12 < context->max_inflight_messages; - if(max_inflight == 0){ + if(context->max_inflight_messages == 0){ return valid_bytes; } if(max_inflight_bytes == 0){ @@ -73,7 +72,7 @@ static bool db__ready_for_queue(struct mosquitto *context, int qos) unsigned long source_bytes = context->msg_bytes12; int source_count = context->msg_count12; unsigned long adjust_bytes = max_inflight_bytes; - int adjust_count = max_inflight; + int adjust_count = context->max_inflight_messages; /* nothing in flight for offline clients */ if(context->sock == INVALID_SOCKET){ @@ -307,7 +306,7 @@ int db__message_delete(struct mosquitto_db *db, struct mosquitto *context, uint1 tail = tail->next; } } - while (context->queued_msgs && (max_inflight == 0 || msg_index < max_inflight)){ + while (context->queued_msgs && (context->max_inflight_messages == 0 || msg_index < context->max_inflight_messages)){ msg_index++; tail = context->queued_msgs; tail->timestamp = mosquitto_time(); @@ -838,7 +837,7 @@ int db__message_release(struct mosquitto_db *db, struct mosquitto *context, uint } } - while(context->queued_msgs && (max_inflight == 0 || msg_index < max_inflight)){ + while(context->queued_msgs && (context->max_inflight_messages == 0 || msg_index < context->max_inflight_messages)){ msg_index++; tail = context->queued_msgs; tail->timestamp = mosquitto_time(); @@ -989,7 +988,7 @@ int db__message_write(struct mosquitto_db *db, struct mosquitto *context) } } - while(context->queued_msgs && (max_inflight == 0 || msg_count < max_inflight)){ + while(context->queued_msgs && (context->max_inflight_messages == 0 || msg_count < context->max_inflight_messages)){ msg_count++; tail = context->queued_msgs; if(tail->direction == mosq_md_out){ @@ -1022,9 +1021,8 @@ int db__message_write(struct mosquitto_db *db, struct mosquitto *context) return MOSQ_ERR_SUCCESS; } -void db__limits_set(int inflight, unsigned long inflight_bytes, int queued, unsigned long queued_bytes) +void db__limits_set(unsigned long inflight_bytes, int queued, unsigned long queued_bytes) { - max_inflight = inflight; max_inflight_bytes = inflight_bytes; max_queued = queued; max_queued_bytes = queued_bytes; diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index cd5eddb8e2..497167c91e 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -260,6 +260,7 @@ struct mosquitto__config { bool log_timestamp; char *log_file; FILE *log_fptr; + uint16_t max_inflight_messages; uint16_t max_keepalive; uint32_t message_size_limit; bool persistence; @@ -552,7 +553,7 @@ int db__close(struct mosquitto_db *db); int persist__backup(struct mosquitto_db *db, bool shutdown); int persist__restore(struct mosquitto_db *db); #endif -void db__limits_set(int inflight, unsigned long inflight_bytes, int queued, unsigned long queued_bytes); +void db__limits_set(unsigned long inflight_bytes, int queued, unsigned long queued_bytes); /* Return the number of in-flight messages in count. */ int db__message_count(int *count); int db__message_delete(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir); diff --git a/src/property_broker.c b/src/property_broker.c index e2f9d46646..57d17c9cea 100644 --- a/src/property_broker.c +++ b/src/property_broker.c @@ -35,6 +35,16 @@ int property__process_connect(struct mosquitto *context, mosquitto_property *pro while(p){ if(p->identifier == MQTT_PROP_SESSION_EXPIRY_INTERVAL){ context->session_expiry_interval = p->value.i32; + }else if(p->identifier == MQTT_PROP_RECEIVE_MAXIMUM){ + if(p->value.i16 == 0){ + return MOSQ_ERR_PROTOCOL; + } + + if(p->value.i16 == 65535){ + context->max_inflight_messages = 0; + }else{ + context->max_inflight_messages = p->value.i16; + } } p = p->next; } From 6eefb45b44e3e01502498aeca4fc4e9e5389cd54 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 3 Jan 2019 23:32:39 +0000 Subject: [PATCH 173/254] Broker tests for Receive Maximum. --- .../02-subpub-qos2-receive-maximum-1.py | 73 +++++++++++++++++++ .../02-subpub-qos2-receive-maximum-2.py | 73 +++++++++++++++++++ .../02-subpub-qos2-receive-maximum-helper.py | 53 ++++++++++++++ test/broker/Makefile | 2 + test/broker/ptest.py | 2 + 5 files changed, 203 insertions(+) create mode 100755 test/broker/02-subpub-qos2-receive-maximum-1.py create mode 100755 test/broker/02-subpub-qos2-receive-maximum-2.py create mode 100755 test/broker/02-subpub-qos2-receive-maximum-helper.py diff --git a/test/broker/02-subpub-qos2-receive-maximum-1.py b/test/broker/02-subpub-qos2-receive-maximum-1.py new file mode 100755 index 0000000000..f517a74525 --- /dev/null +++ b/test/broker/02-subpub-qos2-receive-maximum-1.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python + +# Does the broker respect receive maximum==1? +# MQTT v5 + +from mosq_test_helper import * + +rc = 1 +keepalive = 60 +props = mqtt5_props.gen_uint16_prop(mqtt5_props.PROP_RECEIVE_MAXIMUM, 1) +props = mqtt5_props.prop_finalise(props) +connect_packet = mosq_test.gen_connect("subpub-qos2-test", keepalive=keepalive, proto_ver=5, properties=props) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +mid = 1 +subscribe_packet = mosq_test.gen_subscribe(mid, "subpub/qos2", 2, proto_ver=5) +suback_packet = mosq_test.gen_suback(mid, 2, proto_ver=5) + +mid = 1 +publish_packet1 = mosq_test.gen_publish("subpub/qos2", qos=2, mid=mid, payload="message1", proto_ver=5) +pubrec_packet1 = mosq_test.gen_pubrec(mid, proto_ver=5) +pubrel_packet1 = mosq_test.gen_pubrel(mid, proto_ver=5) +pubcomp_packet1 = mosq_test.gen_pubcomp(mid, proto_ver=5) + +mid = 2 +publish_packet2 = mosq_test.gen_publish("subpub/qos2", qos=2, mid=mid, payload="message2", proto_ver=5) +pubrec_packet2 = mosq_test.gen_pubrec(mid, proto_ver=5) +pubrel_packet2 = mosq_test.gen_pubrel(mid, proto_ver=5) +pubcomp_packet2 = mosq_test.gen_pubcomp(mid, proto_ver=5) + +mid = 3 +publish_packet3 = mosq_test.gen_publish("subpub/qos2", qos=2, mid=mid, payload="message3", proto_ver=5) +pubrec_packet3 = mosq_test.gen_pubrec(mid, proto_ver=5) +pubrel_packet3 = mosq_test.gen_pubrel(mid, proto_ver=5) +pubcomp_packet3 = mosq_test.gen_pubcomp(mid, proto_ver=5) + + +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) + + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback") + + pub = subprocess.Popen(['./02-subpub-qos2-receive-maximum-helper.py', str(port)], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + pub.wait() + (stdo, stde) = pub.communicate() + + if mosq_test.expect_packet(sock, "publish1", publish_packet1): + mosq_test.do_send_receive(sock, pubrec_packet1, pubrel_packet1, "pubrel1") + sock.send(pubcomp_packet1) + + if mosq_test.expect_packet(sock, "publish2", publish_packet2): + mosq_test.do_send_receive(sock, pubrec_packet2, pubrel_packet2, "pubrel2") + sock.send(pubcomp_packet2) + + if mosq_test.expect_packet(sock, "publish3", publish_packet3): + mosq_test.do_send_receive(sock, pubrec_packet3, pubrel_packet3, "pubrel3") + sock.send(pubcomp_packet3) + + rc = 0 + + sock.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/02-subpub-qos2-receive-maximum-2.py b/test/broker/02-subpub-qos2-receive-maximum-2.py new file mode 100755 index 0000000000..4084737db8 --- /dev/null +++ b/test/broker/02-subpub-qos2-receive-maximum-2.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python + +# Does the broker respect receive maximum==2? +# MQTT v5 + +from mosq_test_helper import * + +rc = 1 +keepalive = 60 +props = mqtt5_props.gen_uint16_prop(mqtt5_props.PROP_RECEIVE_MAXIMUM, 2) +props = mqtt5_props.prop_finalise(props) +connect_packet = mosq_test.gen_connect("subpub-qos2-test", keepalive=keepalive, proto_ver=5, properties=props) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +mid = 1 +subscribe_packet = mosq_test.gen_subscribe(mid, "subpub/qos2", 2, proto_ver=5) +suback_packet = mosq_test.gen_suback(mid, 2, proto_ver=5) + +mid = 1 +publish_packet1 = mosq_test.gen_publish("subpub/qos2", qos=2, mid=mid, payload="message1", proto_ver=5) +pubrec_packet1 = mosq_test.gen_pubrec(mid, proto_ver=5) +pubrel_packet1 = mosq_test.gen_pubrel(mid, proto_ver=5) +pubcomp_packet1 = mosq_test.gen_pubcomp(mid, proto_ver=5) + +mid = 2 +publish_packet2 = mosq_test.gen_publish("subpub/qos2", qos=2, mid=mid, payload="message2", proto_ver=5) +pubrec_packet2 = mosq_test.gen_pubrec(mid, proto_ver=5) +pubrel_packet2 = mosq_test.gen_pubrel(mid, proto_ver=5) +pubcomp_packet2 = mosq_test.gen_pubcomp(mid, proto_ver=5) + +mid = 3 +publish_packet3 = mosq_test.gen_publish("subpub/qos2", qos=2, mid=mid, payload="message3", proto_ver=5) +pubrec_packet3 = mosq_test.gen_pubrec(mid, proto_ver=5) +pubrel_packet3 = mosq_test.gen_pubrel(mid, proto_ver=5) +pubcomp_packet3 = mosq_test.gen_pubcomp(mid, proto_ver=5) + + +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) + + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback") + + pub = subprocess.Popen(['./02-subpub-qos2-receive-maximum-helper.py', str(port)], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + pub.wait() + (stdo, stde) = pub.communicate() + + if mosq_test.expect_packet(sock, "publish1", publish_packet1): + if mosq_test.expect_packet(sock, "publish2", publish_packet2): + mosq_test.do_send_receive(sock, pubrec_packet1, pubrel_packet1, "pubrel1") + sock.send(pubcomp_packet1) + + if mosq_test.expect_packet(sock, "publish3", publish_packet3): + mosq_test.do_send_receive(sock, pubrec_packet2, pubrel_packet2, "pubrel2") + sock.send(pubcomp_packet2) + + mosq_test.do_send_receive(sock, pubrec_packet3, pubrel_packet3, "pubrel3") + sock.send(pubcomp_packet3) + + rc = 0 + + sock.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/02-subpub-qos2-receive-maximum-helper.py b/test/broker/02-subpub-qos2-receive-maximum-helper.py new file mode 100755 index 0000000000..01eb91a691 --- /dev/null +++ b/test/broker/02-subpub-qos2-receive-maximum-helper.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +# Test whether a client subscribed to a topic receives its own message sent to that topic. +# MQTT v5 + +from mosq_test_helper import * + +rc = 1 +keepalive = 60 +connect_packet = mosq_test.gen_connect("subpub-qos2-test-helper", keepalive=keepalive, proto_ver=5) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +mid = 1 +publish_packet = mosq_test.gen_publish("subpub/qos2", qos=2, mid=mid, payload="message1", proto_ver=5) +pubrec_packet = mosq_test.gen_pubrec(mid, proto_ver=5) +pubrel_packet = mosq_test.gen_pubrel(mid, proto_ver=5) +pubcomp_packet = mosq_test.gen_pubcomp(mid, proto_ver=5) + +mid = 2 +publish_packet2 = mosq_test.gen_publish("subpub/qos2", qos=2, mid=mid, payload="message2", proto_ver=5) +pubrec_packet2 = mosq_test.gen_pubrec(mid, proto_ver=5) +pubrel_packet2 = mosq_test.gen_pubrel(mid, proto_ver=5) +pubcomp_packet2 = mosq_test.gen_pubcomp(mid, proto_ver=5) + +mid = 3 +publish_packet3 = mosq_test.gen_publish("subpub/qos2", qos=2, mid=mid, payload="message3", proto_ver=5) +pubrec_packet3 = mosq_test.gen_pubrec(mid, proto_ver=5) +pubrel_packet3 = mosq_test.gen_pubrel(mid, proto_ver=5) +pubcomp_packet3 = mosq_test.gen_pubcomp(mid, proto_ver=5) + + +port = mosq_test.get_port() + +try: + sock = mosq_test.do_client_connect(connect_packet, connack_packet, timeout=20, port=port) + + mosq_test.do_send_receive(sock, publish_packet, pubrec_packet, "pubrec") + mosq_test.do_send_receive(sock, pubrel_packet, pubcomp_packet, "pubcomp") + + mosq_test.do_send_receive(sock, publish_packet2, pubrec_packet2, "pubrec2") + mosq_test.do_send_receive(sock, pubrel_packet2, pubcomp_packet2, "pubcomp2") + + mosq_test.do_send_receive(sock, publish_packet3, pubrec_packet3, "pubrec3") + mosq_test.do_send_receive(sock, pubrel_packet3, pubcomp_packet3, "pubcomp3") + rc = 0 + + sock.close() +finally: + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index fa77f88e70..8d9043d1a9 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -56,6 +56,8 @@ endif ./02-subpub-qos0-retain-as-publish.py ./02-subpub-qos0-send-retain.py ./02-subpub-qos0-subscription-id.py + ./02-subpub-qos2-receive-maximum-1.py + ./02-subpub-qos2-receive-maximum-2.py ./02-unsubscribe-qos0.py ./02-unsubscribe-qos1.py ./02-unsubscribe-qos2.py diff --git a/test/broker/ptest.py b/test/broker/ptest.py index 494eda3911..406dfe67f8 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -39,6 +39,8 @@ (1, './02-subpub-qos0-retain-as-publish.py'), (1, './02-subpub-qos0-send-retain.py'), (1, './02-subpub-qos0-subscription-id.py'), + (1, './02-subpub-qos2-receive-maximum-1.py'), + (1, './02-subpub-qos2-receive-maximum-2.py'), (1, './02-unsubscribe-qos0.py'), (1, './02-unsubscribe-qos1.py'), (1, './02-unsubscribe-qos2.py'), From 2f54b165440ffcea05949ec73ade74965cb477e1 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 8 Jan 2019 14:19:50 +0000 Subject: [PATCH 174/254] Fix mosquitto_pub not always sending everything with -l and QoS>0. --- ChangeLog.txt | 4 ++++ client/pub_shared.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 7b83dd4953..5959289dcb 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -17,6 +17,10 @@ Client features: its subscriptions acknowledged. Use with -c to create a durable client session without requiring a message to be received. +Client fixes: +- mosquitto_pub wouldn't always publish all messages when using `-l` and + QoS>0. This has been fixed. + 1.5.5 - 20181211 ================ diff --git a/client/pub_shared.c b/client/pub_shared.c index 9f10d5ec99..9ef50084d8 100644 --- a/client/pub_shared.c +++ b/client/pub_shared.c @@ -200,7 +200,7 @@ int pub_shared_loop(struct mosquitto *mosq) } } if(feof(stdin)){ - if(last_mid == -1){ + if(mid_sent == -1){ /* Empty file */ mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props); disconnect_sent = true; From 0546e7bebcf5faf8589116a139ef13daf0cbe541 Mon Sep 17 00:00:00 2001 From: Roger Light Date: Tue, 8 Jan 2019 11:12:35 +0000 Subject: [PATCH 175/254] Add mosquitto_int_option and mosquitto_void_option This deprecates mosquitto_opts_set(). --- client/client_shared.c | 2 +- lib/linker.version | 2 ++ lib/mosquitto.h | 54 ++++++++++++++++++++++++++++++++++ lib/options.c | 66 +++++++++++++++++++++++++++++++++++------- 4 files changed, 113 insertions(+), 11 deletions(-) diff --git a/client/client_shared.c b/client/client_shared.c index 517a6a6f78..b38306ca88 100644 --- a/client/client_shared.c +++ b/client/client_shared.c @@ -947,7 +947,7 @@ int client_opts_set(struct mosquitto *mosq, struct mosq_config *cfg) { int rc; - mosquitto_opts_set(mosq, MOSQ_OPT_PROTOCOL_VERSION, &(cfg->protocol_version)); + mosquitto_int_option(mosq, MOSQ_OPT_PROTOCOL_VERSION, cfg->protocol_version); if(cfg->will_topic && mosquitto_will_set_v5(mosq, cfg->will_topic, cfg->will_payloadlen, cfg->will_payload, cfg->will_qos, diff --git a/lib/linker.version b/lib/linker.version index e9ee68ca0a..d7eecba006 100644 --- a/lib/linker.version +++ b/lib/linker.version @@ -99,6 +99,7 @@ MOSQ_1.6 { mosquitto_disconnect_v5_callback_set; mosquitto_disconnect_v5; mosquitto_message_v5_callback_set; + mosquitto_int_option; mosquitto_property_add_binary; mosquitto_property_add_byte; mosquitto_property_add_int16; @@ -126,5 +127,6 @@ MOSQ_1.6 { mosquitto_subscribe_v5; mosquitto_unsubscribe_v5_callback_set; mosquitto_unsubscribe_v5; + mosquitto_void_option; mosquitto_will_set_v5; } MOSQ_1.5; diff --git a/lib/mosquitto.h b/lib/mosquitto.h index 1c91d7fb80..742ef59920 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -1313,6 +1313,9 @@ libmosq_EXPORT int mosquitto_threaded_set(struct mosquitto *mosq, bool threaded) * * Used to set options for the client. * + * This function is deprecated, the replacement and + * functions should be used instead. + * * Parameters: * mosq - a valid mosquitto instance. * option - the option to set. @@ -1345,6 +1348,57 @@ libmosq_EXPORT int mosquitto_threaded_set(struct mosquitto *mosq, bool threaded) */ libmosq_EXPORT int mosquitto_opts_set(struct mosquitto *mosq, enum mosq_opt_t option, void *value); +/* + * Function: mosquitto_int_option + * + * Used to set integer options for the client. + * + * Parameters: + * mosq - a valid mosquitto instance. + * option - the option to set. + * value - the option specific value. + * + * Options: + * 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_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 + * the values that are relevant to you. If you use this option then + * you must configure the TLS options as normal, i.e. you should + * use to configure the cafile/capath as a + * minimum. + * This option is only available for openssl 1.1.0 and higher. + */ +libmosq_EXPORT int mosquitto_int_option(struct mosquitto *mosq, enum mosq_opt_t option, int value); + +/* + * Function: mosquitto_void_option + * + * Used to set void* options for the client. + * + * Parameters: + * mosq - a valid mosquitto instance. + * option - the option to set. + * value - the option specific value. + * + * Options: + * 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 + * onus is on you to ensure that you are using secure settings. + * Setting to NULL means that libmosquitto will use its own SSL_CTX + * if TLS is to be used. + * This option is only available for openssl 1.1.0 and higher. + */ +libmosq_EXPORT int mosquitto_void_option(struct mosquitto *mosq, enum mosq_opt_t option, void *value); + + /* * Function: mosquitto_reconnect_delay_set * diff --git a/lib/options.c b/lib/options.c index 85a9cba1a2..c320805080 100644 --- a/lib/options.c +++ b/lib/options.c @@ -276,16 +276,69 @@ int mosquitto_opts_set(struct mosquitto *mosq, enum mosq_opt_t option, void *val switch(option){ case MOSQ_OPT_PROTOCOL_VERSION: ival = *((int *)value); - if(ival == MQTT_PROTOCOL_V31){ + return mosquitto_int_option(mosq, option, ival); + case MOSQ_OPT_SSL_CTX: +#ifdef WITH_TLS + mosq->ssl_ctx = (SSL_CTX *)value; + if(mosq->ssl_ctx){ +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER) + SSL_CTX_up_ref(mosq->ssl_ctx); +#else + CRYPTO_add(&(mosq->ssl_ctx)->references, 1, CRYPTO_LOCK_SSL_CTX); +#endif + } + break; +#else + return MOSQ_ERR_NOT_SUPPORTED; +#endif + default: + return MOSQ_ERR_INVAL; + } + return MOSQ_ERR_SUCCESS; +} + + +int mosquitto_int_option(struct mosquitto *mosq, enum mosq_opt_t option, int value) +{ + if(!mosq) return MOSQ_ERR_INVAL; + + switch(option){ + case MOSQ_OPT_PROTOCOL_VERSION: + if(value == MQTT_PROTOCOL_V31){ mosq->protocol = mosq_p_mqtt31; - }else if(ival == MQTT_PROTOCOL_V311){ + }else if(value == MQTT_PROTOCOL_V311){ mosq->protocol = mosq_p_mqtt311; - }else if(ival == MQTT_PROTOCOL_V5){ + }else if(value == MQTT_PROTOCOL_V5){ mosq->protocol = mosq_p_mqtt5; }else{ return MOSQ_ERR_INVAL; } break; + + case MOSQ_OPT_SSL_CTX_WITH_DEFAULTS: +#if defined(WITH_TLS) && OPENSSL_VERSION_NUMBER >= 0x10100000L + if(value){ + mosq->ssl_ctx_defaults = true; + }else{ + mosq->ssl_ctx_defaults = false; + } + break; +#else + return MOSQ_ERR_NOT_SUPPORTED; +#endif + + default: + return MOSQ_ERR_INVAL; + } + return MOSQ_ERR_SUCCESS; +} + + +int mosquitto_void_option(struct mosquitto *mosq, enum mosq_opt_t option, void *value) +{ + if(!mosq || !value) return MOSQ_ERR_INVAL; + + switch(option){ case MOSQ_OPT_SSL_CTX: #ifdef WITH_TLS mosq->ssl_ctx = (SSL_CTX *)value; @@ -299,13 +352,6 @@ int mosquitto_opts_set(struct mosquitto *mosq, enum mosq_opt_t option, void *val break; #else return MOSQ_ERR_NOT_SUPPORTED; -#endif - case MOSQ_OPT_SSL_CTX_WITH_DEFAULTS: -#if defined(WITH_TLS) && OPENSSL_VERSION_NUMBER >= 0x10100000L - mosq->ssl_ctx_defaults = true; - break; -#else - return MOSQ_ERR_NOT_SUPPORTED; #endif default: return MOSQ_ERR_INVAL; From 67c1d4453e7574b2f3f9caf86fd4d1c8b72220da Mon Sep 17 00:00:00 2001 From: Roger Light Date: Tue, 8 Jan 2019 12:27:19 +0000 Subject: [PATCH 176/254] Receive maximum support for clients. --- lib/connect.c | 3 ++- lib/handle_publish.c | 9 +++++++++ lib/mosquitto.c | 1 + lib/mosquitto.h | 11 +++++++++++ lib/mosquitto_internal.h | 2 ++ lib/options.c | 7 +++++++ lib/send_connect.c | 27 +++++++++++++++++++++------ lib/send_mosq.c | 7 +++++++ lib/util_mosq.c | 9 +++++++++ lib/util_mosq.h | 1 + test/mosq_test.py | 2 ++ 11 files changed, 72 insertions(+), 7 deletions(-) diff --git a/lib/connect.c b/lib/connect.c index 5beed13a2c..a08f7902a2 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -68,6 +68,7 @@ static int mosquitto__connect_init(struct mosquitto *mosq, const char *host, int } mosq->keepalive = keepalive; + mosq->receive_quota = mosq->receive_maximum; if(mosq->sockpairR != INVALID_SOCKET){ COMPAT_CLOSE(mosq->sockpairR); @@ -191,7 +192,7 @@ static int mosquitto__reconnect(struct mosquitto *mosq, bool blocking, const mos mosq->ping_t = 0; packet__cleanup(&mosq->in_packet); - + pthread_mutex_lock(&mosq->current_out_packet_mutex); pthread_mutex_lock(&mosq->out_packet_mutex); diff --git a/lib/handle_publish.c b/lib/handle_publish.c index ed93703e7e..acebd90a97 100644 --- a/lib/handle_publish.c +++ b/lib/handle_publish.c @@ -62,6 +62,15 @@ int handle__publish(struct mosquitto *mosq) } if(message->msg.qos > 0){ + if(mosq->protocol == mosq_p_mqtt5){ + if(mosq->receive_quota == 0){ + message__cleanup(&message); + /* FIXME - should send a DISCONNECT here */ + return MOSQ_ERR_PROTOCOL; + } + mosq->receive_quota--; + } + rc = packet__read_uint16(&mosq->in_packet, &mid); if(rc){ message__cleanup(&message); diff --git a/lib/mosquitto.c b/lib/mosquitto.c index 92c4e9ea4e..b07c69f887 100644 --- a/lib/mosquitto.c +++ b/lib/mosquitto.c @@ -147,6 +147,7 @@ int mosquitto_reinitialise(struct mosquitto *mosq, const char *id, bool clean_st mosq->out_messages = NULL; mosq->out_messages_last = NULL; mosq->max_inflight_messages = 20; + mosq->receive_maximum = 20; mosq->will = NULL; mosq->on_connect = NULL; mosq->on_publish = NULL; diff --git a/lib/mosquitto.h b/lib/mosquitto.h index 742ef59920..cadb2ee00b 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -99,6 +99,7 @@ enum mosq_opt_t { MOSQ_OPT_PROTOCOL_VERSION = 1, MOSQ_OPT_SSL_CTX = 2, MOSQ_OPT_SSL_CTX_WITH_DEFAULTS = 3, + MOSQ_OPT_RECEIVE_MAXIMUM = 4, }; /* MQTT specification restricts client ids to a maximum of 23 characters */ @@ -1364,6 +1365,16 @@ libmosq_EXPORT int mosquitto_opts_set(struct mosquitto *mosq, enum mosq_opt_t op * MQTT_PROTOCOL_V311, or MQTT_PROTOCOL_V5. Must be set before the * client connects. Defaults to MQTT_PROTOCOL_V311. * + * 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 + * not valid for MQTT v3.1 or v3.1.1 clients. + * Note that if the MQTT_PROP_RECEIVE_MAXIMUM property is in the + * proplist passed to mosquitto_connect_v5(), then that property + * will override this option. Using this option is the recommended + * method however. + * * 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 diff --git a/lib/mosquitto_internal.h b/lib/mosquitto_internal.h index 5eff5d0627..f62cf3d356 100644 --- a/lib/mosquitto_internal.h +++ b/lib/mosquitto_internal.h @@ -283,6 +283,8 @@ struct mosquitto { ares_channel achan; # endif #endif + int receive_quota; + int receive_maximum; int max_inflight_messages; #ifdef WITH_BROKER diff --git a/lib/options.c b/lib/options.c index c320805080..053a1e4b69 100644 --- a/lib/options.c +++ b/lib/options.c @@ -315,6 +315,13 @@ int mosquitto_int_option(struct mosquitto *mosq, enum mosq_opt_t option, int val } break; + case MOSQ_OPT_RECEIVE_MAXIMUM: + if(value < 0 || value > 65535){ + return MOSQ_ERR_INVAL; + } + mosq->receive_maximum = value; + break; + case MOSQ_OPT_SSL_CTX_WITH_DEFAULTS: #if defined(WITH_TLS) && OPENSSL_VERSION_NUMBER >= 0x10100000L if(value){ diff --git a/lib/send_connect.c b/lib/send_connect.c index 99778634c4..d0bd3cd32b 100644 --- a/lib/send_connect.c +++ b/lib/send_connect.c @@ -41,7 +41,9 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session uint8_t version; char *clientid, *username, *password; int headerlen; - int proplen, varbytes; + int proplen = 0, will_proplen, varbytes; + mosquitto_property *local_props = NULL; + uint16_t receive_maximum; assert(mosq); @@ -64,9 +66,20 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session #endif if(mosq->protocol == mosq_p_mqtt5){ + /* Generate properties from options */ + if(!mosquitto_property_read_int16(properties, MQTT_PROP_RECEIVE_MAXIMUM, &receive_maximum, false)){ + rc = mosquitto_property_add_int16(&local_props, MQTT_PROP_RECEIVE_MAXIMUM, mosq->receive_maximum); + if(rc) return rc; + }else{ + mosq->receive_maximum = receive_maximum; + mosq->receive_quota = receive_maximum; + } + version = MQTT_PROTOCOL_V5; headerlen = 10; - proplen = property__get_length_all(properties); + proplen = 0; + proplen += property__get_length_all(properties); + proplen += property__get_length_all(local_props); varbytes = packet__varint_bytes(proplen); headerlen += proplen + varbytes; }else if(mosq->protocol == mosq_p_mqtt311){ @@ -93,9 +106,9 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session payloadlen += 2+strlen(mosq->will->msg.topic) + 2+mosq->will->msg.payloadlen; if(mosq->protocol == mosq_p_mqtt5){ - proplen = property__get_length_all(mosq->will->properties); - varbytes = packet__varint_bytes(proplen); - payloadlen += proplen + varbytes; + will_proplen = property__get_length_all(mosq->will->properties); + varbytes = packet__varint_bytes(will_proplen); + payloadlen += will_proplen + varbytes; } } if(username){ @@ -141,7 +154,9 @@ int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session if(mosq->protocol == mosq_p_mqtt5){ /* Write properties */ - property__write_all(packet, properties, true); + packet__write_varint(packet, proplen); + property__write_all(packet, properties, false); + property__write_all(packet, local_props, false); } /* Payload */ diff --git a/lib/send_mosq.c b/lib/send_mosq.c index 8b54b99610..5366fd1e99 100644 --- a/lib/send_mosq.c +++ b/lib/send_mosq.c @@ -72,6 +72,7 @@ int send__puback(struct mosquitto *mosq, uint16_t mid) #else if(mosq) log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBACK (Mid: %d)", mosq->id, mid); #endif + util__increment_receive_quota(mosq); /* We don't use Reason String or User Property yet. */ return send__command_with_mid(mosq, CMD_PUBACK, mid, false, 0, NULL); } @@ -83,6 +84,7 @@ int send__pubcomp(struct mosquitto *mosq, uint16_t mid) #else if(mosq) log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBCOMP (Mid: %d)", mosq->id, mid); #endif + util__increment_receive_quota(mosq); /* We don't use Reason String or User Property yet. */ return send__command_with_mid(mosq, CMD_PUBCOMP, mid, false, 0, NULL); } @@ -95,6 +97,11 @@ int send__pubrec(struct mosquitto *mosq, uint16_t mid) #else if(mosq) log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBREC (Mid: %d)", mosq->id, mid); #endif + /* FIXME - if rc >= 0x80 quota needs incrementing + if(rc >= 0x80){ + util__increment_receive_quota(mosq); + } + */ /* We don't use Reason String or User Property yet. */ return send__command_with_mid(mosq, CMD_PUBREC, mid, false, 0, NULL); } diff --git a/lib/util_mosq.c b/lib/util_mosq.c index 07ba6afb9b..1683a2e9a3 100644 --- a/lib/util_mosq.c +++ b/lib/util_mosq.c @@ -252,3 +252,12 @@ FILE *mosquitto__fopen(const char *path, const char *mode, bool restrict_read) } #endif } + +void util__increment_receive_quota(struct mosquitto *mosq) +{ + if(mosq->protocol == mosq_p_mqtt5){ + if(mosq->receive_quota < mosq->receive_maximum){ + mosq->receive_quota++; + } + } +} diff --git a/lib/util_mosq.h b/lib/util_mosq.h index d94661e7aa..62a14f2be8 100644 --- a/lib/util_mosq.h +++ b/lib/util_mosq.h @@ -37,4 +37,5 @@ FILE *mosquitto__fopen(const char *path, const char *mode, bool restrict_read); int mosquitto__hex2bin(const char *hex, unsigned char *bin, int bin_max_len); #endif +void util__increment_receive_quota(struct mosquitto *mosq); #endif diff --git a/test/mosq_test.py b/test/mosq_test.py index abea7af509..cfa182f57f 100644 --- a/test/mosq_test.py +++ b/test/mosq_test.py @@ -320,6 +320,8 @@ def gen_connect(client_id, clean_session=True, keepalive=60, username=None, pass connect_flags = connect_flags | 0x02 if proto_ver == 5: + properties += mqtt5_props.gen_uint16_prop(mqtt5_props.PROP_RECEIVE_MAXIMUM, 20) + properties = mqtt5_props.prop_finalise(properties) if properties == "": properties = struct.pack("B", 0) remaining_length += len(properties) From 5b6b8e53f41495db4eefa523a958bff42a856ca5 Mon Sep 17 00:00:00 2001 From: Roger Light Date: Tue, 8 Jan 2019 14:26:24 +0000 Subject: [PATCH 177/254] Ignore some test generated files. --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 0bf9912815..d640d5b823 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,8 @@ *.pyc *.so *.vglog +massif.out.* +vglog* c/*.test cpp/*.test From 1f9383d59abb04591fddcb72a44069a5ef48cb81 Mon Sep 17 00:00:00 2001 From: Roger Light Date: Tue, 8 Jan 2019 14:34:35 +0000 Subject: [PATCH 178/254] Helper test scripts for client properties. --- client/pub_test_properties | 26 ++++++++++++++++++++++++++ client/sub_test_properties | 31 +++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100755 client/pub_test_properties create mode 100755 client/sub_test_properties diff --git a/client/pub_test_properties b/client/pub_test_properties new file mode 100755 index 0000000000..8e40058911 --- /dev/null +++ b/client/pub_test_properties @@ -0,0 +1,26 @@ +LD_LIBRARY_PATH=../lib ./mosquitto_pub \ + \ + -t asdf -V mqttv5 -m '{"key":"value"}' \ + \ + -D connect authentication-data password \ + -D connect authentication-method something \ + -D connect maximum-packet-size 0191 \ + -D connect receive-maximum 1000 \ + -D connect request-problem-information 1 \ + -D connect request-response-information 1 \ + -D connect session-expiry-interval 39 \ + -D connect topic-alias-maximum 123 \ + -D connect user-property connect up \ + \ + -D publish content-type application/json \ + -D publish correlation-data some-data \ + -D publish message-expiry-interval 59 \ + -D publish payload-format-indicator 1 \ + -D publish response-topic /dev/null \ + -D publish topic-alias 4 \ + -D publish user-property publish up \ + \ + -D disconnect reason-string "reason" \ + -D disconnect session-expiry-interval 40 \ + -D disconnect user-property disconnect up + diff --git a/client/sub_test_properties b/client/sub_test_properties new file mode 100755 index 0000000000..6d46cb7733 --- /dev/null +++ b/client/sub_test_properties @@ -0,0 +1,31 @@ +LD_LIBRARY_PATH=../lib ./mosquitto_sub \ + \ + -V mqttv5 -C 10 -t \$SYS/# -v -U unsub --will-topic will --will-payload '{"key":"value"}' \ + \ + -D connect authentication-data password \ + -D connect authentication-method something \ + -D connect maximum-packet-size 0191 \ + -D connect receive-maximum 1000 \ + -D connect request-problem-information 1 \ + -D connect request-response-information 1 \ + -D connect session-expiry-interval 39 \ + -D connect topic-alias-maximum 123 \ + -D connect user-property connect up \ + \ + -D will content-type application/json \ + -D will correlation-data some-data \ + -D will message-expiry-interval 59 \ + -D will payload-format-indicator 1 \ + -D will response-topic /dev/null \ + -D will user-property will up \ + -D will will-delay-interval 100 \ + \ + -D subscribe subscription-identifier 1 \ + -D subscribe user-property subscribe up \ + \ + -D unsubscribe user-property unsubscribe up \ + \ + -D disconnect reason-string "reason" \ + -D disconnect session-expiry-interval 40 \ + -D disconnect user-property disconnect up + From 9aec82b0e15010297a653053c3e8d05bd8014530 Mon Sep 17 00:00:00 2001 From: Roger Light Date: Tue, 8 Jan 2019 18:37:38 +0000 Subject: [PATCH 179/254] Finalise test proplists in the packet gen funcs. This makes it easier to add part of a proplist in the test itself, and have the gen func add some more. --- test/broker/02-subpub-qos0-subscription-id.py | 4 ---- test/broker/02-subpub-qos2-receive-maximum-1.py | 1 - test/broker/02-subpub-qos2-receive-maximum-2.py | 1 - test/broker/12-prop-assigned-client-identifier.py | 1 - .../12-prop-response-topic-correlation-data.py | 1 - test/broker/12-prop-response-topic.py | 1 - test/broker/12-prop-session-expiry-invalid.py | 2 -- test/broker/12-prop-subpub-content-type.py | 2 -- test/broker/12-prop-subpub-payload-format.py | 2 -- test/lib/03-request-response-correlation.py | 3 --- test/lib/03-request-response.py | 1 - test/lib/11-prop-send-content-type.py | 1 - test/lib/11-prop-send-payload-format.py | 1 - test/mosq_test.py | 15 ++++++--------- 14 files changed, 6 insertions(+), 30 deletions(-) diff --git a/test/broker/02-subpub-qos0-subscription-id.py b/test/broker/02-subpub-qos0-subscription-id.py index 4841af7589..4f9c1a1deb 100755 --- a/test/broker/02-subpub-qos0-subscription-id.py +++ b/test/broker/02-subpub-qos0-subscription-id.py @@ -12,13 +12,11 @@ mid = 1 props = mqtt5_props.gen_varint_prop(mqtt5_props.PROP_SUBSCRIPTION_IDENTIFIER, 1) -props = mqtt5_props.prop_finalise(props) subscribe1_packet = mosq_test.gen_subscribe(mid, "subpub/id1", 0, proto_ver=5, properties=props) suback1_packet = mosq_test.gen_suback(mid, 0, proto_ver=5) mid = 2 props = mqtt5_props.gen_varint_prop(mqtt5_props.PROP_SUBSCRIPTION_IDENTIFIER, 14) -props = mqtt5_props.prop_finalise(props) subscribe2_packet = mosq_test.gen_subscribe(mid, "subpub/+/id2", 0, proto_ver=5, properties=props) suback2_packet = mosq_test.gen_suback(mid, 0, proto_ver=5) @@ -29,12 +27,10 @@ publish1_packet = mosq_test.gen_publish("subpub/id1", qos=0, payload="message1", proto_ver=5) props = mqtt5_props.gen_varint_prop(mqtt5_props.PROP_SUBSCRIPTION_IDENTIFIER, 1) -props = mqtt5_props.prop_finalise(props) publish1r_packet = mosq_test.gen_publish("subpub/id1", qos=0, payload="message1", proto_ver=5, properties=props) publish2_packet = mosq_test.gen_publish("subpub/test/id2", qos=0, payload="message2", proto_ver=5) props = mqtt5_props.gen_varint_prop(mqtt5_props.PROP_SUBSCRIPTION_IDENTIFIER, 14) -props = mqtt5_props.prop_finalise(props) publish2r_packet = mosq_test.gen_publish("subpub/test/id2", qos=0, payload="message2", proto_ver=5, properties=props) publish3_packet = mosq_test.gen_publish("subpub/noid", qos=0, payload="message3", proto_ver=5) diff --git a/test/broker/02-subpub-qos2-receive-maximum-1.py b/test/broker/02-subpub-qos2-receive-maximum-1.py index f517a74525..db291c52e2 100755 --- a/test/broker/02-subpub-qos2-receive-maximum-1.py +++ b/test/broker/02-subpub-qos2-receive-maximum-1.py @@ -8,7 +8,6 @@ rc = 1 keepalive = 60 props = mqtt5_props.gen_uint16_prop(mqtt5_props.PROP_RECEIVE_MAXIMUM, 1) -props = mqtt5_props.prop_finalise(props) connect_packet = mosq_test.gen_connect("subpub-qos2-test", keepalive=keepalive, proto_ver=5, properties=props) connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) diff --git a/test/broker/02-subpub-qos2-receive-maximum-2.py b/test/broker/02-subpub-qos2-receive-maximum-2.py index 4084737db8..66de557ddb 100755 --- a/test/broker/02-subpub-qos2-receive-maximum-2.py +++ b/test/broker/02-subpub-qos2-receive-maximum-2.py @@ -8,7 +8,6 @@ rc = 1 keepalive = 60 props = mqtt5_props.gen_uint16_prop(mqtt5_props.PROP_RECEIVE_MAXIMUM, 2) -props = mqtt5_props.prop_finalise(props) connect_packet = mosq_test.gen_connect("subpub-qos2-test", keepalive=keepalive, proto_ver=5, properties=props) connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) diff --git a/test/broker/12-prop-assigned-client-identifier.py b/test/broker/12-prop-assigned-client-identifier.py index fac50d11e0..2e85c278c8 100755 --- a/test/broker/12-prop-assigned-client-identifier.py +++ b/test/broker/12-prop-assigned-client-identifier.py @@ -16,7 +16,6 @@ connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5, properties=props) props = mqtt5_props.gen_uint32_prop(mqtt5_props.PROP_SESSION_EXPIRY_INTERVAL, 1) -props = mqtt5_props.prop_finalise(props) disconnect_client_packet = mosq_test.gen_disconnect(proto_ver=5, properties=props) disconnect_server_packet = mosq_test.gen_disconnect(proto_ver=5, reason_code=130) diff --git a/test/broker/12-prop-response-topic-correlation-data.py b/test/broker/12-prop-response-topic-correlation-data.py index 9a04382585..13a64760d0 100755 --- a/test/broker/12-prop-response-topic-correlation-data.py +++ b/test/broker/12-prop-response-topic-correlation-data.py @@ -22,7 +22,6 @@ props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_RESPONSE_TOPIC, "response/topic") props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_CORRELATION_DATA, "45vyvynq30q3vt4 nuy893b4v3") -props = mqtt5_props.prop_finalise(props) publish_packet2 = mosq_test.gen_publish(topic="normal/topic", qos=0, payload="2", proto_ver=5, properties=props) publish_packet1 = mosq_test.gen_publish(topic="response/topic", qos=0, payload="22", proto_ver=5) diff --git a/test/broker/12-prop-response-topic.py b/test/broker/12-prop-response-topic.py index 3b9c3e8bf4..ddfbf936b3 100755 --- a/test/broker/12-prop-response-topic.py +++ b/test/broker/12-prop-response-topic.py @@ -21,7 +21,6 @@ suback_packet = mosq_test.gen_suback(mid=1, qos=0, proto_ver=5) props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_RESPONSE_TOPIC, "response/topic") -props = mqtt5_props.prop_finalise(props) publish_packet2 = mosq_test.gen_publish(topic="normal/topic", qos=0, payload="2", proto_ver=5, properties=props) publish_packet1 = mosq_test.gen_publish(topic="response/topic", qos=0, payload="22", proto_ver=5) diff --git a/test/broker/12-prop-session-expiry-invalid.py b/test/broker/12-prop-session-expiry-invalid.py index de31d0e637..81cd7b5ea5 100755 --- a/test/broker/12-prop-session-expiry-invalid.py +++ b/test/broker/12-prop-session-expiry-invalid.py @@ -9,13 +9,11 @@ keepalive = 10 props = mqtt5_props.gen_uint32_prop(mqtt5_props.PROP_SESSION_EXPIRY_INTERVAL, 0) -props = mqtt5_props.prop_finalise(props) connect_packet = mosq_test.gen_connect("test", proto_ver=5, keepalive=keepalive, properties=props) connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) props = mqtt5_props.gen_uint32_prop(mqtt5_props.PROP_SESSION_EXPIRY_INTERVAL, 1) -props = mqtt5_props.prop_finalise(props) disconnect_client_packet = mosq_test.gen_disconnect(proto_ver=5, properties=props) disconnect_server_packet = mosq_test.gen_disconnect(proto_ver=5, reason_code=130) diff --git a/test/broker/12-prop-subpub-content-type.py b/test/broker/12-prop-subpub-content-type.py index 43ec811dbb..d7106d1585 100755 --- a/test/broker/12-prop-subpub-content-type.py +++ b/test/broker/12-prop-subpub-content-type.py @@ -9,9 +9,7 @@ props_out = mqtt5_props.gen_string_prop(mqtt5_props.PROP_CONTENT_TYPE, "text") props_out = props_out+mqtt5_props.gen_uint16_prop(mqtt5_props.PROP_TOPIC_ALIAS, 1) -props_out = mqtt5_props.prop_finalise(props_out) props_in = mqtt5_props.gen_string_prop(mqtt5_props.PROP_CONTENT_TYPE, "text") -props_in = mqtt5_props.prop_finalise(props_in) helper.prop_subpub_helper(props_out, props_in) diff --git a/test/broker/12-prop-subpub-payload-format.py b/test/broker/12-prop-subpub-payload-format.py index 96d63afefa..8cbd90e1f2 100755 --- a/test/broker/12-prop-subpub-payload-format.py +++ b/test/broker/12-prop-subpub-payload-format.py @@ -9,9 +9,7 @@ props_out = mqtt5_props.gen_byte_prop(mqtt5_props.PROP_PAYLOAD_FORMAT_INDICATOR, 0xed) props_out = props_out+mqtt5_props.gen_uint16_prop(mqtt5_props.PROP_TOPIC_ALIAS, 1) -props_out = mqtt5_props.prop_finalise(props_out) props_in = mqtt5_props.gen_byte_prop(mqtt5_props.PROP_PAYLOAD_FORMAT_INDICATOR, 0xed) -props_in = mqtt5_props.prop_finalise(props_in) helper.prop_subpub_helper(props_out, props_in) diff --git a/test/lib/03-request-response-correlation.py b/test/lib/03-request-response-correlation.py index a2ab54be50..689ddcfce6 100755 --- a/test/lib/03-request-response-correlation.py +++ b/test/lib/03-request-response-correlation.py @@ -22,17 +22,14 @@ props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_RESPONSE_TOPIC, resp_topic) props += mqtt5_props.gen_string_prop(mqtt5_props.PROP_CORRELATION_DATA, "corridor") -props = mqtt5_props.prop_finalise(props) publish1_packet_incoming = mosq_test.gen_publish(pub_topic, qos=0, payload="action", proto_ver=5, properties=props) props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_RESPONSE_TOPIC, resp_topic) props += mqtt5_props.gen_string_prop(mqtt5_props.PROP_CORRELATION_DATA, "corridor") props += mqtt5_props.gen_string_pair_prop(mqtt5_props.PROP_USER_PROPERTY, "user", "data") -props = mqtt5_props.prop_finalise(props) publish1_packet_outgoing = mosq_test.gen_publish(pub_topic, qos=0, payload="action", proto_ver=5, properties=props) props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_CORRELATION_DATA, "corridor") -props = mqtt5_props.prop_finalise(props) publish2_packet = mosq_test.gen_publish(resp_topic, qos=0, payload="a response", proto_ver=5, properties=props) diff --git a/test/lib/03-request-response.py b/test/lib/03-request-response.py index 229bc8f9d5..fe0bf456e9 100755 --- a/test/lib/03-request-response.py +++ b/test/lib/03-request-response.py @@ -21,7 +21,6 @@ props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_RESPONSE_TOPIC, resp_topic) -props = mqtt5_props.prop_finalise(props) publish1_packet = mosq_test.gen_publish(pub_topic, qos=0, payload="action", proto_ver=5, properties=props) publish2_packet = mosq_test.gen_publish(resp_topic, qos=0, payload="a response", proto_ver=5) diff --git a/test/lib/11-prop-send-content-type.py b/test/lib/11-prop-send-content-type.py index f78bb3a6f7..9a433f1ca3 100755 --- a/test/lib/11-prop-send-content-type.py +++ b/test/lib/11-prop-send-content-type.py @@ -10,7 +10,6 @@ connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_CONTENT_TYPE, "application/json") -props = mqtt5_props.prop_finalise(props) publish_packet = mosq_test.gen_publish("prop/qos0", qos=0, payload="message", proto_ver=5, properties=props) disconnect_packet = mosq_test.gen_disconnect(proto_ver=5) diff --git a/test/lib/11-prop-send-payload-format.py b/test/lib/11-prop-send-payload-format.py index da6a61f051..701d55bafb 100755 --- a/test/lib/11-prop-send-payload-format.py +++ b/test/lib/11-prop-send-payload-format.py @@ -20,7 +20,6 @@ connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) props = mqtt5_props.gen_byte_prop(mqtt5_props.PROP_PAYLOAD_FORMAT_INDICATOR, 0x01) -props = mqtt5_props.prop_finalise(props) publish_packet = mosq_test.gen_publish("prop/qos0", qos=0, payload="message", proto_ver=5, properties=props) disconnect_packet = mosq_test.gen_disconnect(proto_ver=5) diff --git a/test/mosq_test.py b/test/mosq_test.py index cfa182f57f..21c702bde1 100644 --- a/test/mosq_test.py +++ b/test/mosq_test.py @@ -320,10 +320,9 @@ def gen_connect(client_id, clean_session=True, keepalive=60, username=None, pass connect_flags = connect_flags | 0x02 if proto_ver == 5: - properties += mqtt5_props.gen_uint16_prop(mqtt5_props.PROP_RECEIVE_MAXIMUM, 20) - properties = mqtt5_props.prop_finalise(properties) if properties == "": - properties = struct.pack("B", 0) + properties += mqtt5_props.gen_uint16_prop(mqtt5_props.PROP_RECEIVE_MAXIMUM, 20) + properties = mqtt5_props.prop_finalise(properties) remaining_length += len(properties) if will_topic != None: @@ -378,7 +377,7 @@ def gen_connack(resv=0, rc=0, proto_ver=4, properties=""): return packet -def gen_publish(topic, qos, payload=None, retain=False, dup=False, mid=0, proto_ver=4, properties=None): +def gen_publish(topic, qos, payload=None, retain=False, dup=False, mid=0, proto_ver=4, properties=""): rl = 2+len(topic) pack_format = "H"+str(len(topic))+"s" if qos > 0: @@ -386,9 +385,7 @@ def gen_publish(topic, qos, payload=None, retain=False, dup=False, mid=0, proto_ pack_format = pack_format + "H" if proto_ver == 5: - if properties is None: - properties = struct.pack("!B", 0) - + properties = mqtt5_props.prop_finalise(properties) rl += len(properties) # This will break if len(properties) > 127 pack_format = pack_format + "%ds"%(len(properties)) @@ -446,6 +443,7 @@ def gen_subscribe(mid, topic, qos, proto_ver=4, properties=""): pack_format = "!BBHBH"+str(len(topic))+"sB" return struct.pack(pack_format, 130, 2+1+2+len(topic)+1, mid, 0, len(topic), topic, qos) else: + properties = mqtt5_props.prop_finalise(properties) pack_format = "!BBH"+str(len(properties))+"s"+"H"+str(len(topic))+"sB" return struct.pack(pack_format, 130, 2+1+2+len(topic)+len(properties), mid, properties, len(topic), topic, qos) else: @@ -480,8 +478,7 @@ def gen_pingresp(): def gen_disconnect(reason_code=0, proto_ver=4, properties=""): if proto_ver == 5: - if properties == "": - properties = struct.pack("B", 0) + properties = mqtt5_props.prop_finalise(properties) return struct.pack('!BBB', 224, 1+len(properties), reason_code) + properties else: From 84660e1cbef07ef856de0527186fecd36ced63ce Mon Sep 17 00:00:00 2001 From: Roger Light Date: Tue, 8 Jan 2019 18:38:47 +0000 Subject: [PATCH 180/254] Send maximum limits for QoS>0. This needs more work on the broker front to simplify the design. --- lib/connect.c | 1 + lib/handle_connack.c | 1 + lib/messages_mosq.c | 30 +++++++++++++----------------- lib/mosquitto.c | 2 +- lib/mosquitto.h | 13 +++++++++++++ lib/mosquitto_internal.h | 6 +++--- lib/options.c | 7 +++++++ lib/util_mosq.c | 7 +++++++ lib/util_mosq.h | 1 + src/context.c | 3 ++- src/database.c | 14 +++++++------- src/property_broker.c | 7 ++----- 12 files changed, 58 insertions(+), 34 deletions(-) diff --git a/lib/connect.c b/lib/connect.c index a08f7902a2..f28040022c 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -69,6 +69,7 @@ static int mosquitto__connect_init(struct mosquitto *mosq, const char *host, int mosq->keepalive = keepalive; mosq->receive_quota = mosq->receive_maximum; + mosq->send_quota = mosq->send_maximum; if(mosq->sockpairR != INVALID_SOCKET){ COMPAT_CLOSE(mosq->sockpairR); diff --git a/lib/handle_connack.c b/lib/handle_connack.c index 5e5fa86df0..135e9b4c1c 100644 --- a/lib/handle_connack.c +++ b/lib/handle_connack.c @@ -62,6 +62,7 @@ int handle__connack(struct mosquitto *mosq) } mosquitto_property_read_int16(properties, MQTT_PROP_SERVER_KEEP_ALIVE, &mosq->keepalive, false); + mosquitto_property_read_int16(properties, MQTT_PROP_RECEIVE_MAXIMUM, &mosq->send_maximum, false); log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received CONNACK (%d)", mosq->id, reason_code); pthread_mutex_lock(&mosq->callback_mutex); diff --git a/lib/messages_mosq.c b/lib/messages_mosq.c index 9d494788f6..51f485505c 100644 --- a/lib/messages_mosq.c +++ b/lib/messages_mosq.c @@ -26,6 +26,7 @@ and the Eclipse Distribution License is available at #include "messages_mosq.h" #include "send_mosq.h" #include "time_mosq.h" +#include "util_mosq.h" void message__cleanup(struct mosquitto_message_all **message) { @@ -123,6 +124,7 @@ int message__queue(struct mosquitto *mosq, struct mosquitto_message_all *message /* mosq->*_message_mutex should be locked before entering this function */ assert(mosq); assert(message); + assert(message->msg.qos != 0); if(dir == mosq_md_out){ mosq->out_queue_len++; @@ -133,12 +135,10 @@ int message__queue(struct mosquitto *mosq, struct mosquitto_message_all *message mosq->out_messages = message; } mosq->out_messages_last = message; - if(message->msg.qos > 0){ - if(mosq->max_inflight_messages == 0 || mosq->inflight_messages < mosq->max_inflight_messages){ - mosq->inflight_messages++; - }else{ - rc = 1; - } + if(mosq->send_quota > 0){ + mosq->send_quota--; + }else{ + rc = 1; } }else{ mosq->in_queue_len++; @@ -187,17 +187,15 @@ void message__reconnect_reset(struct mosquitto *mosq) pthread_mutex_lock(&mosq->out_message_mutex); - mosq->inflight_messages = 0; + mosq->send_quota = mosq->send_maximum; message = mosq->out_messages; mosq->out_queue_len = 0; while(message){ mosq->out_queue_len++; message->timestamp = 0; - if(mosq->max_inflight_messages == 0 || mosq->inflight_messages < mosq->max_inflight_messages){ - if(message->msg.qos > 0){ - mosq->inflight_messages++; - } + if(mosq->send_quota > 0){ + mosq->send_quota--; if(message->msg.qos == 1){ message->state = mosq_ms_publish_qos1; }else if(message->msg.qos == 2){ @@ -243,9 +241,7 @@ int message__remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_dir }else if(!mosq->out_messages){ mosq->out_messages_last = NULL; } - if(cur->msg.qos > 0){ - mosq->inflight_messages--; - } + util__increment_send_quota(mosq); found = true; break; } @@ -256,9 +252,9 @@ int message__remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_dir if(found){ cur = mosq->out_messages; while(cur){ - if(mosq->max_inflight_messages == 0 || mosq->inflight_messages < mosq->max_inflight_messages){ + if(mosq->send_quota > 0){ if(cur->msg.qos > 0 && cur->state == mosq_ms_invalid){ - mosq->inflight_messages++; + mosq->send_quota--; if(cur->msg.qos == 1){ cur->state = mosq_ms_wait_for_puback; }else if(cur->msg.qos == 2){ @@ -394,7 +390,7 @@ int mosquitto_max_inflight_messages_set(struct mosquitto *mosq, unsigned int max { if(!mosq) return MOSQ_ERR_INVAL; - mosq->max_inflight_messages = max_inflight_messages; + mosq->send_maximum = max_inflight_messages; return MOSQ_ERR_SUCCESS; } diff --git a/lib/mosquitto.c b/lib/mosquitto.c index b07c69f887..c5bb056e63 100644 --- a/lib/mosquitto.c +++ b/lib/mosquitto.c @@ -146,8 +146,8 @@ int mosquitto_reinitialise(struct mosquitto *mosq, const char *id, bool clean_st mosq->in_messages_last = NULL; mosq->out_messages = NULL; mosq->out_messages_last = NULL; - mosq->max_inflight_messages = 20; mosq->receive_maximum = 20; + mosq->send_maximum = 20; mosq->will = NULL; mosq->on_connect = NULL; mosq->on_publish = NULL; diff --git a/lib/mosquitto.h b/lib/mosquitto.h index cadb2ee00b..81fc692964 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -100,6 +100,7 @@ enum mosq_opt_t { MOSQ_OPT_SSL_CTX = 2, MOSQ_OPT_SSL_CTX_WITH_DEFAULTS = 3, MOSQ_OPT_RECEIVE_MAXIMUM = 4, + MOSQ_OPT_SEND_MAXIMUM = 5, }; /* MQTT specification restricts client ids to a maximum of 23 characters */ @@ -1375,6 +1376,15 @@ 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 + * 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. + * This option is not valid for MQTT v3.1 or v3.1.1 clients. + * Note that if the broker being connected to sends a + * 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 * 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 @@ -1450,6 +1460,9 @@ libmosq_EXPORT int mosquitto_reconnect_delay_set(struct mosquitto *mosq, unsigne /* * Function: mosquitto_max_inflight_messages_set * + * This function is deprected. Use the function with the + * MOSQ_OPT_SEND_MAXIMUM option instead. + * * Set the number of QoS 1 and 2 messages that can be "in flight" at one time. * An in flight message is part way through its delivery flow. Attempts to send * further messages with will result in the messages being diff --git a/lib/mosquitto_internal.h b/lib/mosquitto_internal.h index f62cf3d356..49a8829b6a 100644 --- a/lib/mosquitto_internal.h +++ b/lib/mosquitto_internal.h @@ -278,14 +278,14 @@ struct mosquitto { bool reconnect_exponential_backoff; char threaded; struct mosquitto__packet *out_packet_last; - int inflight_messages; # ifdef WITH_SRV ares_channel achan; # endif #endif + int send_quota; int receive_quota; - int receive_maximum; - int max_inflight_messages; + uint16_t send_maximum; + uint16_t receive_maximum; #ifdef WITH_BROKER UT_hash_handle hh_id; diff --git a/lib/options.c b/lib/options.c index 053a1e4b69..fd31d57da4 100644 --- a/lib/options.c +++ b/lib/options.c @@ -322,6 +322,13 @@ int mosquitto_int_option(struct mosquitto *mosq, enum mosq_opt_t option, int val mosq->receive_maximum = value; break; + case MOSQ_OPT_SEND_MAXIMUM: + if(value < 0 || value > 65535){ + return MOSQ_ERR_INVAL; + } + mosq->send_maximum = value; + break; + case MOSQ_OPT_SSL_CTX_WITH_DEFAULTS: #if defined(WITH_TLS) && OPENSSL_VERSION_NUMBER >= 0x10100000L if(value){ diff --git a/lib/util_mosq.c b/lib/util_mosq.c index 1683a2e9a3..ca2b5077b1 100644 --- a/lib/util_mosq.c +++ b/lib/util_mosq.c @@ -261,3 +261,10 @@ void util__increment_receive_quota(struct mosquitto *mosq) } } } + +void util__increment_send_quota(struct mosquitto *mosq) +{ + if(mosq->send_quota < mosq->send_maximum){ + mosq->send_quota++; + } +} \ No newline at end of file diff --git a/lib/util_mosq.h b/lib/util_mosq.h index 62a14f2be8..6642a69735 100644 --- a/lib/util_mosq.h +++ b/lib/util_mosq.h @@ -38,4 +38,5 @@ int mosquitto__hex2bin(const char *hex, unsigned char *bin, int bin_max_len); #endif void util__increment_receive_quota(struct mosquitto *mosq); +void util__increment_send_quota(struct mosquitto *mosq); #endif diff --git a/src/context.c b/src/context.c index a93b8e3033..a6a5f49931 100644 --- a/src/context.c +++ b/src/context.c @@ -76,7 +76,8 @@ struct mosquitto *context__init(struct mosquitto_db *db, mosq_sock_t sock) context->last_inflight_msg = NULL; context->queued_msgs = NULL; context->last_queued_msg = NULL; - context->max_inflight_messages = db->config->max_inflight_messages; + context->receive_maximum = db->config->max_inflight_messages; + context->send_maximum = db->config->max_inflight_messages; context->msg_bytes = 0; context->msg_bytes12 = 0; context->msg_count = 0; diff --git a/src/database.c b/src/database.c index d93d3c0867..6fc2dc230f 100644 --- a/src/database.c +++ b/src/database.c @@ -37,14 +37,14 @@ static unsigned long max_queued_bytes = 0; */ static bool db__ready_for_flight(struct mosquitto *context, int qos) { - if(qos == 0 || (context->max_inflight_messages == 0 && max_inflight_bytes == 0)){ + if(qos == 0 || (context->send_maximum == 0 && max_inflight_bytes == 0)){ return true; } bool valid_bytes = context->msg_bytes12 < max_inflight_bytes; - bool valid_count = context->msg_count12 < context->max_inflight_messages; + bool valid_count = context->msg_count12 < context->send_maximum; - if(context->max_inflight_messages == 0){ + if(context->send_maximum == 0){ return valid_bytes; } if(max_inflight_bytes == 0){ @@ -72,7 +72,7 @@ static bool db__ready_for_queue(struct mosquitto *context, int qos) unsigned long source_bytes = context->msg_bytes12; int source_count = context->msg_count12; unsigned long adjust_bytes = max_inflight_bytes; - int adjust_count = context->max_inflight_messages; + int adjust_count = context->send_maximum; /* nothing in flight for offline clients */ if(context->sock == INVALID_SOCKET){ @@ -306,7 +306,7 @@ int db__message_delete(struct mosquitto_db *db, struct mosquitto *context, uint1 tail = tail->next; } } - while (context->queued_msgs && (context->max_inflight_messages == 0 || msg_index < context->max_inflight_messages)){ + while (context->queued_msgs && (context->send_maximum == 0 || msg_index < context->send_maximum)){ msg_index++; tail = context->queued_msgs; tail->timestamp = mosquitto_time(); @@ -837,7 +837,7 @@ int db__message_release(struct mosquitto_db *db, struct mosquitto *context, uint } } - while(context->queued_msgs && (context->max_inflight_messages == 0 || msg_index < context->max_inflight_messages)){ + while(context->queued_msgs && (context->send_maximum == 0 || msg_index < context->send_maximum)){ msg_index++; tail = context->queued_msgs; tail->timestamp = mosquitto_time(); @@ -988,7 +988,7 @@ int db__message_write(struct mosquitto_db *db, struct mosquitto *context) } } - while(context->queued_msgs && (context->max_inflight_messages == 0 || msg_count < context->max_inflight_messages)){ + while(context->queued_msgs && (context->send_maximum == 0 || msg_count < context->send_maximum)){ msg_count++; tail = context->queued_msgs; if(tail->direction == mosq_md_out){ diff --git a/src/property_broker.c b/src/property_broker.c index 57d17c9cea..ee76b2c418 100644 --- a/src/property_broker.c +++ b/src/property_broker.c @@ -40,11 +40,8 @@ int property__process_connect(struct mosquitto *context, mosquitto_property *pro return MOSQ_ERR_PROTOCOL; } - if(p->value.i16 == 65535){ - context->max_inflight_messages = 0; - }else{ - context->max_inflight_messages = p->value.i16; - } + context->send_maximum = p->value.i16; + context->send_quota = context->send_maximum; } p = p->next; } From aeba5b5d0dce4149bde04620e826694d5a04fa7a Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 9 Jan 2019 12:21:15 +0000 Subject: [PATCH 181/254] Fix and tests for client side receive-maximum. --- lib/handle_connack.c | 1 + .../03-publish-c2b-qos1-receive-maximum.py | 102 +++++++++++++++ .../03-publish-c2b-qos2-receive-maximum.py | 119 ++++++++++++++++++ test/lib/Makefile | 2 + .../c/03-publish-c2b-qos1-receive-maximum.c | 52 ++++++++ .../c/03-publish-c2b-qos2-receive-maximum.c | 52 ++++++++ test/lib/c/Makefile | 4 +- test/lib/ptest.py | 2 + 8 files changed, 333 insertions(+), 1 deletion(-) create mode 100755 test/lib/03-publish-c2b-qos1-receive-maximum.py create mode 100755 test/lib/03-publish-c2b-qos2-receive-maximum.py create mode 100644 test/lib/c/03-publish-c2b-qos1-receive-maximum.c create mode 100644 test/lib/c/03-publish-c2b-qos2-receive-maximum.c diff --git a/lib/handle_connack.c b/lib/handle_connack.c index 135e9b4c1c..df230419e2 100644 --- a/lib/handle_connack.c +++ b/lib/handle_connack.c @@ -63,6 +63,7 @@ int handle__connack(struct mosquitto *mosq) mosquitto_property_read_int16(properties, MQTT_PROP_SERVER_KEEP_ALIVE, &mosq->keepalive, false); mosquitto_property_read_int16(properties, MQTT_PROP_RECEIVE_MAXIMUM, &mosq->send_maximum, false); + mosq->send_quota = mosq->send_maximum; log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received CONNACK (%d)", mosq->id, reason_code); pthread_mutex_lock(&mosq->callback_mutex); diff --git a/test/lib/03-publish-c2b-qos1-receive-maximum.py b/test/lib/03-publish-c2b-qos1-receive-maximum.py new file mode 100755 index 0000000000..b55860ea74 --- /dev/null +++ b/test/lib/03-publish-c2b-qos1-receive-maximum.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python + +# Test whether a client responds correctly to multiple PUBLISH with QoS 1, with +# receive maximum set to 3. + +from mosq_test_helper import * + +port = mosq_test.get_lib_port() + +rc = 1 +keepalive = 60 +connect_packet = mosq_test.gen_connect("publish-qos1-test", keepalive=keepalive, proto_ver=5) + +props = mqtt5_props.gen_uint16_prop(mqtt5_props.PROP_RECEIVE_MAXIMUM, 3) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5, properties=props) + +disconnect_packet = mosq_test.gen_disconnect(proto_ver=5) + +mid = 1 +publish_1_packet = mosq_test.gen_publish("topic", qos=1, mid=mid, payload="12345", proto_ver=5) +puback_1_packet = mosq_test.gen_puback(mid, proto_ver=5) + +mid = 2 +publish_2_packet = mosq_test.gen_publish("topic", qos=1, mid=mid, payload="12345", proto_ver=5) +puback_2_packet = mosq_test.gen_puback(mid, proto_ver=5) + +mid = 3 +publish_3_packet = mosq_test.gen_publish("topic", qos=1, mid=mid, payload="12345", proto_ver=5) +puback_3_packet = mosq_test.gen_puback(mid, proto_ver=5) + +mid = 4 +publish_4_packet = mosq_test.gen_publish("topic", qos=1, mid=mid, payload="12345", proto_ver=5) +puback_4_packet = mosq_test.gen_puback(mid, proto_ver=5) + +mid = 5 +publish_5_packet = mosq_test.gen_publish("topic", qos=1, mid=mid, payload="12345", proto_ver=5) +puback_5_packet = mosq_test.gen_puback(mid, proto_ver=5) + +mid = 6 +publish_6_packet = mosq_test.gen_publish("topic", qos=1, mid=mid, payload="12345", proto_ver=5) +puback_6_packet = mosq_test.gen_puback(mid, 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) + + if mosq_test.expect_packet(conn, "publish 1", publish_1_packet): + if mosq_test.expect_packet(conn, "publish 2", publish_2_packet): + if mosq_test.expect_packet(conn, "publish 3", publish_3_packet): + conn.send(puback_1_packet) + conn.send(puback_2_packet) + + if mosq_test.expect_packet(conn, "publish 4", publish_4_packet): + if mosq_test.expect_packet(conn, "publish 5", publish_5_packet): + conn.send(puback_3_packet) + + if mosq_test.expect_packet(conn, "publish 6", publish_6_packet): + conn.send(puback_4_packet) + conn.send(puback_5_packet) + conn.send(puback_6_packet) + rc = 0 + + conn.close() +finally: + for i in range(0, 5): + if client.returncode != None: + break + time.sleep(0.1) + + try: + client.terminate() + except OSError: + pass + + client.wait() + sock.close() + if client.returncode != 0: + exit(1) + +exit(rc) diff --git a/test/lib/03-publish-c2b-qos2-receive-maximum.py b/test/lib/03-publish-c2b-qos2-receive-maximum.py new file mode 100755 index 0000000000..b2335a516c --- /dev/null +++ b/test/lib/03-publish-c2b-qos2-receive-maximum.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python + +# Test whether a client responds correctly to multiple PUBLISH with QoS 2, with +# receive maximum set to 2. + +from mosq_test_helper import * + +port = mosq_test.get_lib_port() + +rc = 1 +keepalive = 60 +connect_packet = mosq_test.gen_connect("publish-qos2-test", keepalive=keepalive, proto_ver=5) + +props = mqtt5_props.gen_uint16_prop(mqtt5_props.PROP_RECEIVE_MAXIMUM, 2) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5, properties=props) + +disconnect_packet = mosq_test.gen_disconnect(proto_ver=5) + +mid = 1 +publish_1_packet = mosq_test.gen_publish("topic", qos=2, mid=mid, payload="12345", proto_ver=5) +pubrec_1_packet = mosq_test.gen_pubrec(mid, proto_ver=5) +pubrel_1_packet = mosq_test.gen_pubrel(mid, proto_ver=5) +pubcomp_1_packet = mosq_test.gen_pubcomp(mid, proto_ver=5) + +mid = 2 +publish_2_packet = mosq_test.gen_publish("topic", qos=2, mid=mid, payload="12345", proto_ver=5) +pubrec_2_packet = mosq_test.gen_pubrec(mid, proto_ver=5) +pubrel_2_packet = mosq_test.gen_pubrel(mid, proto_ver=5) +pubcomp_2_packet = mosq_test.gen_pubcomp(mid, proto_ver=5) + +mid = 3 +publish_3_packet = mosq_test.gen_publish("topic", qos=2, mid=mid, payload="12345", proto_ver=5) +pubrec_3_packet = mosq_test.gen_pubrec(mid, proto_ver=5) +pubrel_3_packet = mosq_test.gen_pubrel(mid, proto_ver=5) +pubcomp_3_packet = mosq_test.gen_pubcomp(mid, proto_ver=5) + +mid = 4 +publish_4_packet = mosq_test.gen_publish("topic", qos=2, mid=mid, payload="12345", proto_ver=5) +pubrec_4_packet = mosq_test.gen_pubrec(mid, proto_ver=5) +pubrel_4_packet = mosq_test.gen_pubrel(mid, proto_ver=5) +pubcomp_4_packet = mosq_test.gen_pubcomp(mid, proto_ver=5) + +mid = 5 +publish_5_packet = mosq_test.gen_publish("topic", qos=2, mid=mid, payload="12345", proto_ver=5) +pubrec_5_packet = mosq_test.gen_pubrec(mid, proto_ver=5) +pubrel_5_packet = mosq_test.gen_pubrel(mid, proto_ver=5) +pubcomp_5_packet = mosq_test.gen_pubcomp(mid, 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) + + if mosq_test.expect_packet(conn, "publish 1", publish_1_packet): + if mosq_test.expect_packet(conn, "publish 2", publish_2_packet): + conn.send(pubrec_1_packet) + conn.send(pubrec_2_packet) + + if mosq_test.expect_packet(conn, "pubrel 1", pubrel_1_packet): + if mosq_test.expect_packet(conn, "pubrel 2", pubrel_2_packet): + conn.send(pubcomp_1_packet) + conn.send(pubcomp_2_packet) + + if mosq_test.expect_packet(conn, "publish 3", publish_3_packet): + if mosq_test.expect_packet(conn, "publish 4", publish_4_packet): + conn.send(pubrec_3_packet) + conn.send(pubrec_4_packet) + + if mosq_test.expect_packet(conn, "pubrel 3", pubrel_3_packet): + if mosq_test.expect_packet(conn, "pubrel 4", pubrel_4_packet): + conn.send(pubcomp_3_packet) + conn.send(pubcomp_4_packet) + + if mosq_test.expect_packet(conn, "publish 5", publish_5_packet): + conn.send(pubrec_5_packet) + + if mosq_test.expect_packet(conn, "pubrel 5", pubrel_5_packet): + conn.send(pubcomp_5_packet) + rc = 0 + + conn.close() +finally: + for i in range(0, 5): + if client.returncode != None: + break + time.sleep(0.1) + + try: + client.terminate() + except OSError: + pass + + client.wait() + sock.close() + if client.returncode != 0: + exit(1) + +exit(rc) diff --git a/test/lib/Makefile b/test/lib/Makefile index e9b0c54c6b..2d4cba9232 100644 --- a/test/lib/Makefile +++ b/test/lib/Makefile @@ -36,6 +36,8 @@ c : test-compile ./03-publish-c2b-qos1-disconnect.py $@/03-publish-c2b-qos1-disconnect.test ./03-publish-c2b-qos2.py $@/03-publish-c2b-qos2.test ./03-publish-c2b-qos2-disconnect.py $@/03-publish-c2b-qos2-disconnect.test + ./03-publish-c2b-qos1-receive-maximum.py $@/03-publish-c2b-qos1-receive-maximum.test + ./03-publish-c2b-qos2-receive-maximum.py $@/03-publish-c2b-qos2-receive-maximum.test ./03-publish-b2c-qos1.py $@/03-publish-b2c-qos1.test ./03-publish-b2c-qos2.py $@/03-publish-b2c-qos2.test ./03-request-response.py $@/03-request-response.test diff --git a/test/lib/c/03-publish-c2b-qos1-receive-maximum.c b/test/lib/c/03-publish-c2b-qos1-receive-maximum.c new file mode 100644 index 0000000000..e2d351cc40 --- /dev/null +++ b/test/lib/c/03-publish-c2b-qos1-receive-maximum.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include + +static int run = -1; + +void on_connect(struct mosquitto *mosq, void *obj, int rc, int flags, const mosquitto_property *properties) +{ + if(rc){ + exit(1); + } + + for(int i=0; i<6; i++){ + mosquitto_publish_v5(mosq, NULL, "topic", 5, "12345", 1, false, NULL); + } +} + +void on_publish(struct mosquitto *mosq, void *obj, int mid, const mosquitto_property *properties) +{ + if(mid == 6){ + mosquitto_disconnect(mosq); + run = 0; + } +} + +int main(int argc, char *argv[]) +{ + int rc; + struct mosquitto *mosq; + mosquitto_property *props = NULL; + + int port = atoi(argv[1]); + + mosquitto_lib_init(); + + mosq = mosquitto_new("publish-qos1-test", true, &run); + mosquitto_int_option(mosq, MOSQ_OPT_PROTOCOL_VERSION, MQTT_PROTOCOL_V5); + + mosquitto_connect_v5_callback_set(mosq, on_connect); + mosquitto_publish_v5_callback_set(mosq, on_publish); + + rc = mosquitto_connect_bind_v5(mosq, "localhost", port, 60, NULL, NULL); + + while(run == -1){ + mosquitto_loop(mosq, 300, 1); + } + + mosquitto_lib_cleanup(); + return run; +} diff --git a/test/lib/c/03-publish-c2b-qos2-receive-maximum.c b/test/lib/c/03-publish-c2b-qos2-receive-maximum.c new file mode 100644 index 0000000000..a4b8e2a235 --- /dev/null +++ b/test/lib/c/03-publish-c2b-qos2-receive-maximum.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include + +static int run = -1; + +void on_connect(struct mosquitto *mosq, void *obj, int rc, int flags, const mosquitto_property *properties) +{ + if(rc){ + exit(1); + } + + for(int i=0; i<5; i++){ + mosquitto_publish_v5(mosq, NULL, "topic", 5, "12345", 2, false, NULL); + } +} + +void on_publish(struct mosquitto *mosq, void *obj, int mid, const mosquitto_property *properties) +{ + if(mid == 5){ + mosquitto_disconnect(mosq); + run = 0; + } +} + +int main(int argc, char *argv[]) +{ + int rc; + struct mosquitto *mosq; + mosquitto_property *props = NULL; + + int port = atoi(argv[1]); + + mosquitto_lib_init(); + + mosq = mosquitto_new("publish-qos2-test", true, &run); + mosquitto_int_option(mosq, MOSQ_OPT_PROTOCOL_VERSION, MQTT_PROTOCOL_V5); + + mosquitto_connect_v5_callback_set(mosq, on_connect); + mosquitto_publish_v5_callback_set(mosq, on_publish); + + rc = mosquitto_connect_bind_v5(mosq, "localhost", port, 60, NULL, NULL); + + while(run == -1){ + mosquitto_loop(mosq, 300, 1); + } + + mosquitto_lib_cleanup(); + return run; +} diff --git a/test/lib/c/Makefile b/test/lib/c/Makefile index 0986b528dc..69dc56a3a4 100644 --- a/test/lib/c/Makefile +++ b/test/lib/c/Makefile @@ -19,11 +19,13 @@ SRC = \ 03-publish-c2b-qos1-disconnect.c \ 03-publish-c2b-qos2.c \ 03-publish-c2b-qos2-disconnect.c \ + 03-publish-c2b-qos1-receive-maximum.c \ + 03-publish-c2b-qos2-receive-maximum.c \ 03-publish-b2c-qos1.c \ + 03-publish-b2c-qos2.c \ 03-request-response-1.c \ 03-request-response-2.c \ 03-request-response-correlation-1.c \ - 03-publish-b2c-qos2.c \ 04-retain-qos0.c \ 08-ssl-connect-no-auth.c \ 08-ssl-connect-cert-auth.c \ diff --git a/test/lib/ptest.py b/test/lib/ptest.py index 64990e5e95..34b5332323 100755 --- a/test/lib/ptest.py +++ b/test/lib/ptest.py @@ -21,6 +21,8 @@ ('./03-publish-c2b-qos1-disconnect.py', 'c/03-publish-c2b-qos1-disconnect.test'), ('./03-publish-c2b-qos2-disconnect.py', 'c/03-publish-c2b-qos2-disconnect.test'), ('./03-publish-c2b-qos2.py', 'c/03-publish-c2b-qos2.test'), + ('./03-publish-c2b-qos1-receive-maximum.py', 'c/03-publish-c2b-qos1-receive-maximum.test'), + ('./03-publish-c2b-qos2-receive-maximum.py', 'c/03-publish-c2b-qos2-receive-maximum.test'), ('./03-publish-qos0-no-payload.py', 'c/03-publish-qos0-no-payload.test'), ('./03-publish-qos0.py', 'c/03-publish-qos0.test'), ('./03-request-response.py', 'c/03-request-response.test'), From 6119f835713ed4df5ccc0795387aafa7a25ff18f Mon Sep 17 00:00:00 2001 From: Roger Light Date: Wed, 9 Jan 2019 13:56:15 +0000 Subject: [PATCH 182/254] Add receive-maximum=1 test for client. --- .../03-publish-c2b-qos2-receive-maximum-1.py | 118 ++++++++++++++++++ ... 03-publish-c2b-qos2-receive-maximum-2.py} | 0 test/lib/Makefile | 3 +- ...> 03-publish-c2b-qos2-receive-maximum-1.c} | 0 .../c/03-publish-c2b-qos2-receive-maximum-2.c | 52 ++++++++ test/lib/c/Makefile | 3 +- test/lib/ptest.py | 3 +- 7 files changed, 176 insertions(+), 3 deletions(-) create mode 100755 test/lib/03-publish-c2b-qos2-receive-maximum-1.py rename test/lib/{03-publish-c2b-qos2-receive-maximum.py => 03-publish-c2b-qos2-receive-maximum-2.py} (100%) rename test/lib/c/{03-publish-c2b-qos2-receive-maximum.c => 03-publish-c2b-qos2-receive-maximum-1.c} (100%) create mode 100644 test/lib/c/03-publish-c2b-qos2-receive-maximum-2.c diff --git a/test/lib/03-publish-c2b-qos2-receive-maximum-1.py b/test/lib/03-publish-c2b-qos2-receive-maximum-1.py new file mode 100755 index 0000000000..cb27cf55f3 --- /dev/null +++ b/test/lib/03-publish-c2b-qos2-receive-maximum-1.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python + +# Test whether a client responds correctly to multiple PUBLISH with QoS 2, with +# receive maximum set to 1. + +from mosq_test_helper import * + +port = mosq_test.get_lib_port() + +rc = 1 +keepalive = 60 +connect_packet = mosq_test.gen_connect("publish-qos2-test", keepalive=keepalive, proto_ver=5) + +props = mqtt5_props.gen_uint16_prop(mqtt5_props.PROP_RECEIVE_MAXIMUM, 1) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5, properties=props) + +disconnect_packet = mosq_test.gen_disconnect(proto_ver=5) + +mid = 1 +publish_1_packet = mosq_test.gen_publish("topic", qos=2, mid=mid, payload="12345", proto_ver=5) +pubrec_1_packet = mosq_test.gen_pubrec(mid, proto_ver=5) +pubrel_1_packet = mosq_test.gen_pubrel(mid, proto_ver=5) +pubcomp_1_packet = mosq_test.gen_pubcomp(mid, proto_ver=5) + +mid = 2 +publish_2_packet = mosq_test.gen_publish("topic", qos=2, mid=mid, payload="12345", proto_ver=5) +pubrec_2_packet = mosq_test.gen_pubrec(mid, proto_ver=5) +pubrel_2_packet = mosq_test.gen_pubrel(mid, proto_ver=5) +pubcomp_2_packet = mosq_test.gen_pubcomp(mid, proto_ver=5) + +mid = 3 +publish_3_packet = mosq_test.gen_publish("topic", qos=2, mid=mid, payload="12345", proto_ver=5) +pubrec_3_packet = mosq_test.gen_pubrec(mid, proto_ver=5) +pubrel_3_packet = mosq_test.gen_pubrel(mid, proto_ver=5) +pubcomp_3_packet = mosq_test.gen_pubcomp(mid, proto_ver=5) + +mid = 4 +publish_4_packet = mosq_test.gen_publish("topic", qos=2, mid=mid, payload="12345", proto_ver=5) +pubrec_4_packet = mosq_test.gen_pubrec(mid, proto_ver=5) +pubrel_4_packet = mosq_test.gen_pubrel(mid, proto_ver=5) +pubcomp_4_packet = mosq_test.gen_pubcomp(mid, proto_ver=5) + +mid = 5 +publish_5_packet = mosq_test.gen_publish("topic", qos=2, mid=mid, payload="12345", proto_ver=5) +pubrec_5_packet = mosq_test.gen_pubrec(mid, proto_ver=5) +pubrel_5_packet = mosq_test.gen_pubrel(mid, proto_ver=5) +pubcomp_5_packet = mosq_test.gen_pubcomp(mid, 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) + + if mosq_test.expect_packet(conn, "publish 1", publish_1_packet): + conn.send(pubrec_1_packet) + if mosq_test.expect_packet(conn, "pubrel 1", pubrel_1_packet): + conn.send(pubcomp_1_packet) + + if mosq_test.expect_packet(conn, "publish 2", publish_2_packet): + conn.send(pubrec_2_packet) + if mosq_test.expect_packet(conn, "pubrel 2", pubrel_2_packet): + conn.send(pubcomp_2_packet) + + if mosq_test.expect_packet(conn, "publish 3", publish_3_packet): + conn.send(pubrec_3_packet) + if mosq_test.expect_packet(conn, "pubrel 3", pubrel_3_packet): + conn.send(pubcomp_3_packet) + + if mosq_test.expect_packet(conn, "publish 4", publish_4_packet): + conn.send(pubrec_4_packet) + if mosq_test.expect_packet(conn, "pubrel 4", pubrel_4_packet): + conn.send(pubcomp_4_packet) + + if mosq_test.expect_packet(conn, "publish 5", publish_5_packet): + conn.send(pubrec_5_packet) + if mosq_test.expect_packet(conn, "pubrel 5", pubrel_5_packet): + conn.send(pubcomp_5_packet) + rc = 0 + + conn.close() +finally: + for i in range(0, 5): + if client.returncode != None: + break + time.sleep(0.1) + + try: + client.terminate() + except OSError: + pass + + client.wait() + sock.close() + if client.returncode != 0: + exit(1) + +exit(rc) diff --git a/test/lib/03-publish-c2b-qos2-receive-maximum.py b/test/lib/03-publish-c2b-qos2-receive-maximum-2.py similarity index 100% rename from test/lib/03-publish-c2b-qos2-receive-maximum.py rename to test/lib/03-publish-c2b-qos2-receive-maximum-2.py diff --git a/test/lib/Makefile b/test/lib/Makefile index 2d4cba9232..f7eb88589a 100644 --- a/test/lib/Makefile +++ b/test/lib/Makefile @@ -37,7 +37,8 @@ c : test-compile ./03-publish-c2b-qos2.py $@/03-publish-c2b-qos2.test ./03-publish-c2b-qos2-disconnect.py $@/03-publish-c2b-qos2-disconnect.test ./03-publish-c2b-qos1-receive-maximum.py $@/03-publish-c2b-qos1-receive-maximum.test - ./03-publish-c2b-qos2-receive-maximum.py $@/03-publish-c2b-qos2-receive-maximum.test + ./03-publish-c2b-qos2-receive-maximum-1.py $@/03-publish-c2b-qos2-receive-maximum-1.test + ./03-publish-c2b-qos2-receive-maximum-2.py $@/03-publish-c2b-qos2-receive-maximum-2.test ./03-publish-b2c-qos1.py $@/03-publish-b2c-qos1.test ./03-publish-b2c-qos2.py $@/03-publish-b2c-qos2.test ./03-request-response.py $@/03-request-response.test diff --git a/test/lib/c/03-publish-c2b-qos2-receive-maximum.c b/test/lib/c/03-publish-c2b-qos2-receive-maximum-1.c similarity index 100% rename from test/lib/c/03-publish-c2b-qos2-receive-maximum.c rename to test/lib/c/03-publish-c2b-qos2-receive-maximum-1.c diff --git a/test/lib/c/03-publish-c2b-qos2-receive-maximum-2.c b/test/lib/c/03-publish-c2b-qos2-receive-maximum-2.c new file mode 100644 index 0000000000..a4b8e2a235 --- /dev/null +++ b/test/lib/c/03-publish-c2b-qos2-receive-maximum-2.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include + +static int run = -1; + +void on_connect(struct mosquitto *mosq, void *obj, int rc, int flags, const mosquitto_property *properties) +{ + if(rc){ + exit(1); + } + + for(int i=0; i<5; i++){ + mosquitto_publish_v5(mosq, NULL, "topic", 5, "12345", 2, false, NULL); + } +} + +void on_publish(struct mosquitto *mosq, void *obj, int mid, const mosquitto_property *properties) +{ + if(mid == 5){ + mosquitto_disconnect(mosq); + run = 0; + } +} + +int main(int argc, char *argv[]) +{ + int rc; + struct mosquitto *mosq; + mosquitto_property *props = NULL; + + int port = atoi(argv[1]); + + mosquitto_lib_init(); + + mosq = mosquitto_new("publish-qos2-test", true, &run); + mosquitto_int_option(mosq, MOSQ_OPT_PROTOCOL_VERSION, MQTT_PROTOCOL_V5); + + mosquitto_connect_v5_callback_set(mosq, on_connect); + mosquitto_publish_v5_callback_set(mosq, on_publish); + + rc = mosquitto_connect_bind_v5(mosq, "localhost", port, 60, NULL, NULL); + + while(run == -1){ + mosquitto_loop(mosq, 300, 1); + } + + mosquitto_lib_cleanup(); + return run; +} diff --git a/test/lib/c/Makefile b/test/lib/c/Makefile index 69dc56a3a4..289d33d6cf 100644 --- a/test/lib/c/Makefile +++ b/test/lib/c/Makefile @@ -20,7 +20,8 @@ SRC = \ 03-publish-c2b-qos2.c \ 03-publish-c2b-qos2-disconnect.c \ 03-publish-c2b-qos1-receive-maximum.c \ - 03-publish-c2b-qos2-receive-maximum.c \ + 03-publish-c2b-qos2-receive-maximum-1.c \ + 03-publish-c2b-qos2-receive-maximum-2.c \ 03-publish-b2c-qos1.c \ 03-publish-b2c-qos2.c \ 03-request-response-1.c \ diff --git a/test/lib/ptest.py b/test/lib/ptest.py index 34b5332323..56d478bc5d 100755 --- a/test/lib/ptest.py +++ b/test/lib/ptest.py @@ -22,7 +22,8 @@ ('./03-publish-c2b-qos2-disconnect.py', 'c/03-publish-c2b-qos2-disconnect.test'), ('./03-publish-c2b-qos2.py', 'c/03-publish-c2b-qos2.test'), ('./03-publish-c2b-qos1-receive-maximum.py', 'c/03-publish-c2b-qos1-receive-maximum.test'), - ('./03-publish-c2b-qos2-receive-maximum.py', 'c/03-publish-c2b-qos2-receive-maximum.test'), + ('./03-publish-c2b-qos2-receive-maximum-1.py', 'c/03-publish-c2b-qos2-receive-maximum-1.test'), + ('./03-publish-c2b-qos2-receive-maximum-2.py', 'c/03-publish-c2b-qos2-receive-maximum-2.test'), ('./03-publish-qos0-no-payload.py', 'c/03-publish-qos0-no-payload.test'), ('./03-publish-qos0.py', 'c/03-publish-qos0.test'), ('./03-request-response.py', 'c/03-request-response.test'), From 740a128769d23a72579bc28b057cdfb30a22c3c7 Mon Sep 17 00:00:00 2001 From: Roger Light Date: Wed, 9 Jan 2019 15:00:12 +0000 Subject: [PATCH 183/254] Support PUBREC reason code >=0x80 as partial qos2 flow. --- lib/handle_pubrec.c | 17 +++- lib/read_handle.c | 2 +- lib/read_handle.h | 2 +- src/read_handle.c | 2 +- .../02-subpub-qos2-pubrec-error-helper.py | 36 ++++++++ test/broker/02-subpub-qos2-pubrec-error.py | 54 ++++++++++++ test/broker/Makefile | 1 + test/broker/ptest.py | 1 + test/lib/03-publish-c2b-qos2-pubrec-error.py | 85 +++++++++++++++++++ test/lib/Makefile | 1 + test/lib/c/03-publish-c2b-qos2-pubrec-error.c | 49 +++++++++++ test/lib/c/Makefile | 1 + test/lib/ptest.py | 1 + 13 files changed, 245 insertions(+), 7 deletions(-) create mode 100755 test/broker/02-subpub-qos2-pubrec-error-helper.py create mode 100755 test/broker/02-subpub-qos2-pubrec-error.py create mode 100755 test/lib/03-publish-c2b-qos2-pubrec-error.py create mode 100644 test/lib/c/03-publish-c2b-qos2-pubrec-error.c diff --git a/lib/handle_pubrec.c b/lib/handle_pubrec.c index 56879265c5..589b405a2b 100644 --- a/lib/handle_pubrec.c +++ b/lib/handle_pubrec.c @@ -35,9 +35,9 @@ and the Eclipse Distribution License is available at #include "send_mosq.h" #include "util_mosq.h" -int handle__pubrec(struct mosquitto *mosq) +int handle__pubrec(struct mosquitto_db *db, struct mosquitto *mosq) { - uint8_t reason_code; + uint8_t reason_code = 0; uint16_t mid; int rc; mosquitto_property *properties = NULL; @@ -60,11 +60,20 @@ int handle__pubrec(struct mosquitto *mosq) #ifdef WITH_BROKER log__printf(NULL, MOSQ_LOG_DEBUG, "Received PUBREC from %s (Mid: %d)", mosq->id, mid); - rc = db__message_update(mosq, mid, mosq_md_out, mosq_ms_wait_for_pubcomp); + if(reason_code < 0x80){ + rc = db__message_update(mosq, mid, mosq_md_out, mosq_ms_wait_for_pubcomp); + }else{ + return db__message_delete(db, mosq, mid, mosq_md_out); + } #else log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received PUBREC (Mid: %d)", mosq->id, mid); - rc = message__out_update(mosq, mid, mosq_ms_wait_for_pubcomp); + if(reason_code < 0x80){ + rc = message__out_update(mosq, mid, mosq_ms_wait_for_pubcomp); + }else{ + message__delete(mosq, mid, mosq_md_out); + return MOSQ_ERR_SUCCESS; + } #endif if(rc == MOSQ_ERR_NOT_FOUND){ log__printf(mosq, MOSQ_LOG_WARNING, "Warning: Received PUBREC from %s for an unknown packet identifier %d.", mosq->id, mid); diff --git a/lib/read_handle.c b/lib/read_handle.c index 991a7dbcf4..28c0e66bd5 100644 --- a/lib/read_handle.c +++ b/lib/read_handle.c @@ -48,7 +48,7 @@ int handle__packet(struct mosquitto *mosq) case CMD_PUBLISH: return handle__publish(mosq); case CMD_PUBREC: - return handle__pubrec(mosq); + return handle__pubrec(NULL, mosq); case CMD_PUBREL: return handle__pubrel(NULL, mosq); case CMD_CONNACK: diff --git a/lib/read_handle.h b/lib/read_handle.h index e0e17c945b..d1c46cfd44 100644 --- a/lib/read_handle.h +++ b/lib/read_handle.h @@ -31,7 +31,7 @@ int handle__pubackcomp(struct mosquitto *mosq, const char *type); int handle__publish(struct mosquitto *mosq); int handle__auth(struct mosquitto *mosq); #endif -int handle__pubrec(struct mosquitto *mosq); +int handle__pubrec(struct mosquitto_db *db, struct mosquitto *mosq); int handle__pubrel(struct mosquitto_db *db, struct mosquitto *mosq); int handle__suback(struct mosquitto *mosq); int handle__unsuback(struct mosquitto *mosq); diff --git a/src/read_handle.c b/src/read_handle.c index 72144ce8cb..f71a76f999 100644 --- a/src/read_handle.c +++ b/src/read_handle.c @@ -46,7 +46,7 @@ int handle__packet(struct mosquitto_db *db, struct mosquitto *context) case CMD_PUBLISH: return handle__publish(db, context); case CMD_PUBREC: - return handle__pubrec(context); + return handle__pubrec(db, context); case CMD_PUBREL: return handle__pubrel(db, context); case CMD_CONNECT: diff --git a/test/broker/02-subpub-qos2-pubrec-error-helper.py b/test/broker/02-subpub-qos2-pubrec-error-helper.py new file mode 100755 index 0000000000..4d1bbc93ad --- /dev/null +++ b/test/broker/02-subpub-qos2-pubrec-error-helper.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python + +from mosq_test_helper import * + +rc = 1 +keepalive = 60 +connect_packet = mosq_test.gen_connect("test-helper", keepalive=keepalive) +connack_packet = mosq_test.gen_connack(rc=0) + +mid = 1 +publish_1_packet = mosq_test.gen_publish("qos2/pubrec/rejected", qos=2, mid=mid, payload="rejected-message") +pubrec_1_packet = mosq_test.gen_pubrec(mid) +pubrel_1_packet = mosq_test.gen_pubrel(mid) +pubcomp_1_packet = mosq_test.gen_pubcomp(mid) + +mid = 2 +publish_2_packet = mosq_test.gen_publish("qos2/pubrec/accepted", qos=2, mid=mid, payload="accepted-message") +pubrec_2_packet = mosq_test.gen_pubrec(mid) +pubrel_2_packet = mosq_test.gen_pubrel(mid) +pubcomp_2_packet = mosq_test.gen_pubcomp(mid) + +port = mosq_test.get_port() +sock = mosq_test.do_client_connect(connect_packet, connack_packet, connack_error="helper connack", port=port) + +mosq_test.do_send_receive(sock, publish_1_packet, pubrec_1_packet, "helper pubrec") +mosq_test.do_send_receive(sock, pubrel_1_packet, pubcomp_1_packet, "helper pubcomp") + +mosq_test.do_send_receive(sock, publish_2_packet, pubrec_2_packet, "helper pubrec") +mosq_test.do_send_receive(sock, pubrel_2_packet, pubcomp_2_packet, "helper pubcomp") + +rc = 0 + +sock.close() + +exit(rc) + diff --git a/test/broker/02-subpub-qos2-pubrec-error.py b/test/broker/02-subpub-qos2-pubrec-error.py new file mode 100755 index 0000000000..2e3b3d34fb --- /dev/null +++ b/test/broker/02-subpub-qos2-pubrec-error.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python + +# Test whether a PUBREC with reason code >= 0x80 is handled correctly + +from mosq_test_helper import * + +rc = 1 +keepalive = 60 +connect_packet = mosq_test.gen_connect("pub-qo2-timeout-test", keepalive=keepalive, proto_ver=5) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +mid = 1 +subscribe_packet = mosq_test.gen_subscribe(mid, "qos2/pubrec/+", 2, proto_ver=5) +suback_packet = mosq_test.gen_suback(mid, 2, proto_ver=5) + +mid = 1 +publish_1_packet = mosq_test.gen_publish("qos2/pubrec/rejected", qos=2, mid=mid, payload="rejected-message", proto_ver=5) +pubrec_1_packet = mosq_test.gen_pubrec(mid, proto_ver=5, reason_code=0x80) + +mid = 2 +publish_2_packet = mosq_test.gen_publish("qos2/pubrec/accepted", qos=2, mid=mid, payload="accepted-message", proto_ver=5) +pubrec_2_packet = mosq_test.gen_pubrec(mid, proto_ver=5) +pubrel_2_packet = mosq_test.gen_pubrel(mid, proto_ver=5) +pubcomp_2_packet = mosq_test.gen_pubcomp(mid, proto_ver=5) + +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, port=port) + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback") + pub = subprocess.Popen(['./02-subpub-qos2-pubrec-error-helper.py', str(port)], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + pub.wait() + (stdo, stde) = pub.communicate() + # Should have now received a publish command + + if mosq_test.expect_packet(sock, "publish 1", publish_1_packet): + sock.send(pubrec_1_packet) + + if mosq_test.expect_packet(sock, "publish 2", publish_2_packet): + mosq_test.do_send_receive(sock, pubrec_2_packet, pubrel_2_packet, "pubrel 2") + sock.send(pubcomp_2_packet) + rc = 0 + + sock.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index 8d9043d1a9..7583026f71 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -58,6 +58,7 @@ endif ./02-subpub-qos0-subscription-id.py ./02-subpub-qos2-receive-maximum-1.py ./02-subpub-qos2-receive-maximum-2.py + ./02-subpub-qos2-pubrec-error.py ./02-unsubscribe-qos0.py ./02-unsubscribe-qos1.py ./02-unsubscribe-qos2.py diff --git a/test/broker/ptest.py b/test/broker/ptest.py index 406dfe67f8..fbaf48f805 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -41,6 +41,7 @@ (1, './02-subpub-qos0-subscription-id.py'), (1, './02-subpub-qos2-receive-maximum-1.py'), (1, './02-subpub-qos2-receive-maximum-2.py'), + (1, './02-subpub-qos2-pubrec-error.py'), (1, './02-unsubscribe-qos0.py'), (1, './02-unsubscribe-qos1.py'), (1, './02-unsubscribe-qos2.py'), diff --git a/test/lib/03-publish-c2b-qos2-pubrec-error.py b/test/lib/03-publish-c2b-qos2-pubrec-error.py new file mode 100755 index 0000000000..58021bd468 --- /dev/null +++ b/test/lib/03-publish-c2b-qos2-pubrec-error.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python + +# Test whether a client responds correctly when sending multiple PUBLISH with +# QoS 2, with the broker rejecting the first PUBLISH by setting the reason code +# in PUBACK to >= 0x80. + +from mosq_test_helper import * + +port = mosq_test.get_lib_port() + +rc = 1 +keepalive = 60 +connect_packet = mosq_test.gen_connect("publish-qos2-test", keepalive=keepalive, proto_ver=5) + +props = mqtt5_props.gen_uint16_prop(mqtt5_props.PROP_RECEIVE_MAXIMUM, 1) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5, properties=props) + +disconnect_packet = mosq_test.gen_disconnect(proto_ver=5) + +mid = 1 +publish_1_packet = mosq_test.gen_publish("topic", qos=2, mid=mid, payload="rejected", proto_ver=5) +pubrec_1_packet = mosq_test.gen_pubrec(mid, proto_ver=5, reason_code=0x80) + +mid = 2 +publish_2_packet = mosq_test.gen_publish("topic", qos=2, mid=mid, payload="accepted", proto_ver=5) +pubrec_2_packet = mosq_test.gen_pubrec(mid, proto_ver=5) +pubrel_2_packet = mosq_test.gen_pubrel(mid, proto_ver=5) +pubcomp_2_packet = mosq_test.gen_pubcomp(mid, 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) + + if mosq_test.expect_packet(conn, "publish 1", publish_1_packet): + conn.send(pubrec_1_packet) + + if mosq_test.expect_packet(conn, "publish 2", publish_2_packet): + conn.send(pubrec_2_packet) + + if mosq_test.expect_packet(conn, "pubrel 2", pubrel_2_packet): + conn.send(pubcomp_2_packet) + rc = 0 + + conn.close() +finally: + for i in range(0, 5): + if client.returncode != None: + break + time.sleep(0.1) + + try: + client.terminate() + except OSError: + pass + + client.wait() + sock.close() + if client.returncode != 0: + exit(1) + +exit(rc) diff --git a/test/lib/Makefile b/test/lib/Makefile index f7eb88589a..c91a1fa932 100644 --- a/test/lib/Makefile +++ b/test/lib/Makefile @@ -39,6 +39,7 @@ c : test-compile ./03-publish-c2b-qos1-receive-maximum.py $@/03-publish-c2b-qos1-receive-maximum.test ./03-publish-c2b-qos2-receive-maximum-1.py $@/03-publish-c2b-qos2-receive-maximum-1.test ./03-publish-c2b-qos2-receive-maximum-2.py $@/03-publish-c2b-qos2-receive-maximum-2.test + ./03-publish-c2b-qos2-pubrec-error.py $@/03-publish-c2b-qos2-pubrec-error.test ./03-publish-b2c-qos1.py $@/03-publish-b2c-qos1.test ./03-publish-b2c-qos2.py $@/03-publish-b2c-qos2.test ./03-request-response.py $@/03-request-response.test diff --git a/test/lib/c/03-publish-c2b-qos2-pubrec-error.c b/test/lib/c/03-publish-c2b-qos2-pubrec-error.c new file mode 100644 index 0000000000..9f454c02de --- /dev/null +++ b/test/lib/c/03-publish-c2b-qos2-pubrec-error.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include +#include + +static int run = -1; + +void on_connect(struct mosquitto *mosq, void *obj, int rc, int flags, const mosquitto_property *properties) +{ + if(rc){ + exit(1); + } + mosquitto_publish_v5(mosq, NULL, "topic", strlen("rejected"), "rejected", 2, false, NULL); + mosquitto_publish_v5(mosq, NULL, "topic", strlen("accepted"), "accepted", 2, false, NULL); +} + +void on_publish(struct mosquitto *mosq, void *obj, int mid, const mosquitto_property *properties) +{ + if(mid == 2){ + run = 0; + } +} + +int main(int argc, char *argv[]) +{ + int rc; + struct mosquitto *mosq; + mosquitto_property *props = NULL; + + int port = atoi(argv[1]); + + mosquitto_lib_init(); + + mosq = mosquitto_new("publish-qos2-test", true, &run); + mosquitto_int_option(mosq, MOSQ_OPT_PROTOCOL_VERSION, MQTT_PROTOCOL_V5); + + mosquitto_connect_v5_callback_set(mosq, on_connect); + mosquitto_publish_v5_callback_set(mosq, on_publish); + + rc = mosquitto_connect_bind_v5(mosq, "localhost", port, 60, NULL, NULL); + + while(run == -1){ + mosquitto_loop(mosq, 100, 1); + } + + mosquitto_lib_cleanup(); + return run; +} diff --git a/test/lib/c/Makefile b/test/lib/c/Makefile index 289d33d6cf..936da2a254 100644 --- a/test/lib/c/Makefile +++ b/test/lib/c/Makefile @@ -22,6 +22,7 @@ SRC = \ 03-publish-c2b-qos1-receive-maximum.c \ 03-publish-c2b-qos2-receive-maximum-1.c \ 03-publish-c2b-qos2-receive-maximum-2.c \ + 03-publish-c2b-qos2-pubrec-error.c \ 03-publish-b2c-qos1.c \ 03-publish-b2c-qos2.c \ 03-request-response-1.c \ diff --git a/test/lib/ptest.py b/test/lib/ptest.py index 56d478bc5d..9b7e4fab3f 100755 --- a/test/lib/ptest.py +++ b/test/lib/ptest.py @@ -24,6 +24,7 @@ ('./03-publish-c2b-qos1-receive-maximum.py', 'c/03-publish-c2b-qos1-receive-maximum.test'), ('./03-publish-c2b-qos2-receive-maximum-1.py', 'c/03-publish-c2b-qos2-receive-maximum-1.test'), ('./03-publish-c2b-qos2-receive-maximum-2.py', 'c/03-publish-c2b-qos2-receive-maximum-2.test'), + ('./03-publish-c2b-qos2-pubrec-error.py', 'c/03-publish-c2b-qos2-pubrec-error.test'), ('./03-publish-qos0-no-payload.py', 'c/03-publish-qos0-no-payload.test'), ('./03-publish-qos0.py', 'c/03-publish-qos0.test'), ('./03-request-response.py', 'c/03-request-response.test'), From 930a314caf08cf74f70af4c3ffe59544480e68cc Mon Sep 17 00:00:00 2001 From: Roger Light Date: Wed, 9 Jan 2019 15:48:17 +0000 Subject: [PATCH 184/254] Add reason_code to on_publish_v5 callback. --- client/pub_client.c | 2 +- client/pub_shared.c | 2 +- client/pub_shared.h | 2 +- client/sub_client.c | 4 ++-- lib/callbacks.c | 2 +- lib/handle_pubackcomp.c | 4 ++-- lib/mosquitto.h | 3 ++- lib/mosquitto_internal.h | 2 +- lib/packet_mosq.c | 2 +- test/lib/c/03-publish-c2b-qos1-receive-maximum.c | 2 +- test/lib/c/03-publish-c2b-qos2-pubrec-error.c | 2 +- test/lib/c/03-publish-c2b-qos2-receive-maximum-1.c | 2 +- test/lib/c/03-publish-c2b-qos2-receive-maximum-2.c | 2 +- 13 files changed, 16 insertions(+), 15 deletions(-) diff --git a/client/pub_client.c b/client/pub_client.c index 4c9c75d558..db4deded1c 100644 --- a/client/pub_client.c +++ b/client/pub_client.c @@ -264,7 +264,7 @@ int main(int argc, char *argv[]) } mosquitto_connect_v5_callback_set(mosq, my_connect_callback); mosquitto_disconnect_v5_callback_set(mosq, my_disconnect_callback); - mosquitto_publish_callback_set(mosq, my_publish_callback); + mosquitto_publish_v5_callback_set(mosq, my_publish_callback); if(client_opts_set(mosq, &cfg)){ goto cleanup; diff --git a/client/pub_shared.c b/client/pub_shared.c index 9ef50084d8..7f0f22ad47 100644 --- a/client/pub_shared.c +++ b/client/pub_shared.c @@ -52,7 +52,7 @@ void my_disconnect_callback(struct mosquitto *mosq, void *obj, int rc, const mos connected = false; } -void my_publish_callback(struct mosquitto *mosq, void *obj, int mid) +void my_publish_callback(struct mosquitto *mosq, void *obj, int mid, int reason_code, const mosquitto_property *properties) { last_mid_sent = mid; if(cfg.pub_mode == MSGMODE_STDIN_LINE){ diff --git a/client/pub_shared.h b/client/pub_shared.h index 22f88e6265..fd7331f750 100644 --- a/client/pub_shared.h +++ b/client/pub_shared.h @@ -28,7 +28,7 @@ extern struct mosq_config cfg; void my_connect_callback(struct mosquitto *mosq, void *obj, int result, int flags, const mosquitto_property *properties); void my_disconnect_callback(struct mosquitto *mosq, void *obj, int rc, const mosquitto_property *properties); -void my_publish_callback(struct mosquitto *mosq, void *obj, int mid); +void my_publish_callback(struct mosquitto *mosq, void *obj, int mid, int reason_code, const mosquitto_property *properties); void my_log_callback(struct mosquitto *mosq, void *obj, int level, const char *str); int load_stdin(void); int load_file(const char *filename); diff --git a/client/sub_client.c b/client/sub_client.c index 6cbf76f903..2657dac753 100644 --- a/client/sub_client.c +++ b/client/sub_client.c @@ -53,7 +53,7 @@ void my_signal_handler(int signum) void print_message(struct mosq_config *cfg, const struct mosquitto_message *message); -void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message) +void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message, const mosquitto_property *properties) { int i; bool res; @@ -282,7 +282,7 @@ int main(int argc, char *argv[]) mosquitto_subscribe_callback_set(mosq, my_subscribe_callback); } mosquitto_connect_v5_callback_set(mosq, my_connect_callback); - mosquitto_message_callback_set(mosq, my_message_callback); + mosquitto_message_v5_callback_set(mosq, my_message_callback); rc = client_connect(mosq, &cfg); if(rc){ diff --git a/lib/callbacks.c b/lib/callbacks.c index 0d6747b948..7b42421077 100644 --- a/lib/callbacks.c +++ b/lib/callbacks.c @@ -62,7 +62,7 @@ void mosquitto_publish_callback_set(struct mosquitto *mosq, void (*on_publish)(s pthread_mutex_unlock(&mosq->callback_mutex); } -void mosquitto_publish_v5_callback_set(struct mosquitto *mosq, void (*on_publish)(struct mosquitto *, void *, int, const mosquitto_property *props)) +void mosquitto_publish_v5_callback_set(struct mosquitto *mosq, void (*on_publish)(struct mosquitto *, void *, int, int, const mosquitto_property *props)) { pthread_mutex_lock(&mosq->callback_mutex); mosq->on_publish_v5 = on_publish; diff --git a/lib/handle_pubackcomp.c b/lib/handle_pubackcomp.c index 4c4f319f10..d03ea59467 100644 --- a/lib/handle_pubackcomp.c +++ b/lib/handle_pubackcomp.c @@ -42,7 +42,7 @@ int handle__pubackcomp(struct mosquitto_db *db, struct mosquitto *mosq, const ch int handle__pubackcomp(struct mosquitto *mosq, const char *type) #endif { - uint8_t reason_code; + uint8_t reason_code = 0; uint16_t mid; int rc; mosquitto_property *properties = NULL; @@ -88,7 +88,7 @@ int handle__pubackcomp(struct mosquitto *mosq, const char *type) } if(mosq->on_publish_v5){ mosq->in_callback = true; - mosq->on_publish_v5(mosq, mosq->userdata, mid, properties); + mosq->on_publish_v5(mosq, mosq->userdata, mid, reason_code, properties); mosq->in_callback = false; } pthread_mutex_unlock(&mosq->callback_mutex); diff --git a/lib/mosquitto.h b/lib/mosquitto.h index 81fc692964..fffe11205e 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -1822,9 +1822,10 @@ libmosq_EXPORT void mosquitto_publish_callback_set(struct mosquitto *mosq, void * mosq - the mosquitto instance making the callback. * obj - the user data provided in * mid - the message id of the sent message. + * reason_code - the MQTT 5 reason code * props - list of MQTT 5 properties, or NULL */ -libmosq_EXPORT void mosquitto_publish_v5_callback_set(struct mosquitto *mosq, void (*on_publish)(struct mosquitto *, void *, int, const mosquitto_property *)); +libmosq_EXPORT void mosquitto_publish_v5_callback_set(struct mosquitto *mosq, void (*on_publish)(struct mosquitto *, void *, int, int, const mosquitto_property *)); /* * Function: mosquitto_message_callback_set diff --git a/lib/mosquitto_internal.h b/lib/mosquitto_internal.h index 49a8829b6a..a3746fcf2c 100644 --- a/lib/mosquitto_internal.h +++ b/lib/mosquitto_internal.h @@ -259,7 +259,7 @@ struct mosquitto { void (*on_disconnect)(struct mosquitto *, void *userdata, int rc); void (*on_disconnect_v5)(struct mosquitto *, void *userdata, int rc, const mosquitto_property *props); void (*on_publish)(struct mosquitto *, void *userdata, int mid); - void (*on_publish_v5)(struct mosquitto *, void *userdata, int mid, const mosquitto_property *props); + void (*on_publish_v5)(struct mosquitto *, void *userdata, int mid, int reason_code, const mosquitto_property *props); void (*on_message)(struct mosquitto *, void *userdata, const struct mosquitto_message *message); void (*on_message_v5)(struct mosquitto *, void *userdata, const struct mosquitto_message *message, const mosquitto_property *props); void (*on_subscribe)(struct mosquitto *, void *userdata, int mid, int qos_count, const int *granted_qos); diff --git a/lib/packet_mosq.c b/lib/packet_mosq.c index b22fdc8aed..b652656eee 100644 --- a/lib/packet_mosq.c +++ b/lib/packet_mosq.c @@ -220,7 +220,7 @@ int packet__write(struct mosquitto *mosq) if(mosq->on_publish_v5){ /* This is a QoS=0 message */ mosq->in_callback = true; - mosq->on_publish_v5(mosq, mosq->userdata, packet->mid, NULL); + mosq->on_publish_v5(mosq, mosq->userdata, packet->mid, 0, NULL); mosq->in_callback = false; } pthread_mutex_unlock(&mosq->callback_mutex); diff --git a/test/lib/c/03-publish-c2b-qos1-receive-maximum.c b/test/lib/c/03-publish-c2b-qos1-receive-maximum.c index e2d351cc40..563da395fc 100644 --- a/test/lib/c/03-publish-c2b-qos1-receive-maximum.c +++ b/test/lib/c/03-publish-c2b-qos1-receive-maximum.c @@ -17,7 +17,7 @@ void on_connect(struct mosquitto *mosq, void *obj, int rc, int flags, const mosq } } -void on_publish(struct mosquitto *mosq, void *obj, int mid, const mosquitto_property *properties) +void on_publish(struct mosquitto *mosq, void *obj, int mid, int reason_code, const mosquitto_property *properties) { if(mid == 6){ mosquitto_disconnect(mosq); diff --git a/test/lib/c/03-publish-c2b-qos2-pubrec-error.c b/test/lib/c/03-publish-c2b-qos2-pubrec-error.c index 9f454c02de..f7a64b17da 100644 --- a/test/lib/c/03-publish-c2b-qos2-pubrec-error.c +++ b/test/lib/c/03-publish-c2b-qos2-pubrec-error.c @@ -15,7 +15,7 @@ void on_connect(struct mosquitto *mosq, void *obj, int rc, int flags, const mosq mosquitto_publish_v5(mosq, NULL, "topic", strlen("accepted"), "accepted", 2, false, NULL); } -void on_publish(struct mosquitto *mosq, void *obj, int mid, const mosquitto_property *properties) +void on_publish(struct mosquitto *mosq, void *obj, int mid, int reason_code, const mosquitto_property *properties) { if(mid == 2){ run = 0; diff --git a/test/lib/c/03-publish-c2b-qos2-receive-maximum-1.c b/test/lib/c/03-publish-c2b-qos2-receive-maximum-1.c index a4b8e2a235..d0f427ae58 100644 --- a/test/lib/c/03-publish-c2b-qos2-receive-maximum-1.c +++ b/test/lib/c/03-publish-c2b-qos2-receive-maximum-1.c @@ -17,7 +17,7 @@ void on_connect(struct mosquitto *mosq, void *obj, int rc, int flags, const mosq } } -void on_publish(struct mosquitto *mosq, void *obj, int mid, const mosquitto_property *properties) +void on_publish(struct mosquitto *mosq, void *obj, int mid, int reason_code, const mosquitto_property *properties) { if(mid == 5){ mosquitto_disconnect(mosq); diff --git a/test/lib/c/03-publish-c2b-qos2-receive-maximum-2.c b/test/lib/c/03-publish-c2b-qos2-receive-maximum-2.c index a4b8e2a235..d0f427ae58 100644 --- a/test/lib/c/03-publish-c2b-qos2-receive-maximum-2.c +++ b/test/lib/c/03-publish-c2b-qos2-receive-maximum-2.c @@ -17,7 +17,7 @@ void on_connect(struct mosquitto *mosq, void *obj, int rc, int flags, const mosq } } -void on_publish(struct mosquitto *mosq, void *obj, int mid, const mosquitto_property *properties) +void on_publish(struct mosquitto *mosq, void *obj, int mid, int reason_code, const mosquitto_property *properties) { if(mid == 5){ mosquitto_disconnect(mosq); From 326292681afb835b8b4bb821319171ce9c311461 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 9 Jan 2019 17:56:01 +0000 Subject: [PATCH 185/254] Add maximum-qos support to broker and client. This comes in the form of: * Per listener maximum_qos option, which can be in the range 0-2. * Changes to mosquitto_publish*() to return MOSQ_ERR_QOS_NOT_SUPPORTED if attempting to publish with a higher QoS than supported. * Bridges will downgrade messages to match the maximum QoS. More tests on the broker side (specifically bridges) are required. This needs bridge support for MQTT 5 first. --- client/pub_client.c | 3 + lib/actions.c | 1 + lib/handle_connack.c | 4 +- lib/mosquitto.c | 1 + lib/mosquitto.h | 5 ++ lib/mosquitto_internal.h | 1 + man/mosquitto.conf.5.xml | 14 ++++ src/conf.c | 11 +++ src/context.c | 1 + src/database.c | 6 +- src/handle_connect.c | 8 ++ src/handle_publish.c | 5 ++ src/mosquitto_broker_internal.h | 1 + test/lib/03-publish-c2b-qos2-maximum-qos-0.py | 68 +++++++++++++++++ test/lib/03-publish-c2b-qos2-maximum-qos-1.py | 74 +++++++++++++++++++ test/lib/Makefile | 2 + .../lib/c/03-publish-c2b-qos2-maximum-qos-0.c | 58 +++++++++++++++ .../lib/c/03-publish-c2b-qos2-maximum-qos-1.c | 58 +++++++++++++++ test/lib/c/Makefile | 2 + test/lib/ptest.py | 2 + 20 files changed, 323 insertions(+), 2 deletions(-) create mode 100755 test/lib/03-publish-c2b-qos2-maximum-qos-0.py create mode 100755 test/lib/03-publish-c2b-qos2-maximum-qos-1.py create mode 100644 test/lib/c/03-publish-c2b-qos2-maximum-qos-0.c create mode 100644 test/lib/c/03-publish-c2b-qos2-maximum-qos-1.c diff --git a/client/pub_client.c b/client/pub_client.c index db4deded1c..28d5ed6be6 100644 --- a/client/pub_client.c +++ b/client/pub_client.c @@ -84,6 +84,9 @@ void my_connect_callback(struct mosquitto *mosq, void *obj, int result, int flag case MOSQ_ERR_PAYLOAD_SIZE: fprintf(stderr, "Error: Message payload is too large.\n"); break; + case MOSQ_ERR_QOS_NOT_SUPPORTED: + fprintf(stderr, "Error: Message QoS not supported on broker, try a lower QoS.\n"); + break; } } mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props); diff --git a/lib/actions.c b/lib/actions.c index 7c0e8c27a6..b7abd592d2 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -46,6 +46,7 @@ int mosquitto_publish_v5(struct mosquitto *mosq, int *mid, const char *topic, in if(!mosq || qos<0 || qos>2) return MOSQ_ERR_INVAL; if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED; + if(qos > mosq->maximum_qos) return MOSQ_ERR_QOS_NOT_SUPPORTED; if(properties){ if(properties->client_generated){ diff --git a/lib/handle_connack.c b/lib/handle_connack.c index df230419e2..1b13e28a31 100644 --- a/lib/handle_connack.c +++ b/lib/handle_connack.c @@ -61,8 +61,10 @@ int handle__connack(struct mosquitto *mosq) } } - mosquitto_property_read_int16(properties, MQTT_PROP_SERVER_KEEP_ALIVE, &mosq->keepalive, false); + mosquitto_property_read_byte(properties, MQTT_PROP_MAXIMUM_QOS, &mosq->maximum_qos, false); mosquitto_property_read_int16(properties, MQTT_PROP_RECEIVE_MAXIMUM, &mosq->send_maximum, false); + mosquitto_property_read_int16(properties, MQTT_PROP_SERVER_KEEP_ALIVE, &mosq->keepalive, false); + mosq->send_quota = mosq->send_maximum; log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received CONNACK (%d)", mosq->id, reason_code); diff --git a/lib/mosquitto.c b/lib/mosquitto.c index c5bb056e63..65b2152916 100644 --- a/lib/mosquitto.c +++ b/lib/mosquitto.c @@ -146,6 +146,7 @@ int mosquitto_reinitialise(struct mosquitto *mosq, const char *id, bool clean_st mosq->in_messages_last = NULL; mosq->out_messages = NULL; mosq->out_messages_last = NULL; + mosq->maximum_qos = 2; mosq->receive_maximum = 20; mosq->send_maximum = 20; mosq->will = NULL; diff --git a/lib/mosquitto.h b/lib/mosquitto.h index fffe11205e..394d1a3a40 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -92,6 +92,7 @@ enum mosq_err_t { MOSQ_ERR_MALFORMED_PACKET = 19, MOSQ_ERR_DUPLICATE_PROPERTY = 20, MOSQ_ERR_TLS_HANDSHAKE = 21, + MOSQ_ERR_QOS_NOT_SUPPORTED = 22, }; /* Error values */ @@ -739,6 +740,8 @@ libmosq_EXPORT int mosquitto_disconnect_v5(struct mosquitto *mosq, int reason_co * broker. * MOSQ_ERR_PAYLOAD_SIZE - if payloadlen is too large. * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8 + * MOSQ_ERR_QOS_NOT_SUPPORTED - if the QoS is greater than that supported by + * the broker. * * See Also: * @@ -787,6 +790,8 @@ libmosq_EXPORT int mosquitto_publish(struct mosquitto *mosq, int *mid, const cha * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8 * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. * MOSQ_ERR_PROTOCOL - if any property is invalid for use with PUBLISH. + * MOSQ_ERR_QOS_NOT_SUPPORTED - if the QoS is greater than that supported by + * the broker. */ libmosq_EXPORT int mosquitto_publish_v5( struct mosquitto *mosq, diff --git a/lib/mosquitto_internal.h b/lib/mosquitto_internal.h index a3746fcf2c..d79a464bba 100644 --- a/lib/mosquitto_internal.h +++ b/lib/mosquitto_internal.h @@ -286,6 +286,7 @@ struct mosquitto { int receive_quota; uint16_t send_maximum; uint16_t receive_maximum; + uint8_t maximum_qos; #ifdef WITH_BROKER UT_hash_handle hh_id; diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml index 97509b0544..437d28917f 100644 --- a/man/mosquitto.conf.5.xml +++ b/man/mosquitto.conf.5.xml @@ -802,6 +802,20 @@ Not reloaded on reload signal. + + count + + Limit the QoS value allowed when using this + listener. Defaults to 2, which means any QoS can be + used. Set to 0 or 1 to limit to those QoS values. + This makes use of an MQTT v5 feature to notify + clients of the limitation. MQTT v3.1.1 clients will + not be aware of the limitation. Clients publshing + to this listener with a too-high QoS will be + disconnected. + Not reloaded on reload signal. + + topic prefix diff --git a/src/conf.c b/src/conf.c index 0ae70ee491..d1f8f64eca 100644 --- a/src/conf.c +++ b/src/conf.c @@ -266,6 +266,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.maximum_qos = 2; } void config__cleanup(struct mosquitto__config *config) @@ -446,6 +447,7 @@ int config__parse_args(struct mosquitto_db *db, struct mosquitto__config *config || config->default_listener.host || config->default_listener.port || config->default_listener.max_connections != -1 + || config->default_listener.maximum_qos != 2 || config->default_listener.mount_point || config->default_listener.protocol != mp_mqtt || config->default_listener.socket_domain @@ -485,6 +487,7 @@ int config__parse_args(struct mosquitto_db *db, struct mosquitto__config *config config->listeners[config->listener_count-1].sock_count = 0; config->listeners[config->listener_count-1].client_count = 0; config->listeners[config->listener_count-1].use_username_as_clientid = config->default_listener.use_username_as_clientid; + config->listeners[config->listener_count-1].maximum_qos = config->default_listener.maximum_qos; #ifdef WITH_TLS config->listeners[config->listener_count-1].tls_version = config->default_listener.tls_version; config->listeners[config->listener_count-1].cafile = config->default_listener.cafile; @@ -1502,6 +1505,14 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct }else{ log__printf(NULL, MOSQ_LOG_ERR, "Error: Empty max_connections value in configuration."); } + }else if(!strcmp(token, "maximum_qos")){ + if(reload) continue; // Listeners not valid for reloading. + if(conf__parse_int(&token, "maximum_qos", &tmp_int, saveptr)) return MOSQ_ERR_INVAL; + if(tmp_int < 0 || tmp_int > 2){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: maximum_qos must be between 0 and 2 inclusive."); + return MOSQ_ERR_INVAL; + } + cur_listener->maximum_qos = tmp_int; }else if(!strcmp(token, "max_inflight_bytes")){ token = strtok_r(NULL, " ", &saveptr); if(token){ diff --git a/src/context.c b/src/context.c index a6a5f49931..bfe2340528 100644 --- a/src/context.c +++ b/src/context.c @@ -78,6 +78,7 @@ struct mosquitto *context__init(struct mosquitto_db *db, mosq_sock_t sock) context->last_queued_msg = NULL; context->receive_maximum = db->config->max_inflight_messages; context->send_maximum = db->config->max_inflight_messages; + context->maximum_qos = 2; context->msg_bytes = 0; context->msg_bytes12 = 0; context->msg_count = 0; diff --git a/src/database.c b/src/database.c index 6fc2dc230f..e00c9ada78 100644 --- a/src/database.c +++ b/src/database.c @@ -451,7 +451,11 @@ int db__message_insert(struct mosquitto_db *db, struct mosquitto *context, uint1 msg->direction = dir; msg->state = state; msg->dup = false; - msg->qos = qos; + if(qos > context->maximum_qos){ + msg->qos = context->maximum_qos; + }else{ + msg->qos = qos; + } msg->retain = retain; msg->properties = properties; diff --git a/src/handle_connect.c b/src/handle_connect.c index aac409be50..cefd20d877 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -262,6 +262,14 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) goto handle_connect_error; } + context->maximum_qos = context->listener->maximum_qos; + if(protocol_version == PROTOCOL_VERSION_v5 && context->maximum_qos != 2){ + if(mosquitto_property_add_byte(&connack_props, MQTT_PROP_MAXIMUM_QOS, context->maximum_qos)){ + rc = MOSQ_ERR_NOMEM; + goto handle_connect_error; + } + } + if(packet__read_byte(&context->in_packet, &connect_flags)){ rc = 1; goto handle_connect_error; diff --git a/src/handle_publish.c b/src/handle_publish.c index 3b02c1af73..6dbf4744c2 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -66,6 +66,11 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) "Invalid QoS in PUBLISH from %s, disconnecting.", context->id); return 1; } + if(qos > context->maximum_qos){ + log__printf(NULL, MOSQ_LOG_INFO, + "Too high QoS in PUBLISH from %s, disconnecting.", context->id); + return 1; + } retain = (header & 0x01); if(retain && db->config->retain_available == false){ diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index 497167c91e..e0e0f5a883 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -220,6 +220,7 @@ struct mosquitto__listener { enum mosquitto_protocol protocol; int socket_domain; bool use_username_as_clientid; + uint8_t maximum_qos; #ifdef WITH_TLS char *cafile; char *capath; diff --git a/test/lib/03-publish-c2b-qos2-maximum-qos-0.py b/test/lib/03-publish-c2b-qos2-maximum-qos-0.py new file mode 100755 index 0000000000..430df3a2a7 --- /dev/null +++ b/test/lib/03-publish-c2b-qos2-maximum-qos-0.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python + +# Test whether a client correctly handles sending a message with QoS > maximum QoS. + +from mosq_test_helper import * + +port = mosq_test.get_lib_port() + +rc = 1 +keepalive = 60 +connect_packet = mosq_test.gen_connect("publish-qos2-test", keepalive=keepalive, proto_ver=5) + +props = mqtt5_props.gen_byte_prop(mqtt5_props.PROP_MAXIMUM_QOS, 0) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5, properties=props) + +disconnect_packet = mosq_test.gen_disconnect(proto_ver=5) + +publish_1_packet = mosq_test.gen_publish("maximum/qos/qos0", qos=0, payload="message", 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) + + if mosq_test.expect_packet(conn, "publish 1", publish_1_packet): + if mosq_test.expect_packet(conn, "disconnect", disconnect_packet): + rc = 0 + + conn.close() +finally: + for i in range(0, 5): + if client.returncode != None: + break + time.sleep(0.1) + + try: + client.terminate() + except OSError: + pass + + client.wait() + sock.close() + if client.returncode != 0: + exit(1) + +exit(rc) diff --git a/test/lib/03-publish-c2b-qos2-maximum-qos-1.py b/test/lib/03-publish-c2b-qos2-maximum-qos-1.py new file mode 100755 index 0000000000..ec29af36bb --- /dev/null +++ b/test/lib/03-publish-c2b-qos2-maximum-qos-1.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python + +# Test whether a client correctly handles sending a message with QoS > maximum QoS. + +from mosq_test_helper import * + +port = mosq_test.get_lib_port() + +rc = 1 +keepalive = 60 +connect_packet = mosq_test.gen_connect("publish-qos2-test", keepalive=keepalive, proto_ver=5) + +props = mqtt5_props.gen_byte_prop(mqtt5_props.PROP_MAXIMUM_QOS, 1) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5, properties=props) + +disconnect_packet = mosq_test.gen_disconnect(proto_ver=5) + +mid = 1 +publish_1_packet = mosq_test.gen_publish("maximum/qos/qos1", qos=1, mid=mid, payload="message", proto_ver=5) +puback_1_packet = mosq_test.gen_puback(mid, proto_ver=5) + +publish_2_packet = mosq_test.gen_publish("maximum/qos/qos0", qos=0, payload="message", 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) + + if mosq_test.expect_packet(conn, "publish 1", publish_1_packet): + conn.send(puback_1_packet) + if mosq_test.expect_packet(conn, "publish 2", publish_2_packet): + if mosq_test.expect_packet(conn, "disconnect", disconnect_packet): + rc = 0 + + conn.close() +finally: + for i in range(0, 5): + if client.returncode != None: + break + time.sleep(0.1) + + try: + client.terminate() + except OSError: + pass + + client.wait() + sock.close() + if client.returncode != 0: + exit(1) + +exit(rc) diff --git a/test/lib/Makefile b/test/lib/Makefile index c91a1fa932..7fa08a0d69 100644 --- a/test/lib/Makefile +++ b/test/lib/Makefile @@ -40,6 +40,8 @@ c : test-compile ./03-publish-c2b-qos2-receive-maximum-1.py $@/03-publish-c2b-qos2-receive-maximum-1.test ./03-publish-c2b-qos2-receive-maximum-2.py $@/03-publish-c2b-qos2-receive-maximum-2.test ./03-publish-c2b-qos2-pubrec-error.py $@/03-publish-c2b-qos2-pubrec-error.test + ./03-publish-c2b-qos2-maximum-qos-0.py $@/03-publish-c2b-qos2-maximum-qos-0.test + ./03-publish-c2b-qos2-maximum-qos-1.py $@/03-publish-c2b-qos2-maximum-qos-1.test ./03-publish-b2c-qos1.py $@/03-publish-b2c-qos1.test ./03-publish-b2c-qos2.py $@/03-publish-b2c-qos2.test ./03-request-response.py $@/03-request-response.test diff --git a/test/lib/c/03-publish-c2b-qos2-maximum-qos-0.c b/test/lib/c/03-publish-c2b-qos2-maximum-qos-0.c new file mode 100644 index 0000000000..cfe7ab1df3 --- /dev/null +++ b/test/lib/c/03-publish-c2b-qos2-maximum-qos-0.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include + +static int run = -1; + +void on_connect(struct mosquitto *mosq, void *obj, int rc) +{ + if(rc){ + exit(1); + }else{ + rc = mosquitto_publish(mosq, NULL, "maximum/qos/qos2", strlen("message"), "message", 2, false); + if(rc != MOSQ_ERR_QOS_NOT_SUPPORTED) run = 1; + rc = mosquitto_publish(mosq, NULL, "maximum/qos/qos1", strlen("message"), "message", 1, false); + if(rc != MOSQ_ERR_QOS_NOT_SUPPORTED) run = 1; + rc = mosquitto_publish(mosq, NULL, "maximum/qos/qos0", strlen("message"), "message", 0, false); + if(rc != MOSQ_ERR_SUCCESS) run = 1; + } +} + +void on_publish(struct mosquitto *mosq, void *obj, int mid) +{ + if(mid == 1){ + mosquitto_disconnect(mosq); + } +} + +void on_disconnect(struct mosquitto *mosq, void *obj, int rc) +{ + run = 0; +} + +int main(int argc, char *argv[]) +{ + int rc; + struct mosquitto *mosq; + + int port = atoi(argv[1]); + + mosquitto_lib_init(); + + mosq = mosquitto_new("publish-qos2-test", true, NULL); + mosquitto_int_option(mosq, MOSQ_OPT_PROTOCOL_VERSION, MQTT_PROTOCOL_V5); + mosquitto_connect_callback_set(mosq, on_connect); + mosquitto_disconnect_callback_set(mosq, on_disconnect); + mosquitto_publish_callback_set(mosq, on_publish); + + rc = mosquitto_connect(mosq, "localhost", port, 60); + + while(run == -1){ + mosquitto_loop(mosq, 50, 1); + } + + mosquitto_lib_cleanup(); + return run; +} diff --git a/test/lib/c/03-publish-c2b-qos2-maximum-qos-1.c b/test/lib/c/03-publish-c2b-qos2-maximum-qos-1.c new file mode 100644 index 0000000000..84e5669202 --- /dev/null +++ b/test/lib/c/03-publish-c2b-qos2-maximum-qos-1.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include + +static int run = -1; + +void on_connect(struct mosquitto *mosq, void *obj, int rc) +{ + if(rc){ + exit(1); + }else{ + rc = mosquitto_publish(mosq, NULL, "maximum/qos/qos2", strlen("message"), "message", 2, false); + if(rc != MOSQ_ERR_QOS_NOT_SUPPORTED) run = 1; + rc = mosquitto_publish(mosq, NULL, "maximum/qos/qos1", strlen("message"), "message", 1, false); + if(rc != MOSQ_ERR_SUCCESS) run = 1; + rc = mosquitto_publish(mosq, NULL, "maximum/qos/qos0", strlen("message"), "message", 0, false); + if(rc != MOSQ_ERR_SUCCESS) run = 1; + } +} + +void on_publish(struct mosquitto *mosq, void *obj, int mid) +{ + if(mid == 2){ + mosquitto_disconnect(mosq); + } +} + +void on_disconnect(struct mosquitto *mosq, void *obj, int rc) +{ + run = 0; +} + +int main(int argc, char *argv[]) +{ + int rc; + struct mosquitto *mosq; + + int port = atoi(argv[1]); + + mosquitto_lib_init(); + + mosq = mosquitto_new("publish-qos2-test", true, NULL); + mosquitto_int_option(mosq, MOSQ_OPT_PROTOCOL_VERSION, MQTT_PROTOCOL_V5); + mosquitto_connect_callback_set(mosq, on_connect); + mosquitto_disconnect_callback_set(mosq, on_disconnect); + mosquitto_publish_callback_set(mosq, on_publish); + + rc = mosquitto_connect(mosq, "localhost", port, 60); + + while(run == -1){ + mosquitto_loop(mosq, 50, 1); + } + + mosquitto_lib_cleanup(); + return run; +} diff --git a/test/lib/c/Makefile b/test/lib/c/Makefile index 936da2a254..cf05d72ba6 100644 --- a/test/lib/c/Makefile +++ b/test/lib/c/Makefile @@ -23,6 +23,8 @@ SRC = \ 03-publish-c2b-qos2-receive-maximum-1.c \ 03-publish-c2b-qos2-receive-maximum-2.c \ 03-publish-c2b-qos2-pubrec-error.c \ + 03-publish-c2b-qos2-maximum-qos-0.c \ + 03-publish-c2b-qos2-maximum-qos-1.c \ 03-publish-b2c-qos1.c \ 03-publish-b2c-qos2.c \ 03-request-response-1.c \ diff --git a/test/lib/ptest.py b/test/lib/ptest.py index 9b7e4fab3f..78ebcd0ebc 100755 --- a/test/lib/ptest.py +++ b/test/lib/ptest.py @@ -25,6 +25,8 @@ ('./03-publish-c2b-qos2-receive-maximum-1.py', 'c/03-publish-c2b-qos2-receive-maximum-1.test'), ('./03-publish-c2b-qos2-receive-maximum-2.py', 'c/03-publish-c2b-qos2-receive-maximum-2.test'), ('./03-publish-c2b-qos2-pubrec-error.py', 'c/03-publish-c2b-qos2-pubrec-error.test'), + ('./03-publish-c2b-qos2-maximum-qos-0.py', 'c/03-publish-c2b-qos2-maximum-qos-0.test'), + ('./03-publish-c2b-qos2-maximum-qos-1.py', 'c/03-publish-c2b-qos2-maximum-qos-1.test'), ('./03-publish-qos0-no-payload.py', 'c/03-publish-qos0-no-payload.test'), ('./03-publish-qos0.py', 'c/03-publish-qos0.test'), ('./03-request-response.py', 'c/03-request-response.test'), From 4a2e569171b55984dbdcf3d8a75545c6bec1e00c Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 9 Jan 2019 18:06:20 +0000 Subject: [PATCH 186/254] -V now accepts `5, `311`, `31`, as well as `mqttv5` etc. --- ChangeLog.txt | 1 + client/client_shared.c | 6 +++--- man/mosquitto_pub.1.xml | 6 ++++-- man/mosquitto_sub.1.xml | 6 ++++-- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 5959289dcb..3ff4e22d2c 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -16,6 +16,7 @@ Client features: - Add -E to mosquitto_sub, which causes it to exit immediately after having its subscriptions acknowledged. Use with -c to create a durable client session without requiring a message to be received. +- -V now accepts `5, `311`, `31`, as well as `mqttv5` etc. Client fixes: - mosquitto_pub wouldn't always publish all messages when using `-l` and diff --git a/client/client_shared.c b/client/client_shared.c index b38306ca88..0a0e26a419 100644 --- a/client/client_shared.c +++ b/client/client_shared.c @@ -710,11 +710,11 @@ int client_config_line_proc(struct mosq_config *cfg, int pub_or_sub, int argc, c fprintf(stderr, "Error: --protocol-version argument given but no version specified.\n\n"); return 1; }else{ - if(!strcmp(argv[i+1], "mqttv31")){ + if(!strcmp(argv[i+1], "mqttv31") || !strcmp(argv[i+1], "31")){ cfg->protocol_version = MQTT_PROTOCOL_V31; - }else if(!strcmp(argv[i+1], "mqttv311")){ + }else if(!strcmp(argv[i+1], "mqttv311") || !strcmp(argv[i+1], "311")){ cfg->protocol_version = MQTT_PROTOCOL_V311; - }else if(!strcmp(argv[i+1], "mqttv5")){ + }else if(!strcmp(argv[i+1], "mqttv5") || !strcmp(argv[i+1], "5")){ cfg->protocol_version = MQTT_PROTOCOL_V5; }else{ fprintf(stderr, "Error: Invalid protocol version argument given.\n\n"); diff --git a/man/mosquitto_pub.1.xml b/man/mosquitto_pub.1.xml index c95c0cbab3..1054d43248 100644 --- a/man/mosquitto_pub.1.xml +++ b/man/mosquitto_pub.1.xml @@ -464,9 +464,11 @@ Specify which version of the MQTT protocol should be used when connecting to the rmeote broker. Can be - , or + , , + , or the more verbose + , , or . - Defaults to . + Defaults to . diff --git a/man/mosquitto_sub.1.xml b/man/mosquitto_sub.1.xml index 7c4861aba3..e46b5bbbc5 100644 --- a/man/mosquitto_sub.1.xml +++ b/man/mosquitto_sub.1.xml @@ -587,9 +587,11 @@ Specify which version of the MQTT protocol should be used when connecting to the rmeote broker. Can be - , or + , , + , or the more verbose + , , or . - Defaults to . + Defaults to . From 5f8d86b4ee793cdaef283b2dfa21f7b34635e09e Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 10 Jan 2019 22:10:32 +0000 Subject: [PATCH 187/254] Fix sub-denied test. --- src/handle_subscribe.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/handle_subscribe.c b/src/handle_subscribe.c index 1f8412f785..e50075a3e5 100644 --- a/src/handle_subscribe.c +++ b/src/handle_subscribe.c @@ -145,8 +145,8 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) log__printf(NULL, MOSQ_LOG_DEBUG, "\t%s (QoS %d)", sub, qos); if(context->protocol != mosq_p_mqtt31){ - rc = mosquitto_acl_check(db, context, sub, 0, NULL, qos, false, MOSQ_ACL_SUBSCRIBE); - switch(rc){ + rc2 = mosquitto_acl_check(db, context, sub, 0, NULL, qos, false, MOSQ_ACL_SUBSCRIBE); + switch(rc2){ case MOSQ_ERR_SUCCESS: break; case MOSQ_ERR_ACL_DENIED: @@ -154,7 +154,7 @@ int handle__subscribe(struct mosquitto_db *db, struct mosquitto *context) break; default: mosquitto__free(sub); - return rc; + return rc2; } } From 4b97a90ef91e2dbbab5a754ba2f9ac4cf85288fe Mon Sep 17 00:00:00 2001 From: Roger Light Date: Thu, 17 Jan 2019 16:52:44 +0000 Subject: [PATCH 188/254] Tests and fixes for truncated PUB* packets For the cases where reason_code is 0, or properties are missing. --- lib/handle_pubackcomp.c | 8 +- lib/handle_pubrec.c | 23 +++-- lib/handle_pubrel.c | 19 ++-- lib/mosquitto.h | 4 +- lib/send_mosq.c | 21 +++-- test/broker/03-publish-b2c-qos1-len-helper.py | 24 ++++++ test/broker/03-publish-b2c-qos1-len.py | 72 ++++++++++++++++ test/broker/03-publish-b2c-qos2-len-helper.py | 27 ++++++ test/broker/03-publish-b2c-qos2-len.py | 79 +++++++++++++++++ test/broker/03-publish-c2b-qos2-len.py | 64 ++++++++++++++ test/broker/Makefile | 3 + test/broker/ptest.py | 3 + test/lib/03-publish-b2c-qos2-len.py | 79 +++++++++++++++++ test/lib/03-publish-c2b-qos1-len.py | 77 +++++++++++++++++ test/lib/03-publish-c2b-qos2-len.py | 86 +++++++++++++++++++ test/lib/Makefile | 3 + test/lib/c/03-publish-b2c-qos2-len.c | 74 ++++++++++++++++ test/lib/c/03-publish-c2b-qos1-len.c | 52 +++++++++++ test/lib/c/03-publish-c2b-qos2-len.c | 52 +++++++++++ test/lib/c/Makefile | 3 + test/lib/ptest.py | 3 + test/mosq_test.py | 32 ++++--- 22 files changed, 776 insertions(+), 32 deletions(-) create mode 100755 test/broker/03-publish-b2c-qos1-len-helper.py create mode 100755 test/broker/03-publish-b2c-qos1-len.py create mode 100755 test/broker/03-publish-b2c-qos2-len-helper.py create mode 100755 test/broker/03-publish-b2c-qos2-len.py create mode 100755 test/broker/03-publish-c2b-qos2-len.py create mode 100755 test/lib/03-publish-b2c-qos2-len.py create mode 100755 test/lib/03-publish-c2b-qos1-len.py create mode 100755 test/lib/03-publish-c2b-qos2-len.py create mode 100644 test/lib/c/03-publish-b2c-qos2-len.c create mode 100644 test/lib/c/03-publish-c2b-qos1-len.c create mode 100644 test/lib/c/03-publish-c2b-qos2-len.c diff --git a/lib/handle_pubackcomp.c b/lib/handle_pubackcomp.c index d03ea59467..b9fc2c5d19 100644 --- a/lib/handle_pubackcomp.c +++ b/lib/handle_pubackcomp.c @@ -52,12 +52,14 @@ int handle__pubackcomp(struct mosquitto *mosq, const char *type) if(rc) return rc; if(mid == 0) return MOSQ_ERR_PROTOCOL; - if(mosq->protocol == mosq_p_mqtt5){ + if(mosq->protocol == mosq_p_mqtt5 && mosq->in_packet.remaining_length > 2){ rc = packet__read_byte(&mosq->in_packet, &reason_code); if(rc) return rc; - rc = property__read_all(CMD_PUBACK, &mosq->in_packet, &properties); - if(rc) return rc; + if(mosq->in_packet.remaining_length > 3){ + rc = property__read_all(CMD_PUBACK, &mosq->in_packet, &properties); + if(rc) return rc; + } } #ifdef WITH_BROKER diff --git a/lib/handle_pubrec.c b/lib/handle_pubrec.c index 589b405a2b..feb41e9215 100644 --- a/lib/handle_pubrec.c +++ b/lib/handle_pubrec.c @@ -47,14 +47,16 @@ int handle__pubrec(struct mosquitto_db *db, struct mosquitto *mosq) if(rc) return rc; if(mid == 0) return MOSQ_ERR_PROTOCOL; - if(mosq->protocol == mosq_p_mqtt5){ + if(mosq->protocol == mosq_p_mqtt5 && mosq->in_packet.remaining_length > 2){ rc = packet__read_byte(&mosq->in_packet, &reason_code); if(rc) return rc; - rc = property__read_all(CMD_PUBREC, &mosq->in_packet, &properties); - if(rc) return rc; - /* Immediately free, we don't do anything with Reason String or User Property at the moment */ - mosquitto_property_free_all(&properties); + if(mosq->in_packet.remaining_length > 3){ + rc = property__read_all(CMD_PUBREC, &mosq->in_packet, &properties); + if(rc) return rc; + /* Immediately free, we don't do anything with Reason String or User Property at the moment */ + mosquitto_property_free_all(&properties); + } } #ifdef WITH_BROKER @@ -71,7 +73,16 @@ int handle__pubrec(struct mosquitto_db *db, struct mosquitto *mosq) if(reason_code < 0x80){ rc = message__out_update(mosq, mid, mosq_ms_wait_for_pubcomp); }else{ - message__delete(mosq, mid, mosq_md_out); + if(!message__delete(mosq, mid, mosq_md_out)){ + /* Only inform the client the message has been sent once. */ + pthread_mutex_lock(&mosq->callback_mutex); + if(mosq->on_publish_v5){ + mosq->in_callback = true; + mosq->on_publish_v5(mosq, mosq->userdata, mid, reason_code, properties); + mosq->in_callback = false; + } + pthread_mutex_unlock(&mosq->callback_mutex); + } return MOSQ_ERR_SUCCESS; } #endif diff --git a/lib/handle_pubrel.c b/lib/handle_pubrel.c index 2ec6dc8b05..e046c40b64 100644 --- a/lib/handle_pubrel.c +++ b/lib/handle_pubrel.c @@ -56,12 +56,14 @@ int handle__pubrel(struct mosquitto_db *db, struct mosquitto *mosq) if(rc) return rc; if(mid == 0) return MOSQ_ERR_PROTOCOL; - if(mosq->protocol == mosq_p_mqtt5){ + if(mosq->protocol == mosq_p_mqtt5 && mosq->in_packet.remaining_length > 2){ rc = packet__read_byte(&mosq->in_packet, &reason_code); if(rc) return rc; - rc = property__read_all(CMD_PUBREL, &mosq->in_packet, &properties); - if(rc) return rc; + if(mosq->in_packet.remaining_length > 3){ + rc = property__read_all(CMD_PUBREL, &mosq->in_packet, &properties); + if(rc) return rc; + } } #ifdef WITH_BROKER @@ -75,9 +77,18 @@ int handle__pubrel(struct mosquitto_db *db, struct mosquitto *mosq) * due to a repeated PUBREL after a client has reconnected. */ log__printf(mosq, MOSQ_LOG_WARNING, "Warning: Received PUBREL from %s for an unknown packet identifier %d.", mosq->id, mid); } + + rc = send__pubcomp(mosq, mid); + if(rc) return rc; #else log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received PUBREL (Mid: %d)", mosq->id, mid); + rc = send__pubcomp(mosq, mid); + if(rc){ + message__remove(mosq, mid, mosq_md_in, &message); + return rc; + } + if(!message__remove(mosq, mid, mosq_md_in, &message)){ /* Only pass the message on if we have removed it from the queue - this * prevents multiple callbacks for the same message. */ @@ -97,8 +108,6 @@ int handle__pubrel(struct mosquitto_db *db, struct mosquitto *mosq) message__cleanup(&message); } #endif - rc = send__pubcomp(mosq, mid); - if(rc) return rc; return MOSQ_ERR_SUCCESS; } diff --git a/lib/mosquitto.h b/lib/mosquitto.h index 394d1a3a40..8174eca09c 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -1816,7 +1816,9 @@ libmosq_EXPORT void mosquitto_publish_callback_set(struct mosquitto *mosq, void * Function: mosquitto_publish_v5_callback_set * * Set the publish callback. This is called when a message initiated with - * has been sent to the broker successfully. + * has been sent to the broker. This callback will be + * called both if the message is sent successfully, or if the broker responded + * with an error, which will be reflected in the reason_code parameter. * * Parameters: * mosq - a valid mosquitto instance. diff --git a/lib/send_mosq.c b/lib/send_mosq.c index 5366fd1e99..6f39b36d3c 100644 --- a/lib/send_mosq.c +++ b/lib/send_mosq.c @@ -135,10 +135,15 @@ int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid packet->remaining_length = 2; if(mosq->protocol == mosq_p_mqtt5){ - proplen = property__get_length_all(properties); - varbytes = packet__varint_bytes(proplen); - /* 1 here is sizeof(reason_code) */ - packet->remaining_length += 1 + varbytes + proplen; + if(reason_code != 0 || properties){ + packet->remaining_length += 1; + } + + if(properties){ + proplen = property__get_length_all(properties); + varbytes = packet__varint_bytes(proplen); + packet->remaining_length += varbytes + proplen; + } } rc = packet__alloc(packet); @@ -150,8 +155,12 @@ int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid packet__write_uint16(packet, mid); if(mosq->protocol == mosq_p_mqtt5){ - packet__write_byte(packet, reason_code); - property__write_all(packet, properties, true); + if(reason_code != 0 || properties){ + packet__write_byte(packet, reason_code); + } + if(properties){ + property__write_all(packet, properties, true); + } } return packet__queue(mosq, packet); diff --git a/test/broker/03-publish-b2c-qos1-len-helper.py b/test/broker/03-publish-b2c-qos1-len-helper.py new file mode 100755 index 0000000000..3c491c4e00 --- /dev/null +++ b/test/broker/03-publish-b2c-qos1-len-helper.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python + +from mosq_test_helper import * + +port = mosq_test.get_port() + +rc = 1 +keepalive = 60 +connect_packet = mosq_test.gen_connect("test-helper", keepalive=keepalive) +connack_packet = mosq_test.gen_connack(rc=0) + +mid = 1 +publish_packet = mosq_test.gen_publish("qos1/len/test", qos=1, mid=mid, payload="len-message") +puback_packet = mosq_test.gen_puback(mid) + +sock = mosq_test.do_client_connect(connect_packet, connack_packet, connack_error="helper connack", port=port) + +mosq_test.do_send_receive(sock, publish_packet, puback_packet, "helper puback") + +rc = 0 + +sock.close() + +exit(rc) diff --git a/test/broker/03-publish-b2c-qos1-len.py b/test/broker/03-publish-b2c-qos1-len.py new file mode 100755 index 0000000000..4eb82ae586 --- /dev/null +++ b/test/broker/03-publish-b2c-qos1-len.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python + +# Check whether the broker handles a v5 PUBACK with all combinations +# of with/without reason code and properties. + +from mosq_test_helper import * + +def len_test(test, puback_packet): + port = mosq_test.get_port() + + rc = 1 + mid = 3265 + keepalive = 60 + connect_packet = mosq_test.gen_connect("pub-qos1-test", keepalive=keepalive, clean_session=False, proto_ver=5) + connack_packet = mosq_test.gen_connack(resv=0, rc=0, proto_ver=5) + + subscribe_packet = mosq_test.gen_subscribe(mid, "qos1/len/test", 1, proto_ver=5) + suback_packet = mosq_test.gen_suback(mid, 1, proto_ver=5) + + mid = 1 + publish_packet = mosq_test.gen_publish("qos1/len/test", qos=1, mid=mid, payload="len-message", proto_ver=5) + + pingreq_packet = mosq_test.gen_pingreq() + pingresp_packet = mosq_test.gen_pingresp() + + broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port) + + try: + sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port) + + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback") + + pub = subprocess.Popen(['./03-publish-b2c-qos1-len-helper.py', str(port)], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + pub.wait() + (stdo, stde) = pub.communicate() + # Should have now received a publish command + + if mosq_test.expect_packet(sock, "publish", publish_packet): + sock.send(puback_packet) + + mosq_test.do_send_receive(sock, pingreq_packet, pingresp_packet, "pingreq") + rc = 0 + + sock.close() + finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + + if rc != 0: + print(test) + exit(rc) + + +# No reason code, no properties +puback_packet = mosq_test.gen_puback(1) +len_test("qos1 len 2", puback_packet) + +# Reason code, no properties +puback_packet = mosq_test.gen_puback(1, proto_ver=5, reason_code=0x00) +len_test("qos1 len 3", puback_packet) + +# Reason code, empty properties +puback_packet = mosq_test.gen_puback(1, proto_ver=5, reason_code=0x00, properties="") +len_test("qos1 len 4", puback_packet) + +# Reason code, one property +props = mqtt5_props.gen_string_pair_prop(mqtt5_props.PROP_USER_PROPERTY, "key", "value") +puback_packet = mosq_test.gen_puback(1, proto_ver=5, reason_code=0x00, properties=props) +len_test("qos1 len >5", puback_packet) diff --git a/test/broker/03-publish-b2c-qos2-len-helper.py b/test/broker/03-publish-b2c-qos2-len-helper.py new file mode 100755 index 0000000000..e2a9c45676 --- /dev/null +++ b/test/broker/03-publish-b2c-qos2-len-helper.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python + +from mosq_test_helper import * + +port = mosq_test.get_port() + +rc = 1 +keepalive = 60 +connect_packet = mosq_test.gen_connect("test-helper", keepalive=keepalive) +connack_packet = mosq_test.gen_connack(rc=0) + +mid = 1 +publish_packet = mosq_test.gen_publish("qos2/len/test", qos=2, mid=mid, payload="len-message") +pubrec_packet = mosq_test.gen_pubrec(mid) +pubrel_packet = mosq_test.gen_pubrel(mid) +pubcomp_packet = mosq_test.gen_pubcomp(mid) + +sock = mosq_test.do_client_connect(connect_packet, connack_packet, connack_error="helper connack", port=port) + +mosq_test.do_send_receive(sock, publish_packet, pubrec_packet, "helper pubrec") +mosq_test.do_send_receive(sock, pubrel_packet, pubcomp_packet, "helper pubcomp") + +rc = 0 + +sock.close() + +exit(rc) diff --git a/test/broker/03-publish-b2c-qos2-len.py b/test/broker/03-publish-b2c-qos2-len.py new file mode 100755 index 0000000000..b3f0e76552 --- /dev/null +++ b/test/broker/03-publish-b2c-qos2-len.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python + +# Check whether the broker handles a v5 PUBREC, PUBCOMP with all combinations +# of with/without reason code and properties. + +from mosq_test_helper import * + +def len_test(test, pubrec_packet, pubcomp_packet): + port = mosq_test.get_port() + + rc = 1 + mid = 3265 + keepalive = 60 + connect_packet = mosq_test.gen_connect("pub-test", keepalive=keepalive, clean_session=False, proto_ver=5) + connack_packet = mosq_test.gen_connack(resv=0, rc=0, proto_ver=5) + + subscribe_packet = mosq_test.gen_subscribe(mid, "qos2/len/test", 2, proto_ver=5) + suback_packet = mosq_test.gen_suback(mid, 2, proto_ver=5) + + mid = 1 + publish_packet = mosq_test.gen_publish("qos2/len/test", qos=2, mid=mid, payload="len-message", proto_ver=5) + pubrel_packet = mosq_test.gen_pubrel(mid) + + pingreq_packet = mosq_test.gen_pingreq() + pingresp_packet = mosq_test.gen_pingresp() + + broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port) + + try: + sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port) + + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback") + + pub = subprocess.Popen(['./03-publish-b2c-qos2-len-helper.py', str(port)], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + pub.wait() + (stdo, stde) = pub.communicate() + # Should have now received a publish command + + if mosq_test.expect_packet(sock, "publish", publish_packet): + mosq_test.do_send_receive(sock, pubrec_packet, pubrel_packet, "pubrel") + sock.send(pubcomp_packet) + + mosq_test.do_send_receive(sock, pingreq_packet, pingresp_packet, "pingresp") + rc = 0 + + sock.close() + finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + + if rc != 0: + print(test) + exit(rc) + + +# No reason code, no properties +pubrec_packet = mosq_test.gen_pubrec(1) +pubcomp_packet = mosq_test.gen_pubcomp(1) +len_test("qos2 len 2", pubrec_packet, pubcomp_packet) + +# Reason code, no properties +pubrec_packet = mosq_test.gen_pubrec(1, proto_ver=5, reason_code=0x00) +pubcomp_packet = mosq_test.gen_pubcomp(1, proto_ver=5, reason_code=0x00) +len_test("qos2 len 3", pubrec_packet, pubcomp_packet) + +# Reason code, empty properties +pubrec_packet = mosq_test.gen_pubrec(1, proto_ver=5, reason_code=0x00, properties="") +pubcomp_packet = mosq_test.gen_pubcomp(1, proto_ver=5, reason_code=0x00, properties="") +len_test("qos2 len 4", pubrec_packet, pubcomp_packet) + +# Reason code, one property +props = mqtt5_props.gen_string_pair_prop(mqtt5_props.PROP_USER_PROPERTY, "key", "value") +pubrec_packet = mosq_test.gen_pubrec(1, proto_ver=5, reason_code=0x00, properties=props) +props = mqtt5_props.gen_string_pair_prop(mqtt5_props.PROP_USER_PROPERTY, "key", "value") +pubcomp_packet = mosq_test.gen_pubcomp(1, proto_ver=5, reason_code=0x00, properties=props) +len_test("qos2 len >5", pubrec_packet, pubcomp_packet) diff --git a/test/broker/03-publish-c2b-qos2-len.py b/test/broker/03-publish-c2b-qos2-len.py new file mode 100755 index 0000000000..753c571dda --- /dev/null +++ b/test/broker/03-publish-c2b-qos2-len.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python + +# Check whether the broker handles a v5 PUBREL with all combinations +# of with/without reason code and properties. + +from mosq_test_helper import * + +def len_test(test, pubrel_packet): + port = mosq_test.get_port() + + rc = 1 + mid = 3265 + keepalive = 60 + connect_packet = mosq_test.gen_connect("pub-test", keepalive=keepalive, clean_session=False, proto_ver=5) + connack_packet = mosq_test.gen_connack(resv=0, rc=0, proto_ver=5) + + mid = 1 + publish_packet = mosq_test.gen_publish("qos2/len/test", qos=2, mid=mid, payload="len-message", proto_ver=5) + pubrec_packet = mosq_test.gen_pubrec(mid) + pubcomp_packet = mosq_test.gen_pubcomp(mid) + + pingreq_packet = mosq_test.gen_pingreq() + pingresp_packet = mosq_test.gen_pingresp() + + broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port) + + try: + sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port) + + mosq_test.do_send_receive(sock, publish_packet, pubrec_packet, "pubrec") + mosq_test.do_send_receive(sock, pubrel_packet, pubcomp_packet, "pubcomp") + + mosq_test.do_send_receive(sock, pingreq_packet, pingresp_packet, "pingresp") + rc = 0 + + sock.close() + finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + + if rc != 0: + print(test) + exit(rc) + + +# No reason code, no properties +pubrel_packet = mosq_test.gen_pubrel(1) +len_test("qos2 len 2", pubrel_packet) + +# Reason code, no properties +pubrel_packet = mosq_test.gen_pubrel(1, proto_ver=5, reason_code=0x00) +len_test("qos2 len 3", pubrel_packet) + +# Reason code, empty properties +pubrel_packet = mosq_test.gen_pubrel(1, proto_ver=5, reason_code=0x00, properties="") +len_test("qos2 len 4", pubrel_packet) + +# Reason code, one property +props = mqtt5_props.gen_string_pair_prop(mqtt5_props.PROP_USER_PROPERTY, "key", "value") +pubrel_packet = mosq_test.gen_pubrel(1, proto_ver=5, reason_code=0x00, properties=props) +len_test("qos2 len >5", pubrel_packet) diff --git a/test/broker/Makefile b/test/broker/Makefile index 7583026f71..6295d7295c 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -74,6 +74,9 @@ endif ./03-publish-b2c-disconnect-qos1.py ./03-publish-c2b-disconnect-qos2.py ./03-publish-b2c-disconnect-qos2.py + ./03-publish-b2c-qos1-len.py + ./03-publish-b2c-qos2-len.py + ./03-publish-c2b-qos2-len.py ./03-pattern-matching.py #./03-publish-qos1-queued-bytes.py ./03-publish-invalid-utf8.py diff --git a/test/broker/ptest.py b/test/broker/ptest.py index fbaf48f805..3f96794c36 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -56,6 +56,9 @@ (1, './03-publish-b2c-disconnect-qos1.py'), (1, './03-publish-c2b-disconnect-qos2.py'), (1, './03-publish-b2c-disconnect-qos2.py'), + (1, './03-publish-b2c-qos1-len.py'), + (1, './03-publish-b2c-qos2-len.py'), + (1, './03-publish-c2b-qos2-len.py'), (1, './03-pattern-matching.py'), #(1, './03-publish-qos1-queued-bytes.py'), (1, './03-publish-invalid-utf8.py'), diff --git a/test/lib/03-publish-b2c-qos2-len.py b/test/lib/03-publish-b2c-qos2-len.py new file mode 100755 index 0000000000..775669cc6f --- /dev/null +++ b/test/lib/03-publish-b2c-qos2-len.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python + +# Check whether a v5 client handles a v5 PUBREL with all combinations +# of with/without reason code and properties. + +from mosq_test_helper import * + +mid = 56 + +def len_test(test, pubrel_packet): + port = mosq_test.get_lib_port() + + rc = 1 + keepalive = 60 + connect_packet = mosq_test.gen_connect("publish-qos2-test", keepalive=keepalive, proto_ver=5) + connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + + disconnect_packet = mosq_test.gen_disconnect(proto_ver=5) + + publish_packet = mosq_test.gen_publish("len/qos2/test", qos=2, mid=mid, payload="message", proto_ver=5) + pubrec_packet = mosq_test.gen_pubrec(mid, proto_ver=5) + pubcomp_packet = mosq_test.gen_pubcomp(mid, 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(15) + + if mosq_test.expect_packet(conn, "connect", connect_packet): + conn.send(connack_packet) + + mosq_test.do_send_receive(conn, publish_packet, pubrec_packet, "pubrec") + mosq_test.do_send_receive(conn, pubrel_packet, pubcomp_packet, "pubcomp") + if mosq_test.expect_packet(conn, "disconnect", disconnect_packet): + rc = 0 + + conn.close() + finally: + client.terminate() + client.wait() + sock.close() + + if rc != 0: + print(test) + exit(rc) + + +# No reason code, no properties +pubrel_packet = mosq_test.gen_pubrel(mid) +len_test("qos2 len 2", pubrel_packet) + +# Reason code, no properties +pubrel_packet = mosq_test.gen_pubrel(mid, proto_ver=5, reason_code=0x00) +len_test("qos2 len 3", pubrel_packet) + +# Reason code, empty properties +pubrel_packet = mosq_test.gen_pubrel(mid, proto_ver=5, reason_code=0x00, properties="") +len_test("qos2 len 4", pubrel_packet) + +# Reason code, one property +props = mqtt5_props.gen_string_pair_prop(mqtt5_props.PROP_USER_PROPERTY, "key", "value") +pubrel_packet = mosq_test.gen_pubrel(mid, proto_ver=5, reason_code=0x00, properties=props) +len_test("qos2 len >5", pubrel_packet) diff --git a/test/lib/03-publish-c2b-qos1-len.py b/test/lib/03-publish-c2b-qos1-len.py new file mode 100755 index 0000000000..30e65337e2 --- /dev/null +++ b/test/lib/03-publish-c2b-qos1-len.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python + +# Check whether a v5 client handles a v5 PUBACK with all combinations +# of with/without reason code and properties. + +from mosq_test_helper import * + +def len_test(test, puback_packet): + port = mosq_test.get_lib_port() + + rc = 1 + keepalive = 60 + connect_packet = mosq_test.gen_connect("publish-qos1-test", keepalive=keepalive, proto_ver=5) + connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + + disconnect_packet = mosq_test.gen_disconnect(proto_ver=5) + + mid = 1 + publish_packet = mosq_test.gen_publish("pub/qos1/test", qos=1, mid=mid, payload="message", 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(15) + + if mosq_test.expect_packet(conn, "connect", connect_packet): + conn.send(connack_packet) + + if mosq_test.expect_packet(conn, "publish", publish_packet): + conn.send(puback_packet) + + if mosq_test.expect_packet(conn, "disconnect", disconnect_packet): + rc = 0 + + conn.close() + finally: + client.terminate() + client.wait() + sock.close() + + if rc != 0: + print(test) + exit(rc) + + +# No reason code, no properties +puback_packet = mosq_test.gen_puback(1) +len_test("qos1 len 2", puback_packet) + +# Reason code, no properties +puback_packet = mosq_test.gen_puback(1, proto_ver=5, reason_code=0x00) +len_test("qos1 len 3", puback_packet) + +# Reason code, empty properties +puback_packet = mosq_test.gen_puback(1, proto_ver=5, reason_code=0x00, properties="") +len_test("qos1 len 4", puback_packet) + +# Reason code, one property +props = mqtt5_props.gen_string_pair_prop(mqtt5_props.PROP_USER_PROPERTY, "key", "value") +puback_packet = mosq_test.gen_puback(1, proto_ver=5, reason_code=0x00, properties=props) +len_test("qos1 len >5", puback_packet) diff --git a/test/lib/03-publish-c2b-qos2-len.py b/test/lib/03-publish-c2b-qos2-len.py new file mode 100755 index 0000000000..fc44416738 --- /dev/null +++ b/test/lib/03-publish-c2b-qos2-len.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python + +# Check whether a v5 client handles a v5 PUBREC, PUBCOMP with all combinations +# of with/without reason code and properties. + +from mosq_test_helper import * + +def len_test(test, pubrec_packet, pubcomp_packet): + port = mosq_test.get_lib_port() + + rc = 1 + keepalive = 60 + connect_packet = mosq_test.gen_connect("publish-qos2-test", keepalive=keepalive, proto_ver=5) + connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + + disconnect_packet = mosq_test.gen_disconnect(proto_ver=5) + + mid = 1 + publish_packet = mosq_test.gen_publish("pub/qos2/test", qos=2, mid=mid, payload="message", proto_ver=5) + pubrel_packet = mosq_test.gen_pubrel(mid, 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(15) + + if mosq_test.expect_packet(conn, "connect", connect_packet): + conn.send(connack_packet) + + if mosq_test.expect_packet(conn, "publish", publish_packet): + conn.send(pubrec_packet) + + if mosq_test.expect_packet(conn, "pubrel", pubrel_packet): + conn.send(pubcomp_packet) + + if mosq_test.expect_packet(conn, "disconnect", disconnect_packet): + rc = 0 + + conn.close() + finally: + client.terminate() + client.wait() + sock.close() + + if rc != 0: + print(test) + exit(rc) + + +# No reason code, no properties +pubrec_packet = mosq_test.gen_pubrec(1) +pubcomp_packet = mosq_test.gen_pubcomp(1) +len_test("qos2 len 2", pubrec_packet, pubcomp_packet) + +# Reason code, no properties +pubrec_packet = mosq_test.gen_pubrec(1, proto_ver=5, reason_code=0x00) +pubcomp_packet = mosq_test.gen_pubcomp(1, proto_ver=5, reason_code=0x00) +len_test("qos2 len 3", pubrec_packet, pubcomp_packet) + +# Reason code, empty properties +pubrec_packet = mosq_test.gen_pubrec(1, proto_ver=5, reason_code=0x00, properties="") +pubcomp_packet = mosq_test.gen_pubcomp(1, proto_ver=5, reason_code=0x00, properties="") +len_test("qos2 len 4", pubrec_packet, pubcomp_packet) + +# Reason code, one property +props = mqtt5_props.gen_string_pair_prop(mqtt5_props.PROP_USER_PROPERTY, "key", "value") +pubrec_packet = mosq_test.gen_pubrec(1, proto_ver=5, reason_code=0x00, properties=props) +props = mqtt5_props.gen_string_pair_prop(mqtt5_props.PROP_USER_PROPERTY, "key", "value") +pubcomp_packet = mosq_test.gen_pubcomp(1, proto_ver=5, reason_code=0x00, properties=props) +len_test("qos2 len >5", pubrec_packet, pubcomp_packet) diff --git a/test/lib/Makefile b/test/lib/Makefile index 7fa08a0d69..cb71a4e7fa 100644 --- a/test/lib/Makefile +++ b/test/lib/Makefile @@ -34,6 +34,9 @@ c : test-compile ./03-publish-qos0.py $@/03-publish-qos0.test ./03-publish-qos0-no-payload.py $@/03-publish-qos0-no-payload.test ./03-publish-c2b-qos1-disconnect.py $@/03-publish-c2b-qos1-disconnect.test + ./03-publish-c2b-qos1-len.py $@/03-publish-c2b-qos1-len.test + ./03-publish-c2b-qos2-len.py $@/03-publish-c2b-qos2-len.test + ./03-publish-b2c-qos2-len.py $@/03-publish-b2c-qos2-len.test ./03-publish-c2b-qos2.py $@/03-publish-c2b-qos2.test ./03-publish-c2b-qos2-disconnect.py $@/03-publish-c2b-qos2-disconnect.test ./03-publish-c2b-qos1-receive-maximum.py $@/03-publish-c2b-qos1-receive-maximum.test diff --git a/test/lib/c/03-publish-b2c-qos2-len.c b/test/lib/c/03-publish-b2c-qos2-len.c new file mode 100644 index 0000000000..3975d914b9 --- /dev/null +++ b/test/lib/c/03-publish-b2c-qos2-len.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include +#include + +static int run = -1; + +void on_connect(struct mosquitto *mosq, void *obj, int rc) +{ + if(rc){ + exit(1); + } +} + +void on_message(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg) +{ + if(msg->mid != 56){ + printf("Invalid mid (%d)\n", msg->mid); + exit(1); + } + if(msg->qos != 2){ + printf("Invalid qos (%d)\n", msg->qos); + exit(1); + } + if(strcmp(msg->topic, "len/qos2/test")){ + printf("Invalid topic (%s)\n", msg->topic); + exit(1); + } + if(strcmp(msg->payload, "message")){ + printf("Invalid payload (%s)\n", (char *)msg->payload); + exit(1); + } + if(msg->payloadlen != 7){ + printf("Invalid payloadlen (%d)\n", msg->payloadlen); + exit(1); + } + if(msg->retain != false){ + printf("Invalid retain (%d)\n", msg->retain); + exit(1); + } + + mosquitto_disconnect(mosq); +} + +void on_disconnect(struct mosquitto *mosq, void *obj, int rc) +{ + run = 0; +} + +int main(int argc, char *argv[]) +{ + int rc; + struct mosquitto *mosq; + + int port = atoi(argv[1]); + + mosquitto_lib_init(); + + mosq = mosquitto_new("publish-qos2-test", true, &run); + mosquitto_int_option(mosq, MOSQ_OPT_PROTOCOL_VERSION, MQTT_PROTOCOL_V5); + mosquitto_connect_callback_set(mosq, on_connect); + mosquitto_disconnect_callback_set(mosq, on_disconnect); + mosquitto_message_callback_set(mosq, on_message); + + rc = mosquitto_connect(mosq, "localhost", port, 60); + + while(run == -1){ + mosquitto_loop(mosq, 100, 1); + } + + mosquitto_lib_cleanup(); + return run; +} diff --git a/test/lib/c/03-publish-c2b-qos1-len.c b/test/lib/c/03-publish-c2b-qos1-len.c new file mode 100644 index 0000000000..66fe76e6ea --- /dev/null +++ b/test/lib/c/03-publish-c2b-qos1-len.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include + +static int run = -1; + +void on_connect(struct mosquitto *mosq, void *obj, int rc) +{ + if(rc){ + exit(1); + }else{ + mosquitto_publish(mosq, NULL, "pub/qos1/test", strlen("message"), "message", 1, false); + } +} + +void on_publish(struct mosquitto *mosq, void *obj, int mid) +{ + mosquitto_disconnect(mosq); +} + +void on_disconnect(struct mosquitto *mosq, void *obj, int rc) +{ + run = 0; +} + +int main(int argc, char *argv[]) +{ + int rc; + struct mosquitto *mosq; + + int port = atoi(argv[1]); + + mosquitto_lib_init(); + + mosq = mosquitto_new("publish-qos1-test", true, NULL); + mosquitto_int_option(mosq, MOSQ_OPT_PROTOCOL_VERSION, MQTT_PROTOCOL_V5); + mosquitto_connect_callback_set(mosq, on_connect); + mosquitto_disconnect_callback_set(mosq, on_disconnect); + mosquitto_publish_callback_set(mosq, on_publish); + mosquitto_message_retry_set(mosq, 3); + + rc = mosquitto_connect(mosq, "localhost", port, 60); + + while(run == -1){ + mosquitto_loop(mosq, 300, 1); + } + + mosquitto_lib_cleanup(); + return run; +} diff --git a/test/lib/c/03-publish-c2b-qos2-len.c b/test/lib/c/03-publish-c2b-qos2-len.c new file mode 100644 index 0000000000..ab59adb773 --- /dev/null +++ b/test/lib/c/03-publish-c2b-qos2-len.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include + +static int run = -1; + +void on_connect(struct mosquitto *mosq, void *obj, int rc) +{ + if(rc){ + exit(1); + }else{ + mosquitto_publish(mosq, NULL, "pub/qos2/test", strlen("message"), "message", 2, false); + } +} + +void on_publish(struct mosquitto *mosq, void *obj, int mid, int reason_code, const mosquitto_property *properties) +{ + mosquitto_disconnect(mosq); +} + +void on_disconnect(struct mosquitto *mosq, void *obj, int rc) +{ + run = 0; +} + +int main(int argc, char *argv[]) +{ + int rc; + struct mosquitto *mosq; + + int port = atoi(argv[1]); + + mosquitto_lib_init(); + + mosq = mosquitto_new("publish-qos2-test", true, NULL); + mosquitto_int_option(mosq, MOSQ_OPT_PROTOCOL_VERSION, MQTT_PROTOCOL_V5); + mosquitto_connect_callback_set(mosq, on_connect); + mosquitto_disconnect_callback_set(mosq, on_disconnect); + mosquitto_publish_v5_callback_set(mosq, on_publish); + mosquitto_message_retry_set(mosq, 3); + + rc = mosquitto_connect(mosq, "localhost", port, 60); + + while(run == -1){ + mosquitto_loop(mosq, 300, 1); + } + + mosquitto_lib_cleanup(); + return run; +} diff --git a/test/lib/c/Makefile b/test/lib/c/Makefile index cf05d72ba6..2df4221cf1 100644 --- a/test/lib/c/Makefile +++ b/test/lib/c/Makefile @@ -17,8 +17,11 @@ SRC = \ 03-publish-qos0.c \ 03-publish-qos0-no-payload.c \ 03-publish-c2b-qos1-disconnect.c \ + 03-publish-c2b-qos1-len.c \ 03-publish-c2b-qos2.c \ 03-publish-c2b-qos2-disconnect.c \ + 03-publish-c2b-qos2-len.c \ + 03-publish-b2c-qos2-len.c \ 03-publish-c2b-qos1-receive-maximum.c \ 03-publish-c2b-qos2-receive-maximum-1.c \ 03-publish-c2b-qos2-receive-maximum-2.c \ diff --git a/test/lib/ptest.py b/test/lib/ptest.py index 78ebcd0ebc..b94e6b40fb 100755 --- a/test/lib/ptest.py +++ b/test/lib/ptest.py @@ -18,6 +18,9 @@ ('./02-unsubscribe.py', 'c/02-unsubscribe.test'), ('./03-publish-b2c-qos1.py', 'c/03-publish-b2c-qos1.test'), ('./03-publish-b2c-qos2.py', 'c/03-publish-b2c-qos2.test'), + ('./03-publish-c2b-qos1-len.py', 'c/03-publish-c2b-qos1-len.test'), + ('./03-publish-c2b-qos2-len.py', 'c/03-publish-c2b-qos2-len.test'), + ('./03-publish-b2c-qos2-len.py', 'c/03-publish-b2c-qos2-len.test'), ('./03-publish-c2b-qos1-disconnect.py', 'c/03-publish-c2b-qos1-disconnect.test'), ('./03-publish-c2b-qos2-disconnect.py', 'c/03-publish-c2b-qos2-disconnect.test'), ('./03-publish-c2b-qos2.py', 'c/03-publish-c2b-qos2.test'), diff --git a/test/mosq_test.py b/test/mosq_test.py index 21c702bde1..a09367ccb9 100644 --- a/test/mosq_test.py +++ b/test/mosq_test.py @@ -415,27 +415,37 @@ def gen_publish(topic, qos, payload=None, retain=False, dup=False, mid=0, proto_ else: return struct.pack("!B" + str(len(rlpacked))+"s" + pack_format, cmd, rlpacked, len(topic), topic, payload) -def _gen_command_with_mid(cmd, mid, proto_ver=4, reason_code=0): - if proto_ver == 5: - return struct.pack('!BBHBB', cmd, 4, mid, reason_code, 0) +def _gen_command_with_mid(cmd, mid, proto_ver=4, reason_code=-1, properties=None): + if proto_ver == 5 and (reason_code != -1 or properties is not None): + if reason_code == -1: + reason_code = 0 + + if properties is None: + return struct.pack('!BBHB', cmd, 3, mid, reason_code) + elif properties == "": + return struct.pack('!BBHBB', cmd, 4, mid, reason_code, 0) + else: + properties = mqtt5_props.prop_finalise(properties) + pack_format = "!BBHB"+str(len(properties))+"s" + return struct.pack(pack_format, cmd, 2+1+len(properties), mid, reason_code, properties) else: return struct.pack('!BBH', cmd, 2, mid) -def gen_puback(mid, proto_ver=4, reason_code=0): - return _gen_command_with_mid(64, mid, proto_ver, reason_code) +def gen_puback(mid, proto_ver=4, reason_code=-1, properties=None): + return _gen_command_with_mid(64, mid, proto_ver, reason_code, properties) -def gen_pubrec(mid, proto_ver=4, reason_code=0): - return _gen_command_with_mid(80, mid, proto_ver, reason_code) +def gen_pubrec(mid, proto_ver=4, reason_code=-1, properties=None): + return _gen_command_with_mid(80, mid, proto_ver, reason_code, properties) -def gen_pubrel(mid, dup=False, proto_ver=4, reason_code=0): +def gen_pubrel(mid, dup=False, proto_ver=4, reason_code=-1, properties=None): if dup: cmd = 96+8+2 else: cmd = 96+2 - return _gen_command_with_mid(cmd, mid, proto_ver, reason_code) + return _gen_command_with_mid(cmd, mid, proto_ver, reason_code, properties) -def gen_pubcomp(mid, proto_ver=4, reason_code=0): - return _gen_command_with_mid(112, mid, proto_ver, reason_code) +def gen_pubcomp(mid, proto_ver=4, reason_code=-1, properties=None): + return _gen_command_with_mid(112, mid, proto_ver, reason_code, properties) def gen_subscribe(mid, topic, qos, proto_ver=4, properties=""): if proto_ver == 5: From 8513af4da5c8d98c8fa3d6c6cef44f8133ad025d Mon Sep 17 00:00:00 2001 From: Roger Light Date: Thu, 17 Jan 2019 18:51:23 +0000 Subject: [PATCH 189/254] Tests and fixes for shortened DISCONNECT packets. --- lib/handle_disconnect.c | 6 ++- lib/send_disconnect.c | 18 +++++---- src/handle_connect.c | 9 +++-- test/broker/01-connect-disconnect-v5.py | 51 +++++++++++++++++++++++++ test/broker/Makefile | 1 + test/broker/ptest.py | 1 + test/mosq_test.py | 15 ++++++-- 7 files changed, 86 insertions(+), 15 deletions(-) create mode 100755 test/broker/01-connect-disconnect-v5.py diff --git a/lib/handle_disconnect.c b/lib/handle_disconnect.c index 2f3bb58ac1..0ec1c8b3cb 100644 --- a/lib/handle_disconnect.c +++ b/lib/handle_disconnect.c @@ -38,10 +38,14 @@ int handle__disconnect(struct mosquitto *mosq) return MOSQ_ERR_INVAL; } + if(mosq->protocol != mosq_p_mqtt5){ + return MOSQ_ERR_PROTOCOL; + } + rc = packet__read_byte(&mosq->in_packet, &reason_code); if(rc) return rc; - if(mosq->protocol == mosq_p_mqtt5){ + if(mosq->in_packet.remaining_length > 2){ rc = property__read_all(CMD_DISCONNECT, &mosq->in_packet, &properties); if(rc) return rc; mosquitto_property_free_all(&properties); diff --git a/lib/send_disconnect.c b/lib/send_disconnect.c index c0959fbb6f..3615a00181 100644 --- a/lib/send_disconnect.c +++ b/lib/send_disconnect.c @@ -51,11 +51,13 @@ int send__disconnect(struct mosquitto *mosq, uint8_t reason_code, const mosquitt if(!packet) return MOSQ_ERR_NOMEM; packet->command = CMD_DISCONNECT; - if(mosq->protocol == mosq_p_mqtt5){ - proplen = property__get_length_all(properties); - varbytes = packet__varint_bytes(proplen); - /* 1 here is the reason code */ - packet->remaining_length = 1 + proplen + varbytes; + if(mosq->protocol == mosq_p_mqtt5 && (reason_code != 0 || properties)){ + packet->remaining_length = 1; + if(properties){ + proplen = property__get_length_all(properties); + varbytes = packet__varint_bytes(proplen); + packet->remaining_length += proplen + varbytes; + } }else{ packet->remaining_length = 0; } @@ -65,9 +67,11 @@ int send__disconnect(struct mosquitto *mosq, uint8_t reason_code, const mosquitt mosquitto__free(packet); return rc; } - if(mosq->protocol == mosq_p_mqtt5){ + if(mosq->protocol == mosq_p_mqtt5 && (reason_code != 0 || properties)){ packet__write_byte(packet, reason_code); - property__write_all(packet, properties, true); + if(properties){ + property__write_all(packet, properties, true); + } } return packet__queue(mosq, packet); diff --git a/src/handle_connect.c b/src/handle_connect.c index cefd20d877..739cd4d670 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -818,12 +818,15 @@ int handle__disconnect(struct mosquitto_db *db, struct mosquitto *context) return MOSQ_ERR_INVAL; } - if(context->protocol == mosq_p_mqtt5){ + if(context->protocol == mosq_p_mqtt5 && context->in_packet.remaining_length > 1){ /* FIXME - must handle reason code */ rc = packet__read_byte(&context->in_packet, &reason_code); if(rc) return rc; - rc = property__read_all(CMD_DISCONNECT, &context->in_packet, &properties); - if(rc) return rc; + + if(context->in_packet.remaining_length > 2){ + rc = property__read_all(CMD_DISCONNECT, &context->in_packet, &properties); + if(rc) return rc; + } } rc = property__process_disconnect(context, properties); if(rc){ diff --git a/test/broker/01-connect-disconnect-v5.py b/test/broker/01-connect-disconnect-v5.py new file mode 100755 index 0000000000..96dd4d89ca --- /dev/null +++ b/test/broker/01-connect-disconnect-v5.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python + +# loop through the different v5 DISCONNECT reason_code/properties options. + +from mosq_test_helper import * + +def disco_test(test, disconnect_packet): + global rc + + sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port) + sock.send(disconnect_packet) + sock.close() + rc -= 1 + + +rc = 4 +keepalive = 10 +connect_packet = mosq_test.gen_connect("connect-disconnect-test", proto_ver=5, keepalive=keepalive) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +port = mosq_test.get_port() +broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port) + + +try: + # No reason code, no properties, len=0 + disconnect_packet = mosq_test.gen_disconnect(proto_ver=5) + disco_test("disco len=0", disconnect_packet) + + # Reason code, no properties, len=1 + disconnect_packet = mosq_test.gen_disconnect(proto_ver=5, reason_code=0) + disco_test("disco len=1", disconnect_packet) + + # Reason code, empty properties, len=2 + disconnect_packet = mosq_test.gen_disconnect(proto_ver=5, reason_code=0, properties="") + disco_test("disco len=2", disconnect_packet) + + # Reason code, one property, len>2 + props = mqtt5_props.gen_string_pair_prop(mqtt5_props.PROP_USER_PROPERTY, "key", "value") + disconnect_packet = mosq_test.gen_disconnect(proto_ver=5, reason_code=0, properties=props) + disco_test("disco len>2", disconnect_packet) +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +if rc != 0: + print(test) + exit(rc) diff --git a/test/broker/Makefile b/test/broker/Makefile index 6295d7295c..74b7f43431 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -23,6 +23,7 @@ test : test-compile 01 02 03 04 05 06 07 08 09 10 11 12 ./01-connect-duplicate-v5.py ./01-connect-success.py ./01-connect-success-v5.py + ./01-connect-disconnect-v5.py ./01-connect-invalid-protonum.py ./01-connect-invalid-id-0.py ./01-connect-invalid-id-0-311.py diff --git a/test/broker/ptest.py b/test/broker/ptest.py index 3f96794c36..cffe6cb03b 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -12,6 +12,7 @@ (1, './01-connect-duplicate-v5.py'), (1, './01-connect-success.py'), (1, './01-connect-success-v5.py'), + (1, './01-connect-disconnect-v5.py'), (1, './01-connect-invalid-protonum.py'), (1, './01-connect-invalid-id-0.py'), (1, './01-connect-invalid-id-0-311.py'), diff --git a/test/mosq_test.py b/test/mosq_test.py index a09367ccb9..b4a4b12532 100644 --- a/test/mosq_test.py +++ b/test/mosq_test.py @@ -486,11 +486,18 @@ def gen_pingreq(): def gen_pingresp(): return struct.pack('!BB', 208, 0) -def gen_disconnect(reason_code=0, proto_ver=4, properties=""): - if proto_ver == 5: - properties = mqtt5_props.prop_finalise(properties) +def gen_disconnect(reason_code=-1, proto_ver=4, properties=None): + if proto_ver == 5 and (reason_code != -1 or properties is not None): + if reason_code == -1: + reason_code = 0 - return struct.pack('!BBB', 224, 1+len(properties), reason_code) + properties + if properties is None: + return struct.pack('!BBB', 224, 1, reason_code) + elif properties == "": + return struct.pack('!BBBB', 224, 2, reason_code, 0) + else: + properties = mqtt5_props.prop_finalise(properties) + return struct.pack("!BBB", 224, 1+len(properties), reason_code) + properties else: return struct.pack('!BB', 224, 0) From 37727b402b164f8b7ceb437fe7a44b3721463e9f Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 17 Jan 2019 21:04:46 +0000 Subject: [PATCH 190/254] Fix maximum qos on listener conf. --- src/conf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/conf.c b/src/conf.c index d1f8f64eca..cabfd6015c 100644 --- a/src/conf.c +++ b/src/conf.c @@ -1331,6 +1331,7 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct cur_listener->security_options.allow_anonymous = -1; cur_listener->protocol = mp_mqtt; cur_listener->port = tmp_int; + cur_listener->maximum_qos = 2; token = strtok_r(NULL, "", &saveptr); mosquitto__free(cur_listener->host); if(token){ From 1cc3e558ee4da2c85316ac5b01397d07a42daf52 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 18 Jan 2019 21:14:23 +0000 Subject: [PATCH 191/254] Test for server keepalive. --- test/lib/01-server-keepalive-pingreq.py | 59 ++++++++++++++++++++++++ test/lib/Makefile | 1 + test/lib/c/01-server-keepalive-pingreq.c | 37 +++++++++++++++ test/lib/c/Makefile | 1 + test/lib/ptest.py | 1 + 5 files changed, 99 insertions(+) create mode 100755 test/lib/01-server-keepalive-pingreq.py create mode 100644 test/lib/c/01-server-keepalive-pingreq.c diff --git a/test/lib/01-server-keepalive-pingreq.py b/test/lib/01-server-keepalive-pingreq.py new file mode 100755 index 0000000000..2d6fa9c2ec --- /dev/null +++ b/test/lib/01-server-keepalive-pingreq.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python + +# Test whether a client sends a pingreq after the keepalive time +# Client sets a keepalive of 60 seconds, but receives a server keepalive to set +# it back to 4 seconds. + +from mosq_test_helper import * + +port = mosq_test.get_lib_port() + +rc = 1 +keepalive = 60 +server_keepalive = 4 +connect_packet = mosq_test.gen_connect("01-server-keepalive-pingreq", keepalive=keepalive, proto_ver=5) + +props = mqtt5_props.gen_uint16_prop(mqtt5_props.PROP_SERVER_KEEP_ALIVE, server_keepalive) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5, properties=props) + +pingreq_packet = mosq_test.gen_pingreq() +pingresp_packet = mosq_test.gen_pingresp() + +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(server_keepalive+10) + + if mosq_test.expect_packet(conn, "connect", connect_packet): + conn.send(connack_packet) + + if mosq_test.expect_packet(conn, "pingreq", pingreq_packet): + time.sleep(1.0) + conn.send(pingresp_packet) + + if mosq_test.expect_packet(conn, "pingreq", pingreq_packet): + rc = 0 + + conn.close() +finally: + client.terminate() + client.wait() + sock.close() + +exit(rc) + diff --git a/test/lib/Makefile b/test/lib/Makefile index cb71a4e7fa..49f3088b87 100644 --- a/test/lib/Makefile +++ b/test/lib/Makefile @@ -27,6 +27,7 @@ c : test-compile ./01-will-unpwd-set.py $@/01-will-unpwd-set.test ./01-no-clean-session.py $@/01-no-clean-session.test ./01-keepalive-pingreq.py $@/01-keepalive-pingreq.test + ./01-server-keepalive-pingreq.py $@/01-server-keepalive-pingreq.test ./02-subscribe-qos0.py $@/02-subscribe-qos0.test ./02-subscribe-qos1.py $@/02-subscribe-qos1.test ./02-subscribe-qos2.py $@/02-subscribe-qos2.test diff --git a/test/lib/c/01-server-keepalive-pingreq.c b/test/lib/c/01-server-keepalive-pingreq.c new file mode 100644 index 0000000000..99da6f6970 --- /dev/null +++ b/test/lib/c/01-server-keepalive-pingreq.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include + +static int run = -1; + +void on_connect(struct mosquitto *mosq, void *obj, int rc) +{ + if(rc){ + exit(1); + } +} + +int main(int argc, char *argv[]) +{ + int rc; + struct mosquitto *mosq; + + int port = atoi(argv[1]); + + mosquitto_lib_init(); + + mosq = mosquitto_new("01-server-keepalive-pingreq", true, NULL); + mosquitto_int_option(mosq, MOSQ_OPT_PROTOCOL_VERSION, MQTT_PROTOCOL_V5); + mosquitto_connect_callback_set(mosq, on_connect); + + rc = mosquitto_connect(mosq, "localhost", port, 60); + + while(run == -1){ + mosquitto_loop(mosq, -1, 1); + } + + mosquitto_destroy(mosq); + mosquitto_lib_cleanup(); + return run; +} diff --git a/test/lib/c/Makefile b/test/lib/c/Makefile index 2df4221cf1..f02beb9024 100644 --- a/test/lib/c/Makefile +++ b/test/lib/c/Makefile @@ -10,6 +10,7 @@ SRC = \ 01-will-unpwd-set.c \ 01-no-clean-session.c \ 01-keepalive-pingreq.c \ + 01-server-keepalive-pingreq.c \ 02-subscribe-qos0.c \ 02-subscribe-qos1.c \ 02-subscribe-qos2.c \ diff --git a/test/lib/ptest.py b/test/lib/ptest.py index b94e6b40fb..c12142a111 100755 --- a/test/lib/ptest.py +++ b/test/lib/ptest.py @@ -8,6 +8,7 @@ tests = [ ('./01-con-discon-success.py', 'c/01-con-discon-success.test'), ('./01-keepalive-pingreq.py', 'c/01-keepalive-pingreq.test'), + ('./01-server-keepalive-pingreq.py', 'c/01-server-keepalive-pingreq.test'), ('./01-no-clean-session.py', 'c/01-no-clean-session.test'), ('./01-unpwd-set.py', 'c/01-unpwd-set.test'), ('./01-will-set.py', 'c/01-will-set.test'), From f9a17e2782763c561c3ec2d34286a4e810d0e2bd Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 18 Jan 2019 21:30:34 +0000 Subject: [PATCH 192/254] Add alias support to the broker. --- lib/alias_mosq.c | 85 +++++++++++++++ lib/alias_mosq.h | 26 +++++ lib/mosquitto_internal.h | 8 ++ lib/packet_datatypes.c | 13 ++- src/Makefile | 4 + src/context.c | 3 + src/handle_publish.c | 123 ++++++++++++---------- test/broker/02-subpub-qos0-topic-alias.py | 54 ++++++++++ test/broker/Makefile | 1 + test/broker/ptest.py | 1 + 10 files changed, 259 insertions(+), 59 deletions(-) create mode 100644 lib/alias_mosq.c create mode 100644 lib/alias_mosq.h create mode 100755 test/broker/02-subpub-qos0-topic-alias.py diff --git a/lib/alias_mosq.c b/lib/alias_mosq.c new file mode 100644 index 0000000000..8057bb9967 --- /dev/null +++ b/lib/alias_mosq.c @@ -0,0 +1,85 @@ +/* +Copyright (c) 2019 Roger Light + +All rights reserved. This program and the accompanying materials +are made available under the terms of the Eclipse Public License v1.0 +and Eclipse Distribution License v1.0 which accompany this distribution. + +The Eclipse Public License is available at + http://www.eclipse.org/legal/epl-v10.html +and the Eclipse Distribution License is available at + http://www.eclipse.org/org/documents/edl-v10.php. + +Contributors: + Roger Light - initial implementation and documentation. +*/ + +#include "config.h" + +#include "mosquitto.h" +#include "alias_mosq.h" +#include "memory_mosq.h" + +int alias__add(struct mosquitto *mosq, const char *topic, int alias) +{ + int i; + struct mosquitto__alias *aliases; + + for(i=0; ialias_count; i++){ + if(mosq->aliases[i].alias == alias){ + mosquitto__free(mosq->aliases[i].topic); + mosq->aliases[i].topic = mosquitto__strdup(topic); + if(mosq->aliases[i].topic){ + return MOSQ_ERR_SUCCESS; + }else{ + + return MOSQ_ERR_NOMEM; + } + } + } + + /* New alias */ + aliases = mosquitto__realloc(mosq->aliases, sizeof(struct mosquitto__alias)*(mosq->alias_count+1)); + if(!aliases) return MOSQ_ERR_NOMEM; + + mosq->aliases = aliases; + mosq->aliases[mosq->alias_count].alias = alias; + mosq->aliases[mosq->alias_count].topic = mosquitto__strdup(topic); + if(!mosq->aliases[mosq->alias_count].topic){ + return MOSQ_ERR_NOMEM; + } + mosq->alias_count++; + + return MOSQ_ERR_SUCCESS; +} + + +int alias__find(struct mosquitto *mosq, char **topic, int alias) +{ + int i; + + for(i=0; ialias_count; i++){ + if(mosq->aliases[i].alias == alias){ + *topic = mosquitto__strdup(mosq->aliases[i].topic); + if(*topic){ + return MOSQ_ERR_SUCCESS; + }else{ + return MOSQ_ERR_NOMEM; + } + } + } + return MOSQ_ERR_INVAL; +} + + +void alias__free_all(struct mosquitto *mosq) +{ + int i; + + for(i=0; ialias_count; i++){ + mosquitto__free(mosq->aliases[i].topic); + } + mosquitto__free(mosq->aliases); + mosq->aliases = NULL; + mosq->alias_count = 0; +} diff --git a/lib/alias_mosq.h b/lib/alias_mosq.h new file mode 100644 index 0000000000..f892dbf887 --- /dev/null +++ b/lib/alias_mosq.h @@ -0,0 +1,26 @@ +/* +Copyright (c) 2019 Roger Light + +All rights reserved. This program and the accompanying materials +are made available under the terms of the Eclipse Public License v1.0 +and Eclipse Distribution License v1.0 which accompany this distribution. + +The Eclipse Public License is available at + http://www.eclipse.org/legal/epl-v10.html +and the Eclipse Distribution License is available at + http://www.eclipse.org/org/documents/edl-v10.php. + +Contributors: + Roger Light - initial implementation and documentation. +*/ + +#ifndef ALIAS_MOSQ_H +#define ALIAS_MOSQ_H + +#include "mosquitto_internal.h" + +int alias__add(struct mosquitto *mosq, const char *topic, int alias); +int alias__find(struct mosquitto *mosq, char **topic, int alias); +void alias__free_all(struct mosquitto *mosq); + +#endif diff --git a/lib/mosquitto_internal.h b/lib/mosquitto_internal.h index d79a464bba..a3eac68777 100644 --- a/lib/mosquitto_internal.h +++ b/lib/mosquitto_internal.h @@ -132,6 +132,12 @@ enum mosquitto__transport { mosq_t_sctp = 3 }; + +struct mosquitto__alias{ + char *topic; + uint16_t alias; +}; + struct mosquitto__packet{ uint8_t *payload; struct mosquitto__packet *next; @@ -178,6 +184,8 @@ struct mosquitto { struct mosquitto__packet *current_out_packet; struct mosquitto__packet *out_packet; struct mosquitto_message_all *will; + struct mosquitto__alias *aliases; + int alias_count; #ifdef WITH_TLS SSL *ssl; SSL_CTX *ssl_ctx; diff --git a/lib/packet_datatypes.c b/lib/packet_datatypes.c index 9297afe6e7..41dd9d942d 100644 --- a/lib/packet_datatypes.c +++ b/lib/packet_datatypes.c @@ -97,6 +97,12 @@ int packet__read_binary(struct mosquitto__packet *packet, uint8_t **data, int *l rc = packet__read_uint16(packet, &slen); if(rc) return rc; + if(slen == 0){ + *data = NULL; + *length = 0; + return MOSQ_ERR_SUCCESS; + } + if(packet->pos+slen > packet->remaining_length) return MOSQ_ERR_PROTOCOL; *data = mosquitto__malloc(slen+1); @@ -116,18 +122,17 @@ int packet__read_binary(struct mosquitto__packet *packet, uint8_t **data, int *l int packet__read_string(struct mosquitto__packet *packet, char **str, int *length) { int rc; - int len; - rc = packet__read_binary(packet, (uint8_t **)str, &len); + rc = packet__read_binary(packet, (uint8_t **)str, length); if(rc) return rc; + if(*length == 0) return MOSQ_ERR_SUCCESS; - if(mosquitto_validate_utf8(*str, len)){ + if(mosquitto_validate_utf8(*str, *length)){ mosquitto__free(*str); *str = NULL; return MOSQ_ERR_MALFORMED_UTF8; } - *length = len; return MOSQ_ERR_SUCCESS; } diff --git a/src/Makefile b/src/Makefile index 07b917dd67..bf7775efc4 100644 --- a/src/Makefile +++ b/src/Makefile @@ -9,6 +9,7 @@ all : mosquitto endif OBJS= mosquitto.o \ + alias_mosq.o \ bridge.o \ conf.o \ conf_includedir.o \ @@ -67,6 +68,9 @@ mosquitto : ${OBJS} mosquitto.o : mosquitto.c mosquitto_broker_internal.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ +alias_mosq.o : ../lib/alias_mosq.c ../lib/alias_mosq.h + ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ + bridge.o : bridge.c mosquitto_broker_internal.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ diff --git a/src/context.c b/src/context.c index bfe2340528..74a5a8d603 100644 --- a/src/context.c +++ b/src/context.c @@ -20,6 +20,7 @@ and the Eclipse Distribution License is available at #include #include "mosquitto_broker_internal.h" +#include "alias_mosq.h" #include "memory_mosq.h" #include "packet_mosq.h" #include "property_mosq.h" @@ -140,6 +141,8 @@ void context__cleanup(struct mosquitto_db *db, struct mosquitto *context, bool d } #endif + alias__free_all(context); + mosquitto__free(context->username); context->username = NULL; diff --git a/src/handle_publish.c b/src/handle_publish.c index 6dbf4744c2..148e717451 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -21,6 +21,7 @@ and the Eclipse Distribution License is available at #include #include "mosquitto_broker_internal.h" +#include "alias_mosq.h" #include "mqtt_protocol.h" #include "memory_mosq.h" #include "packet_mosq.h" @@ -49,6 +50,7 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) mosquitto_property *p, *p_prev; mosquitto_property *msg_properties = NULL, *msg_properties_last; uint32_t message_expiry_interval = 0; + uint16_t topic_alias = 0; #ifdef WITH_BRIDGE char *topic_temp; @@ -81,66 +83,12 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) } if(packet__read_string(&context->in_packet, &topic, &slen)) return 1; - if(!slen){ + if(!slen && context->protocol != mosq_p_mqtt5){ /* Invalid publish topic, disconnect client. */ mosquitto__free(topic); return 1; } -#ifdef WITH_BRIDGE - if(context->bridge && context->bridge->topics && context->bridge->topic_remapping){ - for(i=0; ibridge->topic_count; i++){ - cur_topic = &context->bridge->topics[i]; - if((cur_topic->direction == bd_both || cur_topic->direction == bd_in) - && (cur_topic->remote_prefix || cur_topic->local_prefix)){ - - /* Topic mapping required on this topic if the message matches */ - - rc = mosquitto_topic_matches_sub(cur_topic->remote_topic, topic, &match); - if(rc){ - mosquitto__free(topic); - return rc; - } - if(match){ - if(cur_topic->remote_prefix){ - /* This prefix needs removing. */ - if(!strncmp(cur_topic->remote_prefix, topic, strlen(cur_topic->remote_prefix))){ - topic_temp = mosquitto__strdup(topic+strlen(cur_topic->remote_prefix)); - if(!topic_temp){ - mosquitto__free(topic); - return MOSQ_ERR_NOMEM; - } - mosquitto__free(topic); - topic = topic_temp; - } - } - - if(cur_topic->local_prefix){ - /* This prefix needs adding. */ - len = strlen(topic) + strlen(cur_topic->local_prefix)+1; - topic_temp = mosquitto__malloc(len+1); - if(!topic_temp){ - mosquitto__free(topic); - return MOSQ_ERR_NOMEM; - } - snprintf(topic_temp, len, "%s%s", cur_topic->local_prefix, topic); - topic_temp[len] = '\0'; - - mosquitto__free(topic); - topic = topic_temp; - } - break; - } - } - } - } -#endif - if(mosquitto_pub_topic_check(topic) != MOSQ_ERR_SUCCESS){ - /* Invalid publish topic, just swallow it. */ - mosquitto__free(topic); - return 1; - } - if(qos > 0){ if(packet__read_uint16(&context->in_packet, &mid)){ mosquitto__free(topic); @@ -186,6 +134,7 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) break; case MQTT_PROP_TOPIC_ALIAS: + topic_alias = p->value.i16; p_prev = p; p = p->next; break; @@ -209,6 +158,70 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) } mosquitto_property_free_all(&properties); + if(topic && topic_alias){ + rc = alias__add(context, topic, topic_alias); + if(rc) return rc; + }else if(topic == NULL && topic_alias){ + rc = alias__find(context, &topic, topic_alias); + if(rc) return rc; + }else if(topic == NULL && topic_alias == 0){ + return MOSQ_ERR_PROTOCOL; + } + +#ifdef WITH_BRIDGE + if(context->bridge && context->bridge->topics && context->bridge->topic_remapping){ + for(i=0; ibridge->topic_count; i++){ + cur_topic = &context->bridge->topics[i]; + if((cur_topic->direction == bd_both || cur_topic->direction == bd_in) + && (cur_topic->remote_prefix || cur_topic->local_prefix)){ + + /* Topic mapping required on this topic if the message matches */ + + rc = mosquitto_topic_matches_sub(cur_topic->remote_topic, topic, &match); + if(rc){ + mosquitto__free(topic); + return rc; + } + if(match){ + if(cur_topic->remote_prefix){ + /* This prefix needs removing. */ + if(!strncmp(cur_topic->remote_prefix, topic, strlen(cur_topic->remote_prefix))){ + topic_temp = mosquitto__strdup(topic+strlen(cur_topic->remote_prefix)); + if(!topic_temp){ + mosquitto__free(topic); + return MOSQ_ERR_NOMEM; + } + mosquitto__free(topic); + topic = topic_temp; + } + } + + if(cur_topic->local_prefix){ + /* This prefix needs adding. */ + len = strlen(topic) + strlen(cur_topic->local_prefix)+1; + topic_temp = mosquitto__malloc(len+1); + if(!topic_temp){ + mosquitto__free(topic); + return MOSQ_ERR_NOMEM; + } + snprintf(topic_temp, len, "%s%s", cur_topic->local_prefix, topic); + topic_temp[len] = '\0'; + + mosquitto__free(topic); + topic = topic_temp; + } + break; + } + } + } + } +#endif + if(mosquitto_pub_topic_check(topic) != MOSQ_ERR_SUCCESS){ + /* Invalid publish topic, just swallow it. */ + mosquitto__free(topic); + return 1; + } + payloadlen = context->in_packet.remaining_length - context->in_packet.pos; G_PUB_BYTES_RECEIVED_INC(payloadlen); if(context->listener && context->listener->mount_point){ diff --git a/test/broker/02-subpub-qos0-topic-alias.py b/test/broker/02-subpub-qos0-topic-alias.py new file mode 100755 index 0000000000..89b86fbf26 --- /dev/null +++ b/test/broker/02-subpub-qos0-topic-alias.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python + +# Test whether "topic alias" works to the broker +# MQTT v5 + +from mosq_test_helper import * + +rc = 1 +keepalive = 60 +connect1_packet = mosq_test.gen_connect("sub-test", keepalive=keepalive, proto_ver=5) +connack1_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +connect2_packet = mosq_test.gen_connect("pub-test", keepalive=keepalive, proto_ver=5) +connack2_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +mid = 1 +subscribe_packet = mosq_test.gen_subscribe(mid, "subpub/alias", 0, proto_ver=5) +suback_packet = mosq_test.gen_suback(mid, 0, proto_ver=5) + +props = mqtt5_props.gen_uint16_prop(mqtt5_props.PROP_TOPIC_ALIAS, 3) +publish1_packet = mosq_test.gen_publish("subpub/alias", qos=0, payload="message", proto_ver=5, properties=props) + +props = mqtt5_props.gen_uint16_prop(mqtt5_props.PROP_TOPIC_ALIAS, 3) +publish2s_packet = mosq_test.gen_publish("", qos=0, payload="message", proto_ver=5, properties=props) +publish2r_packet = mosq_test.gen_publish("subpub/alias", qos=0, payload="message", proto_ver=5) + + +port = mosq_test.get_port() +broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port) + +try: + sock1 = mosq_test.do_client_connect(connect1_packet, connack1_packet, timeout=5, port=port) + sock2 = mosq_test.do_client_connect(connect2_packet, connack2_packet, timeout=5, port=port) + + sock1.send(publish1_packet) + + mosq_test.do_send_receive(sock2, subscribe_packet, suback_packet, "suback") + + sock1.send(publish2s_packet) + + if mosq_test.expect_packet(sock2, "publish2r", publish2r_packet): + rc = 0 + + sock1.close() + sock2.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index 74b7f43431..f6434d758b 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -60,6 +60,7 @@ endif ./02-subpub-qos2-receive-maximum-1.py ./02-subpub-qos2-receive-maximum-2.py ./02-subpub-qos2-pubrec-error.py + ./02-subpub-qos0-topic-alias.py ./02-unsubscribe-qos0.py ./02-unsubscribe-qos1.py ./02-unsubscribe-qos2.py diff --git a/test/broker/ptest.py b/test/broker/ptest.py index cffe6cb03b..277b972e36 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -43,6 +43,7 @@ (1, './02-subpub-qos2-receive-maximum-1.py'), (1, './02-subpub-qos2-receive-maximum-2.py'), (1, './02-subpub-qos2-pubrec-error.py'), + (1, './02-subpub-qos0-topic-alias.py'), (1, './02-unsubscribe-qos0.py'), (1, './02-unsubscribe-qos1.py'), (1, './02-unsubscribe-qos2.py'), From 85615c1bae3bef9c4908bbb08325c7a40ca01af2 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 18 Jan 2019 21:38:29 +0000 Subject: [PATCH 193/254] AUTH packet can be truncated. --- src/handle_auth.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/handle_auth.c b/src/handle_auth.c index dd5b2d73b2..1520f22d78 100644 --- a/src/handle_auth.c +++ b/src/handle_auth.c @@ -28,7 +28,7 @@ and the Eclipse Distribution License is available at int handle__auth(struct mosquitto_db *db, struct mosquitto *context) { int rc = 0; - uint8_t reason_code; + uint8_t reason_code = 0; mosquitto_property *properties = NULL; if(!context) return MOSQ_ERR_INVAL; @@ -38,11 +38,13 @@ int handle__auth(struct mosquitto_db *db, struct mosquitto *context) return MOSQ_ERR_PROTOCOL; } - if(packet__read_byte(&context->in_packet, &reason_code)) return 1; + if(mosq->in_packet.remaining_length > 0){ + if(packet__read_byte(&context->in_packet, &reason_code)) return 1; - rc = property__read_all(CMD_AUTH, &context->in_packet, &properties); - if(rc) return rc; - mosquitto_property_free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ + rc = property__read_all(CMD_AUTH, &context->in_packet, &properties); + if(rc) return rc; + mosquitto_property_free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ + } return MOSQ_ERR_SUCCESS; } From 0a9885aea1817d5174bc1ecffd5fb6cf225dc636 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 22 Jan 2019 12:12:18 +0000 Subject: [PATCH 194/254] Rename "resv" in connack to "flags" to better match v5 spec. --- test/broker/03-publish-b2c-disconnect-qos1.py | 4 ++-- test/broker/03-publish-b2c-disconnect-qos2.py | 4 ++-- test/broker/03-publish-b2c-qos1-len.py | 2 +- test/broker/03-publish-b2c-qos2-len.py | 2 +- test/broker/03-publish-c2b-disconnect-qos2.py | 2 +- test/broker/03-publish-c2b-qos2-len.py | 2 +- test/broker/05-clean-session-qos1.py | 4 ++-- test/broker/11-persistent-subscription.py | 2 +- test/mosq_test.py | 6 +++--- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/test/broker/03-publish-b2c-disconnect-qos1.py b/test/broker/03-publish-b2c-disconnect-qos1.py index d171346bda..b95cd5768f 100755 --- a/test/broker/03-publish-b2c-disconnect-qos1.py +++ b/test/broker/03-publish-b2c-disconnect-qos1.py @@ -8,8 +8,8 @@ mid = 3265 keepalive = 60 connect_packet = mosq_test.gen_connect("pub-qos1-disco-test", keepalive=keepalive, clean_session=False) -connack1_packet = mosq_test.gen_connack(resv=0, rc=0) -connack2_packet = mosq_test.gen_connack(resv=1, rc=0) +connack1_packet = mosq_test.gen_connack(flags=0, rc=0) +connack2_packet = mosq_test.gen_connack(flags=1, rc=0) subscribe_packet = mosq_test.gen_subscribe(mid, "qos1/disconnect/test", 1) suback_packet = mosq_test.gen_suback(mid, 1) diff --git a/test/broker/03-publish-b2c-disconnect-qos2.py b/test/broker/03-publish-b2c-disconnect-qos2.py index dda48cc2a2..30227655ac 100755 --- a/test/broker/03-publish-b2c-disconnect-qos2.py +++ b/test/broker/03-publish-b2c-disconnect-qos2.py @@ -6,8 +6,8 @@ mid = 3265 keepalive = 60 connect_packet = mosq_test.gen_connect("pub-qos2-disco-test", keepalive=keepalive, clean_session=False) -connack1_packet = mosq_test.gen_connack(resv=0, rc=0) -connack2_packet = mosq_test.gen_connack(resv=1, rc=0) +connack1_packet = mosq_test.gen_connack(flags=0, rc=0) +connack2_packet = mosq_test.gen_connack(flags=1, rc=0) subscribe_packet = mosq_test.gen_subscribe(mid, "qos2/disconnect/test", 2) suback_packet = mosq_test.gen_suback(mid, 2) diff --git a/test/broker/03-publish-b2c-qos1-len.py b/test/broker/03-publish-b2c-qos1-len.py index 4eb82ae586..7be55611a4 100755 --- a/test/broker/03-publish-b2c-qos1-len.py +++ b/test/broker/03-publish-b2c-qos1-len.py @@ -12,7 +12,7 @@ def len_test(test, puback_packet): mid = 3265 keepalive = 60 connect_packet = mosq_test.gen_connect("pub-qos1-test", keepalive=keepalive, clean_session=False, proto_ver=5) - connack_packet = mosq_test.gen_connack(resv=0, rc=0, proto_ver=5) + connack_packet = mosq_test.gen_connack(flags=0, rc=0, proto_ver=5) subscribe_packet = mosq_test.gen_subscribe(mid, "qos1/len/test", 1, proto_ver=5) suback_packet = mosq_test.gen_suback(mid, 1, proto_ver=5) diff --git a/test/broker/03-publish-b2c-qos2-len.py b/test/broker/03-publish-b2c-qos2-len.py index b3f0e76552..28623a027b 100755 --- a/test/broker/03-publish-b2c-qos2-len.py +++ b/test/broker/03-publish-b2c-qos2-len.py @@ -12,7 +12,7 @@ def len_test(test, pubrec_packet, pubcomp_packet): mid = 3265 keepalive = 60 connect_packet = mosq_test.gen_connect("pub-test", keepalive=keepalive, clean_session=False, proto_ver=5) - connack_packet = mosq_test.gen_connack(resv=0, rc=0, proto_ver=5) + connack_packet = mosq_test.gen_connack(flags=0, rc=0, proto_ver=5) subscribe_packet = mosq_test.gen_subscribe(mid, "qos2/len/test", 2, proto_ver=5) suback_packet = mosq_test.gen_suback(mid, 2, proto_ver=5) diff --git a/test/broker/03-publish-c2b-disconnect-qos2.py b/test/broker/03-publish-c2b-disconnect-qos2.py index 02dc238ba0..d45ffadcaa 100755 --- a/test/broker/03-publish-c2b-disconnect-qos2.py +++ b/test/broker/03-publish-c2b-disconnect-qos2.py @@ -6,7 +6,7 @@ mid = 3265 keepalive = 60 connect_packet = mosq_test.gen_connect("pub-qos2-disco-test", keepalive=keepalive, clean_session=False, proto_ver=3) -connack_packet = mosq_test.gen_connack(resv=0, rc=0) +connack_packet = mosq_test.gen_connack(flags=0, rc=0) subscribe_packet = mosq_test.gen_subscribe(mid, "qos2/disconnect/test", 2) suback_packet = mosq_test.gen_suback(mid, 2) diff --git a/test/broker/03-publish-c2b-qos2-len.py b/test/broker/03-publish-c2b-qos2-len.py index 753c571dda..5f9957fe95 100755 --- a/test/broker/03-publish-c2b-qos2-len.py +++ b/test/broker/03-publish-c2b-qos2-len.py @@ -12,7 +12,7 @@ def len_test(test, pubrel_packet): mid = 3265 keepalive = 60 connect_packet = mosq_test.gen_connect("pub-test", keepalive=keepalive, clean_session=False, proto_ver=5) - connack_packet = mosq_test.gen_connack(resv=0, rc=0, proto_ver=5) + connack_packet = mosq_test.gen_connack(flags=0, rc=0, proto_ver=5) mid = 1 publish_packet = mosq_test.gen_publish("qos2/len/test", qos=2, mid=mid, payload="len-message", proto_ver=5) diff --git a/test/broker/05-clean-session-qos1.py b/test/broker/05-clean-session-qos1.py index 22f5603e77..1726546059 100755 --- a/test/broker/05-clean-session-qos1.py +++ b/test/broker/05-clean-session-qos1.py @@ -8,8 +8,8 @@ mid = 109 keepalive = 60 connect_packet = mosq_test.gen_connect("clean-qos2-test", keepalive=keepalive, clean_session=False) -connack1_packet = mosq_test.gen_connack(resv=0, rc=0) -connack2_packet = mosq_test.gen_connack(resv=1, rc=0) +connack1_packet = mosq_test.gen_connack(flags=0, rc=0) +connack2_packet = mosq_test.gen_connack(flags=1, rc=0) disconnect_packet = mosq_test.gen_disconnect() diff --git a/test/broker/11-persistent-subscription.py b/test/broker/11-persistent-subscription.py index ff1328fcde..e64cf2f875 100755 --- a/test/broker/11-persistent-subscription.py +++ b/test/broker/11-persistent-subscription.py @@ -21,7 +21,7 @@ def write_config(filename, port): "persitent-subscription-test", keepalive=keepalive, clean_session=False, ) connack_packet = mosq_test.gen_connack(rc=0) -connack_packet2 = mosq_test.gen_connack(rc=0, resv=1) # session present +connack_packet2 = mosq_test.gen_connack(rc=0, flags=1) # session present subscribe_packet = mosq_test.gen_subscribe(mid, "subpub/qos1", 1) suback_packet = mosq_test.gen_suback(mid, 1) diff --git a/test/mosq_test.py b/test/mosq_test.py index b4a4b12532..891ce73e04 100644 --- a/test/mosq_test.py +++ b/test/mosq_test.py @@ -366,14 +366,14 @@ def gen_connect(client_id, clean_session=True, keepalive=60, username=None, pass packet = packet + struct.pack("!H"+str(len(password))+"s", len(password), password) return packet -def gen_connack(resv=0, rc=0, proto_ver=4, properties=""): +def gen_connack(flags=0, rc=0, proto_ver=4, properties=""): if proto_ver == 5: properties += mqtt5_props.gen_byte_prop(mqtt5_props.PROP_SHARED_SUB_AVAILABLE, 0) properties = mqtt5_props.prop_finalise(properties) - packet = struct.pack('!BBBB', 32, 2+len(properties), resv, rc) + properties + packet = struct.pack('!BBBB', 32, 2+len(properties), flags, rc) + properties else: - packet = struct.pack('!BBBB', 32, 2, resv, rc); + packet = struct.pack('!BBBB', 32, 2, flags, rc); return packet From 6a59e92db8b0076ab504837d57ea1779cec377f7 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 22 Jan 2019 12:43:52 +0000 Subject: [PATCH 195/254] Set remaining message expiry interval when republishing. --- lib/actions.c | 4 +- lib/messages_mosq.c | 4 +- lib/send_mosq.h | 4 +- lib/send_publish.c | 22 ++++-- src/database.c | 19 ++++-- src/handle_auth.c | 2 +- src/handle_connack.c | 4 +- test/broker/02-subpub-qos1-message-expiry.py | 72 ++++++++++++++++++++ test/broker/Makefile | 1 + test/broker/ptest.py | 1 + 10 files changed, 113 insertions(+), 20 deletions(-) create mode 100755 test/broker/02-subpub-qos1-message-expiry.py diff --git a/lib/actions.c b/lib/actions.c index b7abd592d2..bc6e2e1a0f 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -94,7 +94,7 @@ int mosquitto_publish_v5(struct mosquitto *mosq, int *mid, const char *topic, in } if(qos == 0){ - return send__publish(mosq, local_mid, topic, payloadlen, payload, qos, retain, false, outgoing_properties, NULL); + return send__publish(mosq, local_mid, topic, payloadlen, payload, qos, retain, false, outgoing_properties, NULL, 0); }else{ message = mosquitto__calloc(1, sizeof(struct mosquitto_message_all)); if(!message) return MOSQ_ERR_NOMEM; @@ -134,7 +134,7 @@ int mosquitto_publish_v5(struct mosquitto *mosq, int *mid, const char *topic, in message->state = mosq_ms_wait_for_pubrec; } pthread_mutex_unlock(&mosq->out_message_mutex); - return send__publish(mosq, message->msg.mid, message->msg.topic, message->msg.payloadlen, message->msg.payload, message->msg.qos, message->msg.retain, message->dup, outgoing_properties, NULL); + return send__publish(mosq, message->msg.mid, message->msg.topic, message->msg.payloadlen, message->msg.payload, message->msg.qos, message->msg.retain, message->dup, outgoing_properties, NULL, 0); }else{ message->state = mosq_ms_invalid; pthread_mutex_unlock(&mosq->out_message_mutex); diff --git a/lib/messages_mosq.c b/lib/messages_mosq.c index 51f485505c..75e4c9d995 100644 --- a/lib/messages_mosq.c +++ b/lib/messages_mosq.c @@ -260,7 +260,7 @@ int message__remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_dir }else if(cur->msg.qos == 2){ cur->state = mosq_ms_wait_for_pubrec; } - rc = send__publish(mosq, cur->msg.mid, cur->msg.topic, cur->msg.payloadlen, cur->msg.payload, cur->msg.qos, cur->msg.retain, cur->dup, NULL, NULL); + rc = send__publish(mosq, cur->msg.mid, cur->msg.topic, cur->msg.payloadlen, cur->msg.payload, cur->msg.qos, cur->msg.retain, cur->dup, NULL, NULL, 0); if(rc){ pthread_mutex_unlock(&mosq->out_message_mutex); return rc; @@ -330,7 +330,7 @@ void message__retry_check_actual(struct mosquitto *mosq, struct mosquitto_messag case mosq_ms_publish_qos2: messages->timestamp = now; messages->dup = true; - send__publish(mosq, messages->msg.mid, messages->msg.topic, messages->msg.payloadlen, messages->msg.payload, messages->msg.qos, messages->msg.retain, messages->dup, NULL, NULL); + send__publish(mosq, messages->msg.mid, messages->msg.topic, messages->msg.payloadlen, messages->msg.payload, messages->msg.qos, messages->msg.retain, messages->dup, NULL, NULL, 0); break; case mosq_ms_wait_for_pubrel: messages->timestamp = now; diff --git a/lib/send_mosq.h b/lib/send_mosq.h index 897f2eb82d..9e2853b3f9 100644 --- a/lib/send_mosq.h +++ b/lib/send_mosq.h @@ -21,7 +21,7 @@ and the Eclipse Distribution License is available at int send__simple_command(struct mosquitto *mosq, uint8_t command); int send__command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup, uint8_t reason_code, const mosquitto_property *properties); -int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const mosquitto_property *cmsg_props, const mosquitto_property *store_props); +int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const mosquitto_property *cmsg_props, const mosquitto_property *store_props, uint32_t expiry_interval); int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session, const mosquitto_property *properties); int send__disconnect(struct mosquitto *mosq, uint8_t reason_code, const mosquitto_property *properties); @@ -29,7 +29,7 @@ int send__pingreq(struct mosquitto *mosq); int send__pingresp(struct mosquitto *mosq); int send__puback(struct mosquitto *mosq, uint16_t mid); int send__pubcomp(struct mosquitto *mosq, uint16_t mid); -int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const mosquitto_property *cmsg_props, const mosquitto_property *store_props); +int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const mosquitto_property *cmsg_props, const mosquitto_property *store_props, uint32_t expiry_interval); int send__pubrec(struct mosquitto *mosq, uint16_t mid); int send__pubrel(struct mosquitto *mosq, uint16_t mid); int send__subscribe(struct mosquitto *mosq, int *mid, int topic_count, char *const *const topic, int topic_qos, const mosquitto_property *properties); diff --git a/lib/send_publish.c b/lib/send_publish.c index c1d81e0e0f..41b5e9cebd 100644 --- a/lib/send_publish.c +++ b/lib/send_publish.c @@ -37,7 +37,7 @@ and the Eclipse Distribution License is available at #include "send_mosq.h" -int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const mosquitto_property *cmsg_props, const mosquitto_property *store_props) +int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const mosquitto_property *cmsg_props, const mosquitto_property *store_props, uint32_t expiry_interval) { #ifdef WITH_BROKER size_t len; @@ -110,7 +110,7 @@ int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint3 } log__printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBLISH to %s (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes))", mosq->id, dup, qos, retain, mid, mapped_topic, (long)payloadlen); G_PUB_BYTES_SENT_INC(payloadlen); - rc = send__real_publish(mosq, mid, mapped_topic, payloadlen, payload, qos, retain, dup, cmsg_props, store_props); + rc = send__real_publish(mosq, mid, mapped_topic, payloadlen, payload, qos, retain, dup, cmsg_props, store_props, expiry_interval); mosquitto__free(mapped_topic); return rc; } @@ -124,16 +124,17 @@ int send__publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint3 log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBLISH (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes))", mosq->id, dup, qos, retain, mid, topic, (long)payloadlen); #endif - return send__real_publish(mosq, mid, topic, payloadlen, payload, qos, retain, dup, cmsg_props, store_props); + return send__real_publish(mosq, mid, topic, payloadlen, payload, qos, retain, dup, cmsg_props, store_props, expiry_interval); } -int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const mosquitto_property *cmsg_props, const mosquitto_property *store_props) +int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup, const mosquitto_property *cmsg_props, const mosquitto_property *store_props, uint32_t expiry_interval) { struct mosquitto__packet *packet = NULL; int packetlen; int proplen = 0, varbytes; int rc; + mosquitto_property expiry_prop; assert(mosq); @@ -147,11 +148,21 @@ int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, proplen = 0; proplen += property__get_length_all(cmsg_props); proplen += property__get_length_all(store_props); + if(expiry_interval > 0){ + expiry_prop.next = NULL; + expiry_prop.value.i32 = expiry_interval; + expiry_prop.identifier = MQTT_PROP_MESSAGE_EXPIRY_INTERVAL; + expiry_prop.client_generated = false; + + proplen += property__get_length_all(&expiry_prop); + } + varbytes = packet__varint_bytes(proplen); if(varbytes > 4){ /* FIXME - Properties too big, don't publish any - should remove some first really */ cmsg_props = NULL; store_props = NULL; + expiry_interval = 0; }else{ packetlen += proplen + varbytes; } @@ -181,6 +192,9 @@ int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, packet__write_varint(packet, proplen); property__write_all(packet, cmsg_props, false); property__write_all(packet, store_props, false); + if(expiry_interval > 0){ + property__write_all(packet, &expiry_prop, false); + } } /* Payload */ diff --git a/src/database.c b/src/database.c index e00c9ada78..56f4eb91b4 100644 --- a/src/database.c +++ b/src/database.c @@ -887,6 +887,7 @@ int db__message_write(struct mosquitto_db *db, struct mosquitto *context) int msg_count = 0; mosquitto_property *cmsg_props = NULL, *store_props = NULL; time_t now; + uint32_t expiry_interval = 0; if(!context || context->sock == INVALID_SOCKET || (context->state == mosq_cs_connected && !context->id)){ @@ -901,10 +902,14 @@ int db__message_write(struct mosquitto_db *db, struct mosquitto *context) tail = context->inflight_msgs; while(tail){ msg_count++; - if(tail->store->message_expiry_time && now > tail->store->message_expiry_time){ - /* Message is expired, must not send. */ - db__message_remove(db, context, &tail, last); - continue; + if(tail->store->message_expiry_time){ + if(now > tail->store->message_expiry_time){ + /* Message is expired, must not send. */ + db__message_remove(db, context, &tail, last); + continue; + }else{ + expiry_interval = tail->store->message_expiry_time - now; + } } mid = tail->mid; retries = tail->dup; @@ -918,7 +923,7 @@ int db__message_write(struct mosquitto_db *db, struct mosquitto *context) switch(tail->state){ case mosq_ms_publish_qos0: - rc = send__publish(context, mid, topic, payloadlen, payload, qos, retain, retries, cmsg_props, store_props); + rc = send__publish(context, mid, topic, payloadlen, payload, qos, retain, retries, cmsg_props, store_props, expiry_interval); if(!rc){ db__message_remove(db, context, &tail, last); }else{ @@ -927,7 +932,7 @@ int db__message_write(struct mosquitto_db *db, struct mosquitto *context) break; case mosq_ms_publish_qos1: - rc = send__publish(context, mid, topic, payloadlen, payload, qos, retain, retries, cmsg_props, store_props); + rc = send__publish(context, mid, topic, payloadlen, payload, qos, retain, retries, cmsg_props, store_props, expiry_interval); if(!rc){ tail->timestamp = mosquitto_time(); tail->dup = 1; /* Any retry attempts are a duplicate. */ @@ -940,7 +945,7 @@ int db__message_write(struct mosquitto_db *db, struct mosquitto *context) break; case mosq_ms_publish_qos2: - rc = send__publish(context, mid, topic, payloadlen, payload, qos, retain, retries, cmsg_props, store_props); + rc = send__publish(context, mid, topic, payloadlen, payload, qos, retain, retries, cmsg_props, store_props, expiry_interval); if(!rc){ tail->timestamp = mosquitto_time(); tail->dup = 1; /* Any retry attempts are a duplicate. */ diff --git a/src/handle_auth.c b/src/handle_auth.c index 1520f22d78..a4953e4788 100644 --- a/src/handle_auth.c +++ b/src/handle_auth.c @@ -38,7 +38,7 @@ int handle__auth(struct mosquitto_db *db, struct mosquitto *context) return MOSQ_ERR_PROTOCOL; } - if(mosq->in_packet.remaining_length > 0){ + if(context->in_packet.remaining_length > 0){ if(packet__read_byte(&context->in_packet, &reason_code)) return 1; rc = property__read_all(CMD_AUTH, &context->in_packet, &properties); diff --git a/src/handle_connack.c b/src/handle_connack.c index 9ef568123c..d288a6712b 100644 --- a/src/handle_connack.c +++ b/src/handle_connack.c @@ -59,7 +59,7 @@ int handle__connack(struct mosquitto_db *db, struct mosquitto *context) if(context->bridge->notification_topic){ if(!context->bridge->notifications_local_only){ if(send__real_publish(context, mosquitto__mid_generate(context), - context->bridge->notification_topic, 1, ¬ification_payload, 1, true, 0, NULL, NULL)){ + context->bridge->notification_topic, 1, ¬ification_payload, 1, true, 0, NULL, NULL, 0)){ return 1; } @@ -74,7 +74,7 @@ int handle__connack(struct mosquitto_db *db, struct mosquitto *context) notification_payload = '1'; if(!context->bridge->notifications_local_only){ if(send__real_publish(context, mosquitto__mid_generate(context), - notification_topic, 1, ¬ification_payload, 1, true, 0, NULL, NULL)){ + notification_topic, 1, ¬ification_payload, 1, true, 0, NULL, NULL, 0)){ mosquitto__free(notification_topic); return 1; diff --git a/test/broker/02-subpub-qos1-message-expiry.py b/test/broker/02-subpub-qos1-message-expiry.py new file mode 100755 index 0000000000..3ba16773b4 --- /dev/null +++ b/test/broker/02-subpub-qos1-message-expiry.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python + +# Test whether the broker reduces the message expiry interval when republishing. +# MQTT v5 + +# Client connects with clean session set false, subscribes with qos=1, then disconnects +# Helper publishes two messages, one with a short expiry and one with a long expiry +# We wait until the short expiry will have expired but the long one not. +# Client reconnects, expects delivery of the long expiry message with a reduced +# expiry interval property. + +from mosq_test_helper import * + +rc = 1 +mid = 53 +keepalive = 60 +connect_packet = mosq_test.gen_connect("subpub-qos0-test", keepalive=keepalive, proto_ver=5, clean_session=False) +connack1_packet = mosq_test.gen_connack(rc=0, proto_ver=5) +connack2_packet = mosq_test.gen_connack(rc=0, proto_ver=5, flags=1) + +subscribe_packet = mosq_test.gen_subscribe(mid, "subpub/qos1", 1, proto_ver=5) +suback_packet = mosq_test.gen_suback(mid, 1, proto_ver=5) + + + +helper_connect = mosq_test.gen_connect("helper", proto_ver=5) +helper_connack = mosq_test.gen_connack(rc=0, proto_ver=5) + +mid=1 +props = mqtt5_props.gen_uint32_prop(mqtt5_props.PROP_MESSAGE_EXPIRY_INTERVAL, 1) +publish1s_packet = mosq_test.gen_publish("subpub/qos1", mid=mid, qos=1, payload="message1", proto_ver=5, properties=props) +puback1s_packet = mosq_test.gen_puback(mid) + +mid=2 +props = mqtt5_props.gen_uint32_prop(mqtt5_props.PROP_MESSAGE_EXPIRY_INTERVAL, 10) +publish2s_packet = mosq_test.gen_publish("subpub/qos1", mid=mid, qos=1, payload="message2", proto_ver=5, properties=props) +puback2s_packet = mosq_test.gen_puback(mid) + + +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, connack1_packet, timeout=20, port=port) + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback") + sock.close() + + helper = mosq_test.do_client_connect(helper_connect, helper_connack, timeout=20, port=port) + mosq_test.do_send_receive(helper, publish1s_packet, puback1s_packet, "puback 1") + mosq_test.do_send_receive(helper, publish2s_packet, puback2s_packet, "puback 2") + + time.sleep(2) + + sock = mosq_test.do_client_connect(connect_packet, connack2_packet, timeout=20, port=port) + packet = sock.recv(len(publish2s_packet)) + for i in range(9, 5, -1): + props = mqtt5_props.gen_uint32_prop(mqtt5_props.PROP_MESSAGE_EXPIRY_INTERVAL, i) + publish2r_packet = mosq_test.gen_publish("subpub/qos1", mid=2, qos=1, payload="message2", proto_ver=5, properties=props) + if packet == publish2r_packet: + rc = 0 + break + + sock.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index f6434d758b..4dedbc2fac 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -53,6 +53,7 @@ endif ./02-subpub-qos0-v5.py ./02-subpub-qos1-v5.py ./02-subpub-qos2-v5.py + ./02-subpub-qos1-message-expiry.py ./02-subpub-qos1-nolocal.py ./02-subpub-qos0-retain-as-publish.py ./02-subpub-qos0-send-retain.py diff --git a/test/broker/ptest.py b/test/broker/ptest.py index 277b972e36..d9d243c866 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -36,6 +36,7 @@ (1, './02-subpub-qos0-v5.py'), (1, './02-subpub-qos1-v5.py'), (1, './02-subpub-qos2-v5.py'), + (1, './02-subpub-qos1-message-expiry.py'), (1, './02-subpub-qos1-nolocal.py'), (1, './02-subpub-qos0-retain-as-publish.py'), (1, './02-subpub-qos0-send-retain.py'), From ca3782b38d632cb0e00045c9d193e54315b9cadb Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 22 Jan 2019 17:51:57 +0000 Subject: [PATCH 196/254] Test and fixes for will message expiry interval. --- lib/mosquitto_internal.h | 1 + src/bridge.c | 4 +- src/context.c | 1 + src/database.c | 4 +- src/handle_connack.c | 4 +- src/handle_connect.c | 3 + src/logging.c | 4 +- src/mosquitto_broker_internal.h | 2 +- src/sys_tree.c | 54 +++++++-------- .../02-subpub-qos1-message-expiry-will.py | 65 +++++++++++++++++++ test/broker/Makefile | 1 + test/broker/ptest.py | 1 + test/mosq_test.py | 6 +- 13 files changed, 113 insertions(+), 37 deletions(-) create mode 100755 test/broker/02-subpub-qos1-message-expiry-will.py diff --git a/lib/mosquitto_internal.h b/lib/mosquitto_internal.h index a3eac68777..1e057138e2 100644 --- a/lib/mosquitto_internal.h +++ b/lib/mosquitto_internal.h @@ -159,6 +159,7 @@ struct mosquitto_message_all{ enum mosquitto_msg_state state; bool dup; struct mosquitto_message msg; + uint32_t expiry_interval; }; struct mosquitto { diff --git a/src/bridge.c b/src/bridge.c index 46dbf51cf1..86c314df59 100644 --- a/src/bridge.c +++ b/src/bridge.c @@ -339,7 +339,7 @@ int bridge__connect(struct mosquitto_db *db, struct mosquitto *context) if(context->bridge->notification_topic){ if(!context->bridge->initial_notification_done){ notification_payload = '0'; - db__messages_easy_queue(db, context, context->bridge->notification_topic, 1, 1, ¬ification_payload, 1, NULL); + db__messages_easy_queue(db, context, context->bridge->notification_topic, 1, 1, ¬ification_payload, 1, 0, NULL); context->bridge->initial_notification_done = true; } @@ -359,7 +359,7 @@ int bridge__connect(struct mosquitto_db *db, struct mosquitto *context) if(!context->bridge->initial_notification_done){ notification_payload = '0'; - db__messages_easy_queue(db, context, notification_topic, 1, 1, ¬ification_payload, 1, NULL); + db__messages_easy_queue(db, context, notification_topic, 1, 1, ¬ification_payload, 1, 0, NULL); context->bridge->initial_notification_done = true; } diff --git a/src/context.c b/src/context.c index 74a5a8d603..3133e93a00 100644 --- a/src/context.c +++ b/src/context.c @@ -235,6 +235,7 @@ void context__send_will(struct mosquitto_db *db, struct mosquitto *ctxt) ctxt->will->msg.payloadlen, ctxt->will->msg.payload, ctxt->will->msg.retain, + ctxt->will->expiry_interval, &ctxt->will->properties); } } diff --git a/src/database.c b/src/database.c index 56f4eb91b4..e5ebf0e4ba 100644 --- a/src/database.c +++ b/src/database.c @@ -569,7 +569,7 @@ int db__messages_delete(struct mosquitto_db *db, struct mosquitto *context) return MOSQ_ERR_SUCCESS; } -int db__messages_easy_queue(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int qos, uint32_t payloadlen, const void *payload, int retain, mosquitto_property **properties) +int db__messages_easy_queue(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int qos, uint32_t payloadlen, const void *payload, int retain, uint32_t message_expiry_interval, mosquitto_property **properties) { struct mosquitto_msg_store *stored; char *source_id; @@ -604,7 +604,7 @@ int db__messages_easy_queue(struct mosquitto_db *db, struct mosquitto *context, local_properties = *properties; *properties = NULL; } - if(db__message_store(db, source_id, 0, topic_heap, qos, payloadlen, &payload_uhpa, retain, &stored, 0, local_properties, 0)) return 1; + if(db__message_store(db, source_id, 0, topic_heap, qos, payloadlen, &payload_uhpa, retain, &stored, message_expiry_interval, local_properties, 0)) return 1; return sub__messages_queue(db, source_id, topic_heap, qos, retain, &stored); } diff --git a/src/handle_connack.c b/src/handle_connack.c index d288a6712b..4853010072 100644 --- a/src/handle_connack.c +++ b/src/handle_connack.c @@ -64,7 +64,7 @@ int handle__connack(struct mosquitto_db *db, struct mosquitto *context) return 1; } } - db__messages_easy_queue(db, context, context->bridge->notification_topic, 1, 1, ¬ification_payload, 1, NULL); + db__messages_easy_queue(db, context, context->bridge->notification_topic, 1, 1, ¬ification_payload, 1, 0, NULL); }else{ notification_topic_len = strlen(context->bridge->remote_clientid)+strlen("$SYS/broker/connection//state"); notification_topic = mosquitto__malloc(sizeof(char)*(notification_topic_len+1)); @@ -80,7 +80,7 @@ int handle__connack(struct mosquitto_db *db, struct mosquitto *context) return 1; } } - db__messages_easy_queue(db, context, notification_topic, 1, 1, ¬ification_payload, 1, NULL); + db__messages_easy_queue(db, context, notification_topic, 1, 1, ¬ification_payload, 1, 0, NULL); mosquitto__free(notification_topic); } } diff --git a/src/handle_connect.c b/src/handle_connect.c index 739cd4d670..7a4f6198dd 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -167,6 +167,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) char *will_payload = NULL, *will_topic = NULL; char *will_topic_mount; uint16_t will_payloadlen; + uint32_t will_expiry_interval = 0; struct mosquitto_message_all *will_struct = NULL; uint8_t will, will_retain, will_qos, clean_start; uint8_t username_flag, password_flag; @@ -384,6 +385,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) if(protocol_version == PROTOCOL_VERSION_v5){ rc = property__read_all(CMD_WILL, &context->in_packet, &will_struct->properties); if(rc) return rc; + mosquitto_property_read_int32(properties, MQTT_PROP_MESSAGE_EXPIRY_INTERVAL, &will_expiry_interval, false); mosquitto_property_free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ } if(packet__read_string(&context->in_packet, &will_topic, &slen)){ @@ -736,6 +738,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) } context->will->msg.qos = will_qos; context->will->msg.retain = will_retain; + context->will->expiry_interval = will_expiry_interval; } if(db->config->connection_messages == true){ diff --git a/src/logging.c b/src/logging.c index ccb536514c..78ba9ebeff 100644 --- a/src/logging.c +++ b/src/logging.c @@ -239,10 +239,10 @@ int log__vprintf(int priority, const char *fmt, va_list va) return MOSQ_ERR_NOMEM; } snprintf(st, len, "%d: %s", (int)now, s); - db__messages_easy_queue(&int_db, NULL, topic, 2, strlen(st), st, 0, NULL); + db__messages_easy_queue(&int_db, NULL, topic, 2, strlen(st), st, 0, 20, NULL); mosquitto__free(st); }else{ - db__messages_easy_queue(&int_db, NULL, topic, 2, strlen(s), s, 0, NULL); + db__messages_easy_queue(&int_db, NULL, topic, 2, strlen(s), s, 0, 20, NULL); } } mosquitto__free(s); diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index e0e0f5a883..0cbcf44e55 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -564,7 +564,7 @@ int db__message_update(struct mosquitto *context, uint16_t mid, enum mosquitto_m int db__message_write(struct mosquitto_db *db, struct mosquitto *context); void db__message_dequeue_first(struct mosquitto *context); int db__messages_delete(struct mosquitto_db *db, struct mosquitto *context); -int db__messages_easy_queue(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int qos, uint32_t payloadlen, const void *payload, int retain, mosquitto_property **properties); +int db__messages_easy_queue(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int qos, uint32_t payloadlen, const void *payload, int retain, uint32_t message_expiry_interval, mosquitto_property **properties); int db__message_store(struct mosquitto_db *db, const char *source, uint16_t source_mid, char *topic, int qos, uint32_t payloadlen, mosquitto__payload_uhpa *payload, int retain, struct mosquitto_msg_store **stored, uint32_t message_expiry_interval, mosquitto_property *properties, dbid_t store_id); int db__message_store_find(struct mosquitto *context, uint16_t mid, struct mosquitto_msg_store **stored); void db__msg_store_add(struct mosquitto_db *db, struct mosquitto_msg_store *store); diff --git a/src/sys_tree.c b/src/sys_tree.c index 0baf82a53b..207f44c60e 100644 --- a/src/sys_tree.c +++ b/src/sys_tree.c @@ -52,7 +52,7 @@ void sys_tree__init(struct mosquitto_db *db) /* Set static $SYS messages */ snprintf(buf, 64, "mosquitto version %s", VERSION); - db__messages_easy_queue(db, NULL, "$SYS/broker/version", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/version", SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); } static void sys_tree__update_clients(struct mosquitto_db *db, char *buf) @@ -71,12 +71,12 @@ static void sys_tree__update_clients(struct mosquitto_db *db, char *buf) if(client_count != count_total){ client_count = count_total; snprintf(buf, BUFLEN, "%d", client_count); - db__messages_easy_queue(db, NULL, "$SYS/broker/clients/total", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/clients/total", SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); if(client_count > client_max){ client_max = client_count; snprintf(buf, BUFLEN, "%d", client_max); - db__messages_easy_queue(db, NULL, "$SYS/broker/clients/maximum", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/clients/maximum", SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); } } @@ -90,19 +90,19 @@ static void sys_tree__update_clients(struct mosquitto_db *db, char *buf) disconnected_count = 0; } snprintf(buf, BUFLEN, "%d", disconnected_count); - db__messages_easy_queue(db, NULL, "$SYS/broker/clients/inactive", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); - db__messages_easy_queue(db, NULL, "$SYS/broker/clients/disconnected", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/clients/inactive", SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/clients/disconnected", SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); } if(connected_count != count_by_sock){ connected_count = count_by_sock; snprintf(buf, BUFLEN, "%d", connected_count); - db__messages_easy_queue(db, NULL, "$SYS/broker/clients/active", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); - db__messages_easy_queue(db, NULL, "$SYS/broker/clients/connected", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/clients/active", SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/clients/connected", SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); } if(g_clients_expired != clients_expired){ clients_expired = g_clients_expired; snprintf(buf, BUFLEN, "%d", clients_expired); - db__messages_easy_queue(db, NULL, "$SYS/broker/clients/expired", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/clients/expired", SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); } } @@ -117,13 +117,13 @@ static void sys_tree__update_memory(struct mosquitto_db *db, char *buf) if(current_heap != value_ul){ current_heap = value_ul; snprintf(buf, BUFLEN, "%lu", current_heap); - db__messages_easy_queue(db, NULL, "$SYS/broker/heap/current", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/heap/current", SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); } value_ul =mosquitto__max_memory_used(); if(max_heap != value_ul){ max_heap = value_ul; snprintf(buf, BUFLEN, "%lu", max_heap); - db__messages_easy_queue(db, NULL, "$SYS/broker/heap/maximum", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/heap/maximum", SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); } } #endif @@ -135,12 +135,12 @@ static void calc_load(struct mosquitto_db *db, char *buf, const char *topic, boo if (initial) { new_value = *current; snprintf(buf, BUFLEN, "%.2f", new_value); - db__messages_easy_queue(db, NULL, topic, SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, topic, SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); } else { new_value = interval + exponent*((*current) - interval); if(fabs(new_value - (*current)) >= 0.01){ snprintf(buf, BUFLEN, "%.2f", new_value); - db__messages_easy_queue(db, NULL, topic, SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, topic, SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); } } (*current) = new_value; @@ -218,7 +218,7 @@ void sys_tree__update(struct mosquitto_db *db, int interval, time_t start_time) if(interval && now - interval > last_update){ uptime = now - start_time; snprintf(buf, BUFLEN, "%d seconds", (int)uptime); - db__messages_easy_queue(db, NULL, "$SYS/broker/uptime", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/uptime", SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); sys_tree__update_clients(db, buf); bool initial_publish = false; @@ -287,26 +287,26 @@ void sys_tree__update(struct mosquitto_db *db, int interval, time_t start_time) if(db->msg_store_count != msg_store_count){ msg_store_count = db->msg_store_count; snprintf(buf, BUFLEN, "%d", msg_store_count); - db__messages_easy_queue(db, NULL, "$SYS/broker/messages/stored", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); - db__messages_easy_queue(db, NULL, "$SYS/broker/store/messages/count", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/messages/stored", SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/store/messages/count", SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); } if (db->msg_store_bytes != msg_store_bytes){ msg_store_bytes = db->msg_store_bytes; snprintf(buf, BUFLEN, "%lu", msg_store_bytes); - db__messages_easy_queue(db, NULL, "$SYS/broker/store/messages/bytes", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/store/messages/bytes", SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); } if(db->subscription_count != subscription_count){ subscription_count = db->subscription_count; snprintf(buf, BUFLEN, "%d", subscription_count); - db__messages_easy_queue(db, NULL, "$SYS/broker/subscriptions/count", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/subscriptions/count", SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); } if(db->retained_count != retained_count){ retained_count = db->retained_count; snprintf(buf, BUFLEN, "%d", retained_count); - db__messages_easy_queue(db, NULL, "$SYS/broker/retained messages/count", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/retained messages/count", SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); } #ifdef REAL_WITH_MEMORY_TRACKING @@ -316,55 +316,55 @@ void sys_tree__update(struct mosquitto_db *db, int interval, time_t start_time) if(msgs_received != g_msgs_received){ msgs_received = g_msgs_received; snprintf(buf, BUFLEN, "%lu", msgs_received); - db__messages_easy_queue(db, NULL, "$SYS/broker/messages/received", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/messages/received", SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); } if(msgs_sent != g_msgs_sent){ msgs_sent = g_msgs_sent; snprintf(buf, BUFLEN, "%lu", msgs_sent); - db__messages_easy_queue(db, NULL, "$SYS/broker/messages/sent", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/messages/sent", SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); } if(publish_dropped != g_msgs_dropped){ publish_dropped = g_msgs_dropped; snprintf(buf, BUFLEN, "%lu", publish_dropped); - db__messages_easy_queue(db, NULL, "$SYS/broker/publish/messages/dropped", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/publish/messages/dropped", SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); } if(pub_msgs_received != g_pub_msgs_received){ pub_msgs_received = g_pub_msgs_received; snprintf(buf, BUFLEN, "%lu", pub_msgs_received); - db__messages_easy_queue(db, NULL, "$SYS/broker/publish/messages/received", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/publish/messages/received", SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); } if(pub_msgs_sent != g_pub_msgs_sent){ pub_msgs_sent = g_pub_msgs_sent; snprintf(buf, BUFLEN, "%lu", pub_msgs_sent); - db__messages_easy_queue(db, NULL, "$SYS/broker/publish/messages/sent", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/publish/messages/sent", SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); } if(bytes_received != g_bytes_received){ bytes_received = g_bytes_received; snprintf(buf, BUFLEN, "%llu", bytes_received); - db__messages_easy_queue(db, NULL, "$SYS/broker/bytes/received", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/bytes/received", SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); } if(bytes_sent != g_bytes_sent){ bytes_sent = g_bytes_sent; snprintf(buf, BUFLEN, "%llu", bytes_sent); - db__messages_easy_queue(db, NULL, "$SYS/broker/bytes/sent", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/bytes/sent", SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); } if(pub_bytes_received != g_pub_bytes_received){ pub_bytes_received = g_pub_bytes_received; snprintf(buf, BUFLEN, "%llu", pub_bytes_received); - db__messages_easy_queue(db, NULL, "$SYS/broker/publish/bytes/received", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/publish/bytes/received", SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); } if(pub_bytes_sent != g_pub_bytes_sent){ pub_bytes_sent = g_pub_bytes_sent; snprintf(buf, BUFLEN, "%llu", pub_bytes_sent); - db__messages_easy_queue(db, NULL, "$SYS/broker/publish/bytes/sent", SYS_TREE_QOS, strlen(buf), buf, 1, NULL); + db__messages_easy_queue(db, NULL, "$SYS/broker/publish/bytes/sent", SYS_TREE_QOS, strlen(buf), buf, 1, 60, NULL); } last_update = mosquitto_time(); diff --git a/test/broker/02-subpub-qos1-message-expiry-will.py b/test/broker/02-subpub-qos1-message-expiry-will.py new file mode 100755 index 0000000000..b8b139b234 --- /dev/null +++ b/test/broker/02-subpub-qos1-message-expiry-will.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python + +# Test whether the broker reduces the message expiry interval when republishing a will. +# MQTT v5 + +# Client connects with clean session set false, subscribes with qos=1, then disconnects +# Helper publishes two messages, one with a short expiry and one with a long expiry +# We wait until the short expiry will have expired but the long one not. +# Client reconnects, expects delivery of the long expiry message with a reduced +# expiry interval property. + +from mosq_test_helper import * + +rc = 1 +mid = 53 +keepalive = 60 +connect_packet = mosq_test.gen_connect("subpub-qos0-test", keepalive=keepalive, proto_ver=5, clean_session=False) +connack1_packet = mosq_test.gen_connack(rc=0, proto_ver=5) +connack2_packet = mosq_test.gen_connack(rc=0, proto_ver=5, flags=1) + +subscribe_packet = mosq_test.gen_subscribe(mid, "subpub/qos1", 1, proto_ver=5) +suback_packet = mosq_test.gen_suback(mid, 1, proto_ver=5) + + +props = mqtt5_props.gen_uint32_prop(mqtt5_props.PROP_MESSAGE_EXPIRY_INTERVAL, 10) +helper_connect = mosq_test.gen_connect("helper", proto_ver=5, will_topic="subpub/qos1", will_qos=1, will_payload="message", will_properties=props, keepalive=2) +helper_connack = mosq_test.gen_connack(rc=0, proto_ver=5) + +#mid=2 +props = mqtt5_props.gen_uint32_prop(mqtt5_props.PROP_MESSAGE_EXPIRY_INTERVAL, 10) +publish2s_packet = mosq_test.gen_publish("subpub/qos1", mid=mid, qos=1, payload="message2", proto_ver=5, properties=props) +puback2s_packet = mosq_test.gen_puback(mid) + + +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, connack1_packet, timeout=20, port=port) + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback") + sock.close() + + helper = mosq_test.do_client_connect(helper_connect, helper_connack, timeout=20, port=port) + + time.sleep(2) + + sock = mosq_test.do_client_connect(connect_packet, connack2_packet, timeout=20, port=port) + packet = sock.recv(len(publish2s_packet)) + for i in range(10, 5, -1): + props = mqtt5_props.gen_uint32_prop(mqtt5_props.PROP_MESSAGE_EXPIRY_INTERVAL, i) + publish2r_packet = mosq_test.gen_publish("subpub/qos1", mid=1, qos=1, payload="message", proto_ver=5, properties=props) + if packet == publish2r_packet: + rc = 0 + break + + sock.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index 4dedbc2fac..be1f842534 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -54,6 +54,7 @@ endif ./02-subpub-qos1-v5.py ./02-subpub-qos2-v5.py ./02-subpub-qos1-message-expiry.py + ./02-subpub-qos1-message-expiry-will.py ./02-subpub-qos1-nolocal.py ./02-subpub-qos0-retain-as-publish.py ./02-subpub-qos0-send-retain.py diff --git a/test/broker/ptest.py b/test/broker/ptest.py index d9d243c866..e2966d0ea4 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -37,6 +37,7 @@ (1, './02-subpub-qos1-v5.py'), (1, './02-subpub-qos2-v5.py'), (1, './02-subpub-qos1-message-expiry.py'), + (1, './02-subpub-qos1-message-expiry-will.py'), (1, './02-subpub-qos1-nolocal.py'), (1, './02-subpub-qos0-retain-as-publish.py'), (1, './02-subpub-qos0-send-retain.py'), diff --git a/test/mosq_test.py b/test/mosq_test.py index 891ce73e04..95cab4a1ce 100644 --- a/test/mosq_test.py +++ b/test/mosq_test.py @@ -298,7 +298,7 @@ def to_string(packet): # Reserved return "0xF0" -def gen_connect(client_id, clean_session=True, keepalive=60, username=None, password=None, will_topic=None, will_qos=0, will_retain=False, will_payload="", proto_ver=4, connect_reserved=False, properties=""): +def gen_connect(client_id, clean_session=True, keepalive=60, username=None, password=None, will_topic=None, will_qos=0, will_retain=False, will_payload="", proto_ver=4, connect_reserved=False, properties="", will_properties=""): if (proto_ver&0x7F) == 3 or proto_ver == 0: remaining_length = 12 elif (proto_ver&0x7F) == 4 or proto_ver == 5: @@ -330,6 +330,9 @@ def gen_connect(client_id, clean_session=True, keepalive=60, username=None, pass connect_flags = connect_flags | 0x04 | ((will_qos&0x03) << 3) if will_retain: connect_flags = connect_flags | 32 + if proto_ver == 5: + will_properties = mqtt5_props.prop_finalise(will_properties) + remaining_length += len(will_properties) if username != None: remaining_length = remaining_length + 2+len(username) @@ -354,6 +357,7 @@ def gen_connect(client_id, clean_session=True, keepalive=60, username=None, pass packet = packet + struct.pack("!H", 0) if will_topic != None: + packet += will_properties packet = packet + struct.pack("!H"+str(len(will_topic))+"s", len(will_topic), will_topic) if len(will_payload) > 0: packet = packet + struct.pack("!H"+str(len(will_payload))+"s", len(will_payload), will_payload) From 6b977fa198a437549170c0d6b6d19ee526342e9c Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 23 Jan 2019 10:00:13 +0000 Subject: [PATCH 197/254] Test and fixes for expiring retained messages. --- src/subs.c | 30 +++++-- .../02-subpub-qos1-message-expiry-retain.py | 89 +++++++++++++++++++ test/broker/Makefile | 1 + test/broker/ptest.py | 1 + 4 files changed, 113 insertions(+), 8 deletions(-) create mode 100755 test/broker/02-subpub-qos1-message-expiry-retain.py diff --git a/src/subs.c b/src/subs.c index 04bb2231fe..394eb0e806 100644 --- a/src/subs.c +++ b/src/subs.c @@ -646,12 +646,24 @@ void sub__tree_print(struct mosquitto__subhier *root, int level) } } -static int retain__process(struct mosquitto_db *db, struct mosquitto_msg_store *retained, struct mosquitto *context, const char *sub, int sub_qos, uint32_t subscription_identifier) +static int retain__process(struct mosquitto_db *db, struct mosquitto__subhier *branch, struct mosquitto *context, const char *sub, int sub_qos, uint32_t subscription_identifier, time_t now) { int rc = 0; int qos; uint16_t mid; mosquitto_property *properties = NULL; + struct mosquitto_msg_store *retained; + + if(branch->retained->message_expiry_time > 0 && now > branch->retained->message_expiry_time){ + db__msg_store_deref(db, &branch->retained); + branch->retained = NULL; +#ifdef WITH_SYS_TREE + db->retained_count--; +#endif + return MOSQ_ERR_SUCCESS; + } + + retained = branch->retained; rc = mosquitto_acl_check(db, context, retained->topic, retained->payloadlen, UHPA_ACCESS(retained->payload, retained->payloadlen), retained->qos, retained->retain, MOSQ_ACL_READ); @@ -678,7 +690,7 @@ static int retain__process(struct mosquitto_db *db, struct mosquitto_msg_store * return db__message_insert(db, context, mid, mosq_md_out, qos, true, retained, properties); } -static int retain__search(struct mosquitto_db *db, struct mosquitto__subhier *subhier, struct sub__token *tokens, struct mosquitto *context, const char *sub, int sub_qos, uint32_t subscription_identifier, int level) +static int retain__search(struct mosquitto_db *db, struct mosquitto__subhier *subhier, struct sub__token *tokens, struct mosquitto *context, const char *sub, int sub_qos, uint32_t subscription_identifier, time_t now, int level) { struct mosquitto__subhier *branch, *branch_tmp; int flag = 0; @@ -694,25 +706,25 @@ static int retain__search(struct mosquitto_db *db, struct mosquitto__subhier *su */ flag = -1; if(branch->retained){ - retain__process(db, branch->retained, context, sub, sub_qos, subscription_identifier); + retain__process(db, branch, context, sub, sub_qos, subscription_identifier, now); } if(branch->children){ - retain__search(db, branch, tokens, context, sub, sub_qos, subscription_identifier, level+1); + retain__search(db, branch, tokens, context, sub, sub_qos, subscription_identifier, now, level+1); } }else if(strcmp(UHPA_ACCESS_TOPIC(branch), "+") && (!strcmp(UHPA_ACCESS_TOPIC(branch), UHPA_ACCESS_TOPIC(tokens)) || !strcmp(UHPA_ACCESS_TOPIC(tokens), "+"))){ if(tokens->next){ - if(retain__search(db, branch, tokens->next, context, sub, sub_qos, subscription_identifier, level+1) == -1 + if(retain__search(db, branch, tokens->next, context, sub, sub_qos, subscription_identifier, now, level+1) == -1 || (!branch_tmp && tokens->next && !strcmp(UHPA_ACCESS_TOPIC(tokens->next), "#") && level>0)){ if(branch->retained){ - retain__process(db, branch->retained, context, sub, sub_qos, subscription_identifier); + retain__process(db, branch, context, sub, sub_qos, subscription_identifier, now); } } }else{ if(branch->retained){ - retain__process(db, branch->retained, context, sub, sub_qos, subscription_identifier); + retain__process(db, branch, context, sub, sub_qos, subscription_identifier, now); } } } @@ -724,6 +736,7 @@ int sub__retain_queue(struct mosquitto_db *db, struct mosquitto *context, const { struct mosquitto__subhier *subhier; struct sub__token *tokens = NULL, *tail; + time_t now; assert(db); assert(context); @@ -734,7 +747,8 @@ int sub__retain_queue(struct mosquitto_db *db, struct mosquitto *context, const HASH_FIND(hh, db->subs, UHPA_ACCESS_TOPIC(tokens), tokens->topic_len, subhier); if(subhier){ - retain__search(db, subhier, tokens, context, sub, sub_qos, subscription_identifier, 0); + now = time(NULL); + retain__search(db, subhier, tokens, context, sub, sub_qos, subscription_identifier, now, 0); } while(tokens){ tail = tokens->next; diff --git a/test/broker/02-subpub-qos1-message-expiry-retain.py b/test/broker/02-subpub-qos1-message-expiry-retain.py new file mode 100755 index 0000000000..8ff512ea3a --- /dev/null +++ b/test/broker/02-subpub-qos1-message-expiry-retain.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python + +# Test whether the broker reduces the message expiry interval when republishing +# a retained message, and eventually removes it. +# MQTT v5 + +# Helper publishes a message, with a medium length expiry with retained set. It +# publishes a second message with retained set but no expiry. +# Client connects, subscribes, gets messages, disconnects. +# We wait until the expiry will have expired. +# Client connects, subscribes, doesn't get expired message, does get +# non-expired message. + +from mosq_test_helper import * + +rc = 1 +keepalive = 60 +connect_packet = mosq_test.gen_connect("subpub", keepalive=keepalive, proto_ver=5) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +mid = 1 +subscribe1_packet = mosq_test.gen_subscribe(mid, "subpub/expired", 1, proto_ver=5) +suback1_packet = mosq_test.gen_suback(mid, 1, proto_ver=5) + +mid = 2 +subscribe2_packet = mosq_test.gen_subscribe(mid, "subpub/kept", 1, proto_ver=5) +suback2_packet = mosq_test.gen_suback(mid, 1, proto_ver=5) + +helper_connect = mosq_test.gen_connect("helper", proto_ver=5) +helper_connack = mosq_test.gen_connack(rc=0, proto_ver=5) + +mid=1 +props = mqtt5_props.gen_uint32_prop(mqtt5_props.PROP_MESSAGE_EXPIRY_INTERVAL, 4) +publish1_packet = mosq_test.gen_publish("subpub/expired", mid=mid, qos=1, retain=True, payload="message1", proto_ver=5, properties=props) +puback1_packet = mosq_test.gen_puback(mid) + +mid=2 +publish2s_packet = mosq_test.gen_publish("subpub/kept", mid=mid, qos=1, retain=True, payload="message2", proto_ver=5) +puback2s_packet = mosq_test.gen_puback(mid) + +mid=1 +publish2r_packet = mosq_test.gen_publish("subpub/kept", mid=mid, qos=1, retain=True, payload="message2", proto_ver=5) +puback2r_packet = mosq_test.gen_puback(mid) + +pingreq_packet = mosq_test.gen_pingreq() +pingresp_packet = mosq_test.gen_pingresp() + + +port = mosq_test.get_port() +broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port) + +try: + helper = mosq_test.do_client_connect(helper_connect, helper_connack, timeout=20, port=port) + mosq_test.do_send_receive(helper, publish1_packet, puback1_packet, "puback 1") + mosq_test.do_send_receive(helper, publish2s_packet, puback2s_packet, "puback 2") + helper.close() + + sock = mosq_test.do_client_connect(connect_packet, connack_packet, timeout=20, port=port) + mosq_test.do_send_receive(sock, subscribe1_packet, suback1_packet, "suback 1-1") + + if mosq_test.expect_packet(sock, "publish 1", publish1_packet): + sock.send(puback1_packet) + + mosq_test.do_send_receive(sock, subscribe2_packet, suback2_packet, "suback 2-1") + if mosq_test.expect_packet(sock, "publish 2", publish2s_packet): + sock.send(puback2s_packet) + + sock.close() + + time.sleep(5) + sock = mosq_test.do_client_connect(connect_packet, connack_packet, timeout=20, port=port) + mosq_test.do_send_receive(sock, subscribe1_packet, suback1_packet, "suback 1-2") + # We shouldn't receive a publish here + # This will fail if we do receive a publish + mosq_test.do_send_receive(sock, subscribe2_packet, suback2_packet, "suback 2-2") + if mosq_test.expect_packet(sock, "publish 2", publish2r_packet): + sock.send(puback2r_packet) + sock.close() + rc = 0 + +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index be1f842534..713893db82 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -54,6 +54,7 @@ endif ./02-subpub-qos1-v5.py ./02-subpub-qos2-v5.py ./02-subpub-qos1-message-expiry.py + ./02-subpub-qos1-message-expiry-retain.py ./02-subpub-qos1-message-expiry-will.py ./02-subpub-qos1-nolocal.py ./02-subpub-qos0-retain-as-publish.py diff --git a/test/broker/ptest.py b/test/broker/ptest.py index e2966d0ea4..adaf32ba39 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -37,6 +37,7 @@ (1, './02-subpub-qos1-v5.py'), (1, './02-subpub-qos2-v5.py'), (1, './02-subpub-qos1-message-expiry.py'), + (1, './02-subpub-qos1-message-expiry-retain.py'), (1, './02-subpub-qos1-message-expiry-will.py'), (1, './02-subpub-qos1-nolocal.py'), (1, './02-subpub-qos0-retain-as-publish.py'), From e1976739b8e74e2ca5923d91c9a44fa3192a8466 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 23 Jan 2019 16:37:48 +0000 Subject: [PATCH 198/254] Fix duplicate error values. Closes #1109. Thanks to Tifaifai. --- lib/mosquitto.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/mosquitto.h b/lib/mosquitto.h index 8174eca09c..b47faff115 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -89,10 +89,10 @@ enum mosq_err_t { MOSQ_ERR_MALFORMED_UTF8 = 18, MOSQ_ERR_KEEPALIVE = 19, MOSQ_ERR_LOOKUP = 20, - MOSQ_ERR_MALFORMED_PACKET = 19, - MOSQ_ERR_DUPLICATE_PROPERTY = 20, - MOSQ_ERR_TLS_HANDSHAKE = 21, - MOSQ_ERR_QOS_NOT_SUPPORTED = 22, + MOSQ_ERR_MALFORMED_PACKET = 21, + MOSQ_ERR_DUPLICATE_PROPERTY = 22, + MOSQ_ERR_TLS_HANDSHAKE = 23, + MOSQ_ERR_QOS_NOT_SUPPORTED = 24, }; /* Error values */ From 219f47b07f4363b694032ec9d3308788f25abd86 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 25 Jan 2019 21:38:33 +0000 Subject: [PATCH 199/254] Add test for multiple unsubscribe. --- test/broker/02-unsubscribe-qos2-multiple.py | 34 +++++++++++++++++++++ test/broker/Makefile | 1 + test/broker/ptest.py | 1 + test/mosq_test.py | 18 +++++++++++ 4 files changed, 54 insertions(+) create mode 100755 test/broker/02-unsubscribe-qos2-multiple.py diff --git a/test/broker/02-unsubscribe-qos2-multiple.py b/test/broker/02-unsubscribe-qos2-multiple.py new file mode 100755 index 0000000000..b7851f9f83 --- /dev/null +++ b/test/broker/02-unsubscribe-qos2-multiple.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python + +# Test whether a SUBSCRIBE to multiple topics with QoS 2 results in the correct SUBACK packet. + +from mosq_test_helper import * + +rc = 1 +mid = 3 +keepalive = 60 +connect_packet = mosq_test.gen_connect("unsubscribe-qos2-test", keepalive=keepalive) +connack_packet = mosq_test.gen_connack(rc=0) + +unsubscribe_packet = mosq_test.gen_unsubscribe_multiple(mid, ["qos2/one", "qos2/two"]) +unsuback_packet = mosq_test.gen_unsuback(mid) + +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, port=port) + mosq_test.do_send_receive(sock, unsubscribe_packet, unsuback_packet, "unsuback") + + rc = 0 + + sock.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index 713893db82..ecf35df377 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -69,6 +69,7 @@ endif ./02-unsubscribe-qos2.py ./02-unsubscribe-qos2-v5.py ./02-unsubscribe-invalid-no-topic.py + ./02-unsubscribe-qos2-multiple.py ./02-subscribe-invalid-utf8.py ./02-subscribe-persistence-flipflop.py ./02-subhier-crash.py diff --git a/test/broker/ptest.py b/test/broker/ptest.py index adaf32ba39..441946fc3a 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -52,6 +52,7 @@ (1, './02-unsubscribe-qos2.py'), (1, './02-unsubscribe-qos2-v5.py'), (1, './02-unsubscribe-invalid-no-topic.py'), + (1, './02-unsubscribe-qos2-multiple.py'), (1, './02-subscribe-invalid-utf8.py'), (1, './02-subscribe-persistence-flipflop.py'), (1, './02-subhier-crash.py'), diff --git a/test/mosq_test.py b/test/mosq_test.py index 95cab4a1ce..c278cfbb3f 100644 --- a/test/mosq_test.py +++ b/test/mosq_test.py @@ -478,6 +478,24 @@ def gen_unsubscribe(mid, topic, proto_ver=4): pack_format = "!BBHH"+str(len(topic))+"s" return struct.pack(pack_format, 162, 2+2+len(topic), mid, len(topic), topic) +def gen_unsubscribe_multiple(mid, topics, proto_ver=4): + packet = "" + remaining_length = 0 + for t in topics: + remaining_length += 2+len(t) + print(t) + packet += struct.pack("!H"+str(len(t))+"s", len(t), t) + print(packet) + + if proto_ver == 5: + remaining_length += 2+1 + + return struct.pack("!BBHB", 162, remaining_length, mid, 0) + packet + else: + remaining_length += 2 + + return struct.pack("!BBH", 162, remaining_length, mid) + packet + def gen_unsuback(mid, proto_ver=4): if proto_ver == 5: return struct.pack('!BBHB', 176, 3, mid, 0) From 5e7f43c9eabd42a1d625f9f1119ebef21457508d Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 25 Jan 2019 22:02:12 +0000 Subject: [PATCH 200/254] Temporarily disable all extended AUTH. --- src/handle_auth.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/handle_auth.c b/src/handle_auth.c index a4953e4788..fd659fb7d1 100644 --- a/src/handle_auth.c +++ b/src/handle_auth.c @@ -23,6 +23,7 @@ and the Eclipse Distribution License is available at #include "mqtt_protocol.h" #include "packet_mosq.h" #include "property_mosq.h" +#include "send_mosq.h" int handle__auth(struct mosquitto_db *db, struct mosquitto *context) @@ -46,5 +47,7 @@ int handle__auth(struct mosquitto_db *db, struct mosquitto *context) mosquitto_property_free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */ } - return MOSQ_ERR_SUCCESS; + /* FIXME - Extended auth not currently supported */ + send__disconnect(context, MQTT_RC_NOT_AUTHORIZED, NULL); + return 1; } From 873ffce27afb43a736190b0912d0c6e6d4f213a2 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 25 Jan 2019 22:53:31 +0000 Subject: [PATCH 201/254] Send DISCONNECT on invalid topic alias, plus test. --- src/handle_publish.c | 7 +++- .../02-subpub-qos0-topic-alias-unknown.py | 37 +++++++++++++++++++ test/broker/Makefile | 1 + test/broker/ptest.py | 1 + test/mosq_test.py | 2 - 5 files changed, 45 insertions(+), 3 deletions(-) create mode 100755 test/broker/02-subpub-qos0-topic-alias-unknown.py diff --git a/src/handle_publish.c b/src/handle_publish.c index 148e717451..8defeb42a3 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -163,7 +163,12 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) if(rc) return rc; }else if(topic == NULL && topic_alias){ rc = alias__find(context, &topic, topic_alias); - if(rc) return rc; + if(rc){ + if(context->protocol == mosq_p_mqtt5){ + send__disconnect(context, MQTT_RC_TOPIC_ALIAS_INVALID, NULL); + } + return rc; + } }else if(topic == NULL && topic_alias == 0){ return MOSQ_ERR_PROTOCOL; } diff --git a/test/broker/02-subpub-qos0-topic-alias-unknown.py b/test/broker/02-subpub-qos0-topic-alias-unknown.py new file mode 100755 index 0000000000..a79c19e25b --- /dev/null +++ b/test/broker/02-subpub-qos0-topic-alias-unknown.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python + +# Test whether "topic alias" works to the broker +# MQTT v5 + +from mosq_test_helper import * + +rc = 1 +keepalive = 60 +connect_packet = mosq_test.gen_connect("sub-test", keepalive=keepalive, proto_ver=5) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +props = mqtt5_props.gen_uint16_prop(mqtt5_props.PROP_TOPIC_ALIAS, 3) +publish1_packet = mosq_test.gen_publish("", qos=0, payload="message", proto_ver=5, properties=props) + +disconnect_packet = mosq_test.gen_disconnect(reason_code=148, proto_ver=5) + +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=5, port=port) + sock.send(publish1_packet) + + if mosq_test.expect_packet(sock, "disconnect", disconnect_packet): + rc = 0 + + sock.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index ecf35df377..790f2de330 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -64,6 +64,7 @@ endif ./02-subpub-qos2-receive-maximum-2.py ./02-subpub-qos2-pubrec-error.py ./02-subpub-qos0-topic-alias.py + ./02-subpub-qos0-topic-alias-unknown.py ./02-unsubscribe-qos0.py ./02-unsubscribe-qos1.py ./02-unsubscribe-qos2.py diff --git a/test/broker/ptest.py b/test/broker/ptest.py index 441946fc3a..60fdad4357 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -47,6 +47,7 @@ (1, './02-subpub-qos2-receive-maximum-2.py'), (1, './02-subpub-qos2-pubrec-error.py'), (1, './02-subpub-qos0-topic-alias.py'), + (1, './02-subpub-qos0-topic-alias-unknown.py'), (1, './02-unsubscribe-qos0.py'), (1, './02-unsubscribe-qos1.py'), (1, './02-unsubscribe-qos2.py'), diff --git a/test/mosq_test.py b/test/mosq_test.py index c278cfbb3f..f3a9d97391 100644 --- a/test/mosq_test.py +++ b/test/mosq_test.py @@ -483,9 +483,7 @@ def gen_unsubscribe_multiple(mid, topics, proto_ver=4): remaining_length = 0 for t in topics: remaining_length += 2+len(t) - print(t) packet += struct.pack("!H"+str(len(t))+"s", len(t), t) - print(packet) if proto_ver == 5: remaining_length += 2+1 From e179e751c4bc0a6ef665f4b85a16e89af76500fe Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sat, 2 Feb 2019 22:22:28 +0000 Subject: [PATCH 202/254] Update download paths. --- www/pages/download.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/www/pages/download.md b/www/pages/download.md index 2aceb0a53a..cfe4375462 100644 --- a/www/pages/download.md +++ b/www/pages/download.md @@ -12,7 +12,6 @@ # Source * [mosquitto-1.5.5.tar.gz](https://mosquitto.org/files/source/mosquitto-1.5.5.tar.gz) (319kB) ([GPG signature](https://mosquitto.org/files/source/mosquitto-1.5.5.tar.gz.asc)) -* [mosquitto-1.5.4.tar.gz](https://www.eclipse.org/downloads/download.php?file=/mosquitto/source/mosquitto-1.5.4.tar.gz) (via Eclipse) * [Git source code repository](https://github.com/eclipse/mosquitto) (github.com) Older downloads are available at [https://mosquitto.org/files/](../files/) @@ -25,8 +24,8 @@ distributions. ## Windows -* [mosquitto-1.5.4-install-windows-x64.exe](https://www.eclipse.org/downloads/download.php?file=/mosquitto/binary/win64/mosquitto-1.5.4-install-windows-x64.exe) (~360 kB) (64-bit build, Windows Vista and up, built with Visual Studio Community 2017) -* [mosquitto-1.5.4-install-windows-x32.exe](https://www.eclipse.org/downloads/download.php?file=/mosquitto/binary/win32/mosquitto-1.5.4-install-windows-x86.exe) (~360 kB) (32-bit build, Windows Vista and up, built with Visual Studio Community 2017) +* [mosquitto-1.5.5-install-windows-x64.exe](https://mosquitto.org/files/binary/win64/mosquitto-1.5.5-install-windows-x64.exe) (~360 kB) (64-bit build, Windows Vista and up, built with Visual Studio Community 2017) +* [mosquitto-1.5.5-install-windows-x32.exe](https://mosquitto.org/files/binary/win32/mosquitto-1.5.5-install-windows-x86.exe) (~360 kB) (32-bit build, Windows Vista and up, built with Visual Studio Community 2017) See also readme-windows.txt after installing. From f6943b006a00b604deb6830032dfcf855a48b438 Mon Sep 17 00:00:00 2001 From: Maksym Ruchko Date: Fri, 4 Jan 2019 10:39:30 +0000 Subject: [PATCH 203/254] Fixed threaded enum lost in merges Change was part of the original commit e8185ddaa74234c2c37aa529e711cddfc7cede91 "[166] Don't cancel external threads." and then lost during code reorganizing and subsequent merge, commits 970ba58da63b2790607585edcc364b7ada614e3b 81cb7ab547b37edcdf9e22e2ab93cbe260bb924b Signed-off-by: Maksym Ruchko --- lib/packet_mosq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/packet_mosq.c b/lib/packet_mosq.c index 686006fc89..b1dc84f961 100644 --- a/lib/packet_mosq.c +++ b/lib/packet_mosq.c @@ -141,7 +141,7 @@ int packet__queue(struct mosquitto *mosq, struct mosquitto__packet *packet) #endif } - if(mosq->in_callback == false && mosq->threaded == false){ + if(mosq->in_callback == false && mosq->threaded == mosq_ts_none){ return packet__write(mosq); }else{ return MOSQ_ERR_SUCCESS; From 70c4097b6ff165e40ff5538700e90ec8e2184ce8 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 10 Jan 2019 15:51:34 +0000 Subject: [PATCH 204/254] Fix comparison of boolean values in CMake build. Closes #1101. Thanks to Mojca Miklavec and Andrew L. Moore. --- CMakeLists.txt | 20 +++++++++--------- ChangeLog.txt | 7 ++++++ client/CMakeLists.txt | 4 ++-- lib/CMakeLists.txt | 12 +++++------ lib/cpp/CMakeLists.txt | 8 +++---- src/CMakeLists.txt | 48 ++++++++++++++++++++---------------------- 6 files changed, 52 insertions(+), 47 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 265c106d9c..8439e43b46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,7 +51,7 @@ option(WITH_TLS_PSK "Include TLS-PSK support (requires WITH_TLS)?" ON) option(WITH_EC "Include Elliptic Curve support (requires WITH_TLS)?" ON) -if (${WITH_TLS} STREQUAL ON) +if (WITH_TLS) find_package(OpenSSL REQUIRED) add_definitions("-DWITH_TLS") @@ -62,19 +62,19 @@ if (${WITH_TLS} STREQUAL ON) if (${WITH_EC} STREQUAL ON) add_definitions("-DWITH_EC") endif (${WITH_EC} STREQUAL ON) -else (${WITH_TLS} STREQUAL ON) +else (WITH_TLS) set (OPENSSL_INCLUDE_DIR "") -endif (${WITH_TLS} STREQUAL ON) +endif (WITH_TLS) option(WITH_SOCKS "Include SOCKS5 support?" ON) -if (${WITH_SOCKS} STREQUAL ON) +if (WITH_SOCKS) add_definitions("-DWITH_SOCKS") -endif (${WITH_SOCKS} STREQUAL ON) +endif (WITH_SOCKS) option(WITH_SRV "Include SRV lookup support?" OFF) option(WITH_THREADING "Include client library threading support?" ON) -if (${WITH_THREADING} STREQUAL ON) +if (WITH_THREADING) add_definitions("-DWITH_THREADING") if (WIN32) if (CMAKE_CL_64) @@ -92,10 +92,10 @@ if (${WITH_THREADING} STREQUAL ON) endif() set (PTHREAD_INCLUDE_DIR "") endif (WIN32) -else (${WITH_THREADING} STREQUAL ON) +else (WITH_THREADING) set (PTHREAD_LIBRARIES "") set (PTHREAD_INCLUDE_DIR "") -endif (${WITH_THREADING} STREQUAL ON) +endif (WITH_THREADING) option(DOCUMENTATION "Build documentation?" ON) @@ -106,9 +106,9 @@ option(DOCUMENTATION "Build documentation?" ON) add_subdirectory(lib) add_subdirectory(client) add_subdirectory(src) -if (${DOCUMENTATION} STREQUAL ON) +if (DOCUMENTATION) add_subdirectory(man) -endif (${DOCUMENTATION} STREQUAL ON) +endif (DOCUMENTATION) # ======================================== # Install config file diff --git a/ChangeLog.txt b/ChangeLog.txt index ba8864db75..abc7430a08 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,10 @@ +1.5.6 - 201901xx +================ + +Build: +- Fix comparison of boolean values in CMake build. Closes #1101. + + 1.5.5 - 20181211 ================ diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 660bf1ac6a..56b5c73eb4 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -4,9 +4,9 @@ link_directories(${mosquitto_BINARY_DIR}/lib) set(shared_src client_shared.c client_shared.h) -if (${WITH_SRV} STREQUAL ON) +if (WITH_SRV) add_definitions("-DWITH_SRV") -endif (${WITH_SRV} STREQUAL ON) +endif (WITH_SRV) add_executable(mosquitto_pub pub_client.c ${shared_src}) add_executable(mosquitto_sub sub_client.c sub_client_output.c ${shared_src}) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index c92571aa55..5abfd2e0e3 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -60,7 +60,7 @@ if (WIN32) set (LIBRARIES ${LIBRARIES} ws2_32) endif (WIN32) -if (${WITH_SRV} STREQUAL ON) +if (WITH_SRV) # Simple detect c-ares find_path(ARES_HEADER ares.h) if (ARES_HEADER) @@ -69,7 +69,7 @@ if (${WITH_SRV} STREQUAL ON) else (ARES_HEADER) message(WARNING "c-ares library not found.") endif (ARES_HEADER) -endif (${WITH_SRV} STREQUAL ON) +endif (WITH_SRV) add_library(libmosquitto SHARED ${C_SRC}) set_target_properties(libmosquitto PROPERTIES @@ -86,13 +86,13 @@ set_target_properties(libmosquitto PROPERTIES install(TARGETS libmosquitto RUNTIME DESTINATION "${BINDIR}" LIBRARY DESTINATION "${LIBDIR}") -if (${WITH_STATIC_LIBRARIES} STREQUAL ON) +if (WITH_STATIC_LIBRARIES) add_library(libmosquitto_static STATIC ${C_SRC}) - if (${WITH_PIC} STREQUAL ON) + if (WITH_PIC) set_target_properties(libmosquitto_static PROPERTIES POSITION_INDEPENDENT_CODE 1 ) - endif (${WITH_PIC} STREQUAL ON) + endif (WITH_PIC) target_link_libraries(libmosquitto_static ${LIBRARIES}) @@ -103,7 +103,7 @@ if (${WITH_STATIC_LIBRARIES} STREQUAL ON) target_compile_definitions(libmosquitto_static PUBLIC "LIBMOSQUITTO_STATIC") install(TARGETS libmosquitto_static RUNTIME DESTINATION "${BINDIR}" ARCHIVE DESTINATION "${LIBDIR}") -endif (${WITH_STATIC_LIBRARIES} STREQUAL ON) +endif (WITH_STATIC_LIBRARIES) install(FILES mosquitto.h DESTINATION "${INCLUDEDIR}") diff --git a/lib/cpp/CMakeLists.txt b/lib/cpp/CMakeLists.txt index 5e4f08ea95..b2d8621697 100644 --- a/lib/cpp/CMakeLists.txt +++ b/lib/cpp/CMakeLists.txt @@ -15,16 +15,16 @@ set_target_properties(mosquittopp PROPERTIES ) install(TARGETS mosquittopp RUNTIME DESTINATION "${BINDIR}" LIBRARY DESTINATION "${LIBDIR}") -if (${WITH_STATIC_LIBRARIES} STREQUAL ON) +if (WITH_STATIC_LIBRARIES) add_library(mosquittopp_static STATIC ${C_SRC} ${CPP_SRC} ) - if (${WITH_PIC} STREQUAL ON) + if (WITH_PIC) set_target_properties(mosquittopp_static PROPERTIES POSITION_INDEPENDENT_CODE 1 ) - endif (${WITH_PIC} STREQUAL ON) + endif (WITH_PIC) target_link_libraries(mosquittopp_static ${LIBRARIES}) @@ -35,7 +35,7 @@ if (${WITH_STATIC_LIBRARIES} STREQUAL ON) target_compile_definitions(mosquittopp_static PUBLIC "LIBMOSQUITTO_STATIC") install(TARGETS mosquittopp_static RUNTIME DESTINATION "${BINDIR}" ARCHIVE DESTINATION "${LIBDIR}") -endif (${WITH_STATIC_LIBRARIES} STREQUAL ON) +endif (WITH_STATIC_LIBRARIES) install(FILES mosquittopp.h DESTINATION "${INCLUDEDIR}") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 187d0aac6f..baf6e31369 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -52,62 +52,62 @@ set (MOSQ_SRCS option(WITH_BUNDLED_DEPS "Build with bundled dependencies?" ON) -if (${WITH_BUNDLED_DEPS} STREQUAL ON) +if (WITH_BUNDLED_DEPS) include_directories(${mosquitto_SOURCE_DIR} ${mosquitto_SOURCE_DIR}/src/deps) -endif (${WITH_BUNDLED_DEPS} STREQUAL ON) +endif (WITH_BUNDLED_DEPS) option(INC_BRIDGE_SUPPORT "Include bridge support for connecting to other brokers?" ON) -if (${INC_BRIDGE_SUPPORT} STREQUAL ON) +if (INC_BRIDGE_SUPPORT) set (MOSQ_SRCS ${MOSQ_SRCS} bridge.c) add_definitions("-DWITH_BRIDGE") -endif (${INC_BRIDGE_SUPPORT} STREQUAL ON) +endif (INC_BRIDGE_SUPPORT) option(USE_LIBWRAP "Include tcp-wrappers support?" OFF) -if (${USE_LIBWRAP} STREQUAL ON) +if (USE_LIBWRAP) set (MOSQ_LIBS ${MOSQ_LIBS} wrap) add_definitions("-DWITH_WRAP") -endif (${USE_LIBWRAP} STREQUAL ON) +endif (USE_LIBWRAP) option(INC_DB_UPGRADE "Include database upgrade support? (recommended)" ON) option(INC_MEMTRACK "Include memory tracking support?" ON) -if (${INC_MEMTRACK} STREQUAL ON) +if (INC_MEMTRACK) add_definitions("-DWITH_MEMORY_TRACKING") -endif (${INC_MEMTRACK} STREQUAL ON) +endif (INC_MEMTRACK) option(WITH_PERSISTENCE "Include persistence support?" ON) -if (${WITH_PERSISTENCE} STREQUAL ON) +if (WITH_PERSISTENCE) add_definitions("-DWITH_PERSISTENCE") -endif (${WITH_PERSISTENCE} STREQUAL ON) +endif (WITH_PERSISTENCE) option(WITH_SYS_TREE "Include $SYS tree support?" ON) -if (${WITH_SYS_TREE} STREQUAL ON) +if (WITH_SYS_TREE) add_definitions("-DWITH_SYS_TREE") -endif (${WITH_SYS_TREE} STREQUAL ON) +endif (WITH_SYS_TREE) if (CMAKE_SYSTEM_NAME STREQUAL Linux) option(WITH_SYSTEMD "Include systemd support?" OFF) - if (${WITH_SYSTEMD} STREQUAL ON) + if (WITH_SYSTEMD) add_definitions("-DWITH_SYSTEMD") find_library(SYSTEMD_LIBRARY systemd) set (MOSQ_LIBS ${MOSQ_LIBS} ${SYSTEMD_LIBRARY}) - endif (${WITH_SYSTEMD} STREQUAL ON) + endif (WITH_SYSTEMD) endif (CMAKE_SYSTEM_NAME STREQUAL Linux) option(WITH_WEBSOCKETS "Include websockets support?" OFF) option(STATIC_WEBSOCKETS "Use the static libwebsockets library?" OFF) -if (${WITH_WEBSOCKETS} STREQUAL ON ) +if (WITH_WEBSOCKETS) add_definitions("-DWITH_WEBSOCKETS") -endif (${WITH_WEBSOCKETS} STREQUAL ON) +endif (WITH_WEBSOCKETS) if (WIN32 OR CYGWIN) set (MOSQ_SRCS ${MOSQ_SRCS} service.c) @@ -144,17 +144,17 @@ if (WIN32) set (MOSQ_LIBS ${MOSQ_LIBS} ws2_32) endif (WIN32) -if (${WITH_WEBSOCKETS} STREQUAL ON) - if (${STATIC_WEBSOCKETS} STREQUAL ON) +if (WITH_WEBSOCKETS) + if (STATIC_WEBSOCKETS) set (MOSQ_LIBS ${MOSQ_LIBS} websockets_static) if (WIN32) set (MOSQ_LIBS ${MOSQ_LIBS} iphlpapi) link_directories(${mosquitto_SOURCE_DIR}) endif (WIN32) - else (${STATIC_WEBSOCKETS} STREQUAL ON) + else (STATIC_WEBSOCKETS) set (MOSQ_LIBS ${MOSQ_LIBS} websockets) - endif (${STATIC_WEBSOCKETS} STREQUAL ON) -endif (${WITH_WEBSOCKETS} STREQUAL ON) + endif (STATIC_WEBSOCKETS) +endif (WITH_WEBSOCKETS) # Simple detect libuuid if(NOT APPLE) @@ -179,14 +179,12 @@ endif (UNIX) install(TARGETS mosquitto RUNTIME DESTINATION "${SBINDIR}" LIBRARY DESTINATION "${LIBDIR}") install(FILES mosquitto_broker.h mosquitto_plugin.h DESTINATION "${INCLUDEDIR}") -if (${WITH_TLS} STREQUAL ON) +if (WITH_TLS) add_executable(mosquitto_passwd mosquitto_passwd.c) target_link_libraries(mosquitto_passwd ${OPENSSL_LIBRARIES}) install(TARGETS mosquitto_passwd RUNTIME DESTINATION "${BINDIR}" LIBRARY DESTINATION "${LIBDIR}") -endif (${WITH_TLS} STREQUAL ON) +endif (WITH_TLS) if (UNIX AND NOT APPLE) install(CODE "EXEC_PROGRAM(/sbin/ldconfig)") endif (UNIX AND NOT APPLE) - - From be9c1071b001b2031f35ce36ac2db5d4d0351088 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 10 Jan 2019 17:44:46 +0000 Subject: [PATCH 205/254] Fix compilation when openssl deprecated APIs are not available. Closes #1094. Thanks to Rosen Penev. --- ChangeLog.txt | 2 ++ lib/net_mosq.c | 20 ++++++++++++-------- lib/util_mosq.c | 3 +++ src/mosquitto_passwd.c | 2 ++ 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index abc7430a08..0d96ad9f46 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -3,6 +3,8 @@ Build: - Fix comparison of boolean values in CMake build. Closes #1101. +- Fix compilation when openssl deprecated APIs are not available. + Closes #1094. 1.5.5 - 20181211 diff --git a/lib/net_mosq.c b/lib/net_mosq.c index 09a26042dc..6ff60a9345 100644 --- a/lib/net_mosq.c +++ b/lib/net_mosq.c @@ -87,9 +87,11 @@ int net__init(void) #endif #ifdef WITH_TLS +# if OPENSSL_VERSION_NUMBER < 0x10100000L || OPENSSL_API_COMPAT < 0x10100000L SSL_load_error_strings(); SSL_library_init(); OpenSSL_add_all_algorithms(); +# endif if(tls_ex_index_mosq == -1){ tls_ex_index_mosq = SSL_get_ex_new_index(0, "client context", NULL, NULL, NULL); } @@ -100,16 +102,18 @@ int net__init(void) void net__cleanup(void) { #ifdef WITH_TLS - #if OPENSSL_VERSION_NUMBER < 0x10100000L - ERR_remove_state(0); - #endif - #ifndef OPENSSL_NO_ENGINE - ENGINE_cleanup(); - #endif - CONF_modules_unload(1); +# if OPENSSL_VERSION_NUMBER < 0x10100000L || OPENSSL_API_COMPAT < 0x10100000L + CRYPTO_cleanup_all_ex_data(); ERR_free_strings(); + ERR_remove_state(0); EVP_cleanup(); - CRYPTO_cleanup_all_ex_data(); + +# if !defined(OPENSSL_NO_ENGINE) + ENGINE_cleanup(); +# endif +# endif + + CONF_modules_unload(1); #endif #ifdef WITH_SRV diff --git a/lib/util_mosq.c b/lib/util_mosq.c index d98bbde448..72666872f3 100644 --- a/lib/util_mosq.c +++ b/lib/util_mosq.c @@ -28,6 +28,9 @@ and the Eclipse Distribution License is available at # include #endif +#ifdef WITH_TLS +# include +#endif #ifdef WITH_BROKER #include "mosquitto_broker_internal.h" diff --git a/src/mosquitto_passwd.c b/src/mosquitto_passwd.c index 5b303c1a1d..c9d5cbe89e 100644 --- a/src/mosquitto_passwd.c +++ b/src/mosquitto_passwd.c @@ -387,7 +387,9 @@ int main(int argc, char *argv[]) signal(SIGINT, handle_sigint); signal(SIGTERM, handle_sigint); +#if OPENSSL_VERSION_NUMBER < 0x10100000L || OPENSSL_API_COMPAT < 0x10100000L OpenSSL_add_all_digests(); +#endif if(argc == 1){ print_usage(); From 78259850ed87bc19500986fcfce71cae12cc7cd7 Mon Sep 17 00:00:00 2001 From: Vinod Kumar Date: Thu, 27 Dec 2018 14:04:12 +0530 Subject: [PATCH 206/254] ignore inline comments while parsing optional config params Signed-off-by: Vinod Kumar --- src/conf.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/conf.c b/src/conf.c index 0968d326cc..c995babef2 100644 --- a/src/conf.c +++ b/src/conf.c @@ -766,6 +766,9 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct return MOSQ_ERR_INVAL; } while((token = strtok_r(NULL, " ", &saveptr))){ + if (token[0] == '#'){ + break; + } cur_bridge->address_count++; cur_bridge->addresses = mosquitto__realloc(cur_bridge->addresses, sizeof(struct bridge_address)*cur_bridge->address_count); if(!cur_bridge->addresses){ @@ -1327,7 +1330,10 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct cur_listener->security_options.allow_anonymous = -1; cur_listener->protocol = mp_mqtt; cur_listener->port = tmp_int; - token = strtok_r(NULL, "", &saveptr); + token = strtok_r(NULL, " ", &saveptr); + if (token != NULL && token[0] == '#'){ + token = NULL; + } mosquitto__free(cur_listener->host); if(token){ cur_listener->host = mosquitto__strdup(token); @@ -1871,6 +1877,9 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct } token = strtok_r(NULL, " ", &saveptr); if(token){ + if (token[0] == '#'){ + strtok_r(NULL, "", &saveptr); + } cur_topic->qos = atoi(token); if(cur_topic->qos < 0 || cur_topic->qos > 2){ log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge QoS level '%s'.", token); @@ -1880,8 +1889,11 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct token = strtok_r(NULL, " ", &saveptr); if(token){ cur_bridge->topic_remapping = true; - if(!strcmp(token, "\"\"")){ + if(!strcmp(token, "\"\"") || token[0] == '#'){ cur_topic->local_prefix = NULL; + if (token[0] == '#'){ + strtok_r(NULL, "", &saveptr); + } }else{ if(mosquitto_pub_topic_check(token) != MOSQ_ERR_SUCCESS){ log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge topic local prefix '%s'.", token); @@ -1896,7 +1908,7 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct token = strtok_r(NULL, " ", &saveptr); if(token){ - if(!strcmp(token, "\"\"")){ + if(!strcmp(token, "\"\"") || token[0] == '#'){ cur_topic->remote_prefix = NULL; }else{ if(mosquitto_pub_topic_check(token) != MOSQ_ERR_SUCCESS){ From a2b78d87a638585f557efd958c5565436e7ae3ed Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 15 Jan 2019 12:37:45 +0000 Subject: [PATCH 207/254] Update changelog --- ChangeLog.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ChangeLog.txt b/ChangeLog.txt index 0d96ad9f46..79c6bbe4c3 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,6 +1,9 @@ 1.5.6 - 201901xx ================ +Broker: +- Fixed comment handling for config options that have optional arguments. + Build: - Fix comparison of boolean values in CMake build. Closes #1101. - Fix compilation when openssl deprecated APIs are not available. From e8320cbf19c1e97958c093d54a4bbae69cba2280 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 15 Jan 2019 13:21:12 +0000 Subject: [PATCH 208/254] Fix TLS connections not working over SOCKS. Thanks to Mark Oeltjenbruns. --- ChangeLog.txt | 3 +++ lib/net_mosq.c | 11 ++++++++--- lib/net_mosq.h | 2 +- lib/socks_mosq.c | 4 ++++ 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 79c6bbe4c3..48a7614bec 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -4,6 +4,9 @@ Broker: - Fixed comment handling for config options that have optional arguments. +Library: +- Fix TLS connections not working over SOCKS. + Build: - Fix comparison of boolean values in CMake build. Closes #1101. - Fix compilation when openssl deprecated APIs are not available. diff --git a/lib/net_mosq.c b/lib/net_mosq.c index 6ff60a9345..2473da4c6e 100644 --- a/lib/net_mosq.c +++ b/lib/net_mosq.c @@ -610,7 +610,7 @@ static int net__init_ssl_ctx(struct mosquitto *mosq) #endif -int net__socket_connect_step3(struct mosquitto *mosq, const char *host, uint16_t port, const char *bind_address, bool blocking) +int net__socket_connect_step3(struct mosquitto *mosq, const char *host) { #ifdef WITH_TLS BIO *bio; @@ -671,8 +671,13 @@ int net__socket_connect(struct mosquitto *mosq, const char *host, uint16_t port, mosq->sock = sock; - rc = net__socket_connect_step3(mosq, host, port, bind_address, blocking); - if(rc) return rc; +#ifdef WITH_SOCKS + if(!mosq->socks5_host) +#endif + { + rc = net__socket_connect_step3(mosq, host); + if(rc) return rc; + } return MOSQ_ERR_SUCCESS; } diff --git a/lib/net_mosq.h b/lib/net_mosq.h index ea7296656f..702034dbc0 100644 --- a/lib/net_mosq.h +++ b/lib/net_mosq.h @@ -61,7 +61,7 @@ int net__socket_close(struct mosquitto *mosq); int net__try_connect(struct mosquitto *mosq, const char *host, uint16_t port, mosq_sock_t *sock, const char *bind_address, bool blocking); int net__try_connect_step1(struct mosquitto *mosq, const char *host); int net__try_connect_step2(struct mosquitto *mosq, uint16_t port, mosq_sock_t *sock); -int net__socket_connect_step3(struct mosquitto *mosq, const char *host, uint16_t port, const char *bind_address, bool blocking); +int net__socket_connect_step3(struct mosquitto *mosq, const char *host); int net__socket_nonblock(mosq_sock_t *sock); int net__socketpair(mosq_sock_t *sp1, mosq_sock_t *sp2); diff --git a/lib/socks_mosq.c b/lib/socks_mosq.c index e7d597f7f1..ea524c1f58 100644 --- a/lib/socks_mosq.c +++ b/lib/socks_mosq.c @@ -424,6 +424,10 @@ int socks5__read(struct mosquitto *mosq) /* Auth passed */ packet__cleanup(&mosq->in_packet); mosq->state = mosq_cs_new; + if(mosq->socks5_host){ + int rc = net__socket_connect_step3(mosq, mosq->host); + if(rc) return rc; + } return send__connect(mosq, mosq->keepalive, mosq->clean_session); }else{ i = mosq->in_packet.payload[1]; From 4325c44baf1712b75eb6f2ece422f20a921acaec Mon Sep 17 00:00:00 2001 From: Matthias Stone Date: Wed, 12 Dec 2018 17:44:18 -0700 Subject: [PATCH 209/254] Don't clear SSL context when TLS connection is closed. Previous behaviour would clear the external SSL_CTX provided by MOSQ_OPT_SSL_CTX. This required the user to reset the SSL_CTX every disconnect, and trust that they were not leaking references. Recreating the SSL context for every connection is not necessary, and the SSL context is freed in mosquitto_destroy, which is sufficient. Signed-off-by: Matthias Stone --- lib/net_mosq.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/net_mosq.c b/lib/net_mosq.c index 2473da4c6e..c7de615af1 100644 --- a/lib/net_mosq.c +++ b/lib/net_mosq.c @@ -149,10 +149,6 @@ int net__socket_close(struct mosquitto *mosq) SSL_free(mosq->ssl); mosq->ssl = NULL; } - if(mosq->ssl_ctx){ - SSL_CTX_free(mosq->ssl_ctx); - mosq->ssl_ctx = NULL; - } } #endif From ad42f449d81823fe1798b670587c90c215f31273 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 15 Jan 2019 14:23:01 +0000 Subject: [PATCH 210/254] Update changelog for previous PR. Thanks to Matthias Stone. --- ChangeLog.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog.txt b/ChangeLog.txt index 48a7614bec..9f7a860b6b 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -6,6 +6,8 @@ Broker: Library: - Fix TLS connections not working over SOCKS. +- Don't clear SSL context when TLS connection is closed, meaning if a user + provided an external SSL_CTX they have less chance of leaking references. Build: - Fix comparison of boolean values in CMake build. Closes #1101. From 495e9647c229ae6ad4a5bb5af1e5c8c670b1c8f6 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 22 Jan 2019 09:51:20 +0000 Subject: [PATCH 211/254] Improve bridge remapping documentation. --- ChangeLog.txt | 1 + man/mosquitto.conf.5.xml | 30 +++++++++++++++++++----------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 9f7a860b6b..b9faac5af0 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -3,6 +3,7 @@ Broker: - Fixed comment handling for config options that have optional arguments. +- Improved documentation around bridge topic remapping. Library: - Fix TLS connections not working over SOCKS. diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml index d5dcc50b65..df7a3725b4 100644 --- a/man/mosquitto.conf.5.xml +++ b/man/mosquitto.conf.5.xml @@ -1359,27 +1359,35 @@ "". Using the empty marker for the topic itself is also valid. The table below defines what combination of empty or value is - valid. + valid. The and + show the resulting + topics that would be used on the local and remote ends + of the bridge. For example, for the first table row if + you publish to on the local + broker, then the remote broker will receive a message + on the topic . + - + - Topic Local Prefix Remote Prefix Validity + Full Local Topic + Full Remote Topic - 1valuevaluevaluevalid - 2valuevalue""valid - 3value""valuevalid - 4value""""valid (no remapping) - 5""valuevaluevalid (remap single local topic to remote) - 6""value""invalid - 7""""valueinvalid - 8""""""invalid + topicL/R/validL/topicR/topic + topicL/""validL/topictopic + topic""R/validtopicR/topic + topic""""valid (no remapping)topictopic + ""localremotevalid (remap single local topic to remote)localremote + ""local""invalid + """"remoteinvalid + """"""invalid From 760b2f125c5ebdd43b43281290da219d92cdb32a Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 22 Jan 2019 23:04:55 +0000 Subject: [PATCH 212/254] Make table more consistent with preceding documentation. --- man/mosquitto.conf.5.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml index df7a3725b4..8b212e2db7 100644 --- a/man/mosquitto.conf.5.xml +++ b/man/mosquitto.conf.5.xml @@ -1371,7 +1371,7 @@ - Topic + Pattern Local Prefix Remote Prefix Validity @@ -1380,10 +1380,10 @@ - topicL/R/validL/topicR/topic - topicL/""validL/topictopic - topic""R/validtopicR/topic - topic""""valid (no remapping)topictopic + patternL/R/validL/patternR/pattern + patternL/""validL/patternpattern + pattern""R/validpatternR/pattern + pattern""""valid (no remapping)patternpattern ""localremotevalid (remap single local topic to remote)localremote ""local""invalid """"remoteinvalid From 52362951592f70f8a869dff49498530b05dba5ed Mon Sep 17 00:00:00 2001 From: Roger Light Date: Wed, 23 Jan 2019 11:44:19 +0000 Subject: [PATCH 213/254] Handle mismatched handshakes properly. For example, a QoS1 PUBLISH with QoS2 reply. --- ChangeLog.txt | 1 + lib/handle_pubackcomp.c | 9 ++- lib/handle_pubrec.c | 4 +- lib/handle_pubrel.c | 10 ++- lib/messages_mosq.c | 17 ++++-- lib/messages_mosq.h | 6 +- src/database.c | 19 ++++-- src/mosquitto_broker_internal.h | 4 +- test/broker/02-subpub-qos1-bad-pubcomp.py | 69 +++++++++++++++++++++ test/broker/02-subpub-qos1-bad-pubrec.py | 65 ++++++++++++++++++++ test/broker/02-subpub-qos2-bad-puback-1.py | 68 +++++++++++++++++++++ test/broker/02-subpub-qos2-bad-puback-2.py | 71 ++++++++++++++++++++++ test/broker/02-subpub-qos2-bad-pubcomp.py | 68 +++++++++++++++++++++ test/broker/Makefile | 5 ++ test/broker/ptest.py | 5 ++ 15 files changed, 401 insertions(+), 20 deletions(-) create mode 100755 test/broker/02-subpub-qos1-bad-pubcomp.py create mode 100755 test/broker/02-subpub-qos1-bad-pubrec.py create mode 100755 test/broker/02-subpub-qos2-bad-puback-1.py create mode 100755 test/broker/02-subpub-qos2-bad-puback-2.py create mode 100755 test/broker/02-subpub-qos2-bad-pubcomp.py diff --git a/ChangeLog.txt b/ChangeLog.txt index b9faac5af0..6bb4cae9de 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -4,6 +4,7 @@ Broker: - Fixed comment handling for config options that have optional arguments. - Improved documentation around bridge topic remapping. +- Handle mismatched handshakes (e.g. QoS1 PUBLISH with QoS2 reply) properly. Library: - Fix TLS connections not working over SOCKS. diff --git a/lib/handle_pubackcomp.c b/lib/handle_pubackcomp.c index 37788456bd..b86c26d7c4 100644 --- a/lib/handle_pubackcomp.c +++ b/lib/handle_pubackcomp.c @@ -44,15 +44,17 @@ int handle__pubackcomp(struct mosquitto *mosq, const char *type) { uint16_t mid; int rc; + int qos; assert(mosq); rc = packet__read_uint16(&mosq->in_packet, &mid); if(rc) return rc; + qos = type[3] == 'A'?1:2; /* pubAck or pubComp */ #ifdef WITH_BROKER log__printf(NULL, MOSQ_LOG_DEBUG, "Received %s from %s (Mid: %d)", type, mosq->id, mid); if(mid){ - rc = db__message_delete(db, mosq, mid, mosq_md_out); + rc = db__message_delete(db, mosq, mid, mosq_md_out, qos); if(rc == MOSQ_ERR_NOT_FOUND){ log__printf(mosq, MOSQ_LOG_WARNING, "Warning: Received %s from %s for an unknown packet identifier %d.", type, mosq->id, mid); return MOSQ_ERR_SUCCESS; @@ -63,7 +65,10 @@ int handle__pubackcomp(struct mosquitto *mosq, const char *type) #else log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received %s (Mid: %d)", mosq->id, type, mid); - if(!message__delete(mosq, mid, mosq_md_out)){ + rc = message__delete(mosq, mid, mosq_md_out, qos); + if(rc){ + return rc; + }else{ /* Only inform the client the message has been sent once. */ pthread_mutex_lock(&mosq->callback_mutex); if(mosq->on_publish){ diff --git a/lib/handle_pubrec.c b/lib/handle_pubrec.c index 59eea1b7e7..a610af39b3 100644 --- a/lib/handle_pubrec.c +++ b/lib/handle_pubrec.c @@ -46,11 +46,11 @@ int handle__pubrec(struct mosquitto *mosq) #ifdef WITH_BROKER log__printf(NULL, MOSQ_LOG_DEBUG, "Received PUBREC from %s (Mid: %d)", mosq->id, mid); - rc = db__message_update(mosq, mid, mosq_md_out, mosq_ms_wait_for_pubcomp); + rc = db__message_update(mosq, mid, mosq_md_out, mosq_ms_wait_for_pubcomp, 2); #else log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received PUBREC (Mid: %d)", mosq->id, mid); - rc = message__out_update(mosq, mid, mosq_ms_wait_for_pubcomp); + rc = message__out_update(mosq, mid, mosq_ms_wait_for_pubcomp, 2); #endif if(rc == MOSQ_ERR_NOT_FOUND){ log__printf(mosq, MOSQ_LOG_WARNING, "Warning: Received PUBREC from %s for an unknown packet identifier %d.", mosq->id, mid); diff --git a/lib/handle_pubrel.c b/lib/handle_pubrel.c index 56660987c9..81f33ebbb7 100644 --- a/lib/handle_pubrel.c +++ b/lib/handle_pubrel.c @@ -55,7 +55,10 @@ int handle__pubrel(struct mosquitto_db *db, struct mosquitto *mosq) #ifdef WITH_BROKER log__printf(NULL, MOSQ_LOG_DEBUG, "Received PUBREL from %s (Mid: %d)", mosq->id, mid); - if(db__message_release(db, mosq, mid, mosq_md_in)){ + rc = db__message_release(db, mosq, mid, mosq_md_in); + if(rc == MOSQ_ERR_PROTOCOL){ + return rc; + }else if(rc != MOSQ_ERR_SUCCESS){ /* Message not found. Still send a PUBCOMP anyway because this could be * due to a repeated PUBREL after a client has reconnected. */ log__printf(mosq, MOSQ_LOG_WARNING, "Warning: Received PUBREL from %s for an unknown packet identifier %d.", mosq->id, mid); @@ -63,7 +66,10 @@ int handle__pubrel(struct mosquitto_db *db, struct mosquitto *mosq) #else log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received PUBREL (Mid: %d)", mosq->id, mid); - if(!message__remove(mosq, mid, mosq_md_in, &message)){ + rc = message__remove(mosq, mid, mosq_md_in, &message, 2); + if(rc){ + return rc; + }else{ /* Only pass the message on if we have removed it from the queue - this * prevents multiple callbacks for the same message. */ pthread_mutex_lock(&mosq->callback_mutex); diff --git a/lib/messages_mosq.c b/lib/messages_mosq.c index f6c50b8bc5..c735944684 100644 --- a/lib/messages_mosq.c +++ b/lib/messages_mosq.c @@ -82,13 +82,13 @@ int mosquitto_message_copy(struct mosquitto_message *dst, const struct mosquitto return MOSQ_ERR_SUCCESS; } -int message__delete(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir) +int message__delete(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, int qos) { struct mosquitto_message_all *message; int rc; assert(mosq); - rc = message__remove(mosq, mid, dir, &message); + rc = message__remove(mosq, mid, dir, &message, qos); if(rc == MOSQ_ERR_SUCCESS){ message__cleanup(&message); } @@ -218,7 +218,7 @@ void message__reconnect_reset(struct mosquitto *mosq) pthread_mutex_unlock(&mosq->out_message_mutex); } -int message__remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, struct mosquitto_message_all **message) +int message__remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, struct mosquitto_message_all **message, int qos) { struct mosquitto_message_all *cur, *prev = NULL; bool found = false; @@ -231,6 +231,9 @@ int message__remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_dir cur = mosq->out_messages; while(cur){ if(cur->msg.mid == mid){ + if(cur->msg.qos != qos){ + return MOSQ_ERR_PROTOCOL; + } if(prev){ prev->next = cur->next; }else{ @@ -287,6 +290,9 @@ int message__remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_dir cur = mosq->in_messages; while(cur){ if(cur->msg.mid == mid){ + if(cur->msg.qos != qos){ + return MOSQ_ERR_PROTOCOL; + } if(prev){ prev->next = cur->next; }else{ @@ -370,7 +376,7 @@ void mosquitto_message_retry_set(struct mosquitto *mosq, unsigned int message_re { } -int message__out_update(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_state state) +int message__out_update(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_state state, int qos) { struct mosquitto_message_all *message; assert(mosq); @@ -379,6 +385,9 @@ int message__out_update(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg message = mosq->out_messages; while(message){ if(message->msg.mid == mid){ + if(message->msg.qos != qos){ + return MOSQ_ERR_PROTOCOL; + } message->state = state; message->timestamp = mosquitto_time(); pthread_mutex_unlock(&mosq->out_message_mutex); diff --git a/lib/messages_mosq.h b/lib/messages_mosq.h index 85b82185c1..42385003b4 100644 --- a/lib/messages_mosq.h +++ b/lib/messages_mosq.h @@ -21,11 +21,11 @@ and the Eclipse Distribution License is available at void message__cleanup_all(struct mosquitto *mosq); void message__cleanup(struct mosquitto_message_all **message); -int message__delete(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir); +int message__delete(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, int qos); int message__queue(struct mosquitto *mosq, struct mosquitto_message_all *message, enum mosquitto_msg_direction dir); void message__reconnect_reset(struct mosquitto *mosq); -int message__remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, struct mosquitto_message_all **message); +int message__remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, struct mosquitto_message_all **message, int qos); void message__retry_check(struct mosquitto *mosq); -int message__out_update(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_state state); +int message__out_update(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_state state, int qos); #endif diff --git a/src/database.c b/src/database.c index d2f482d1b6..2f76de1280 100644 --- a/src/database.c +++ b/src/database.c @@ -288,7 +288,7 @@ void db__message_dequeue_first(struct mosquitto *context) msg->next = NULL; } -int db__message_delete(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir) +int db__message_delete(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, int qos) { struct mosquitto_client_msg *tail, *last = NULL; int msg_index = 0; @@ -299,6 +299,11 @@ int db__message_delete(struct mosquitto_db *db, struct mosquitto *context, uint1 while(tail){ msg_index++; if(tail->mid == mid && tail->direction == dir){ + if(tail->qos != qos){ + return MOSQ_ERR_PROTOCOL; + }else if(qos == 2 && tail->state != mosq_ms_wait_for_pubcomp){ + return MOSQ_ERR_PROTOCOL; + } msg_index--; db__message_remove(db, context, &tail, last); }else{ @@ -509,13 +514,16 @@ int db__message_insert(struct mosquitto_db *db, struct mosquitto *context, uint1 #endif } -int db__message_update(struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, enum mosquitto_msg_state state) +int db__message_update(struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, enum mosquitto_msg_state state, int qos) { struct mosquitto_client_msg *tail; tail = context->inflight_msgs; while(tail){ if(tail->mid == mid && tail->direction == dir){ + if(tail->qos != qos){ + return MOSQ_ERR_PROTOCOL; + } tail->state = state; tail->timestamp = mosquitto_time(); return MOSQ_ERR_SUCCESS; @@ -780,7 +788,6 @@ int db__message_reconnect_reset(struct mosquitto_db *db, struct mosquitto *conte int db__message_release(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir) { struct mosquitto_client_msg *tail, *last = NULL; - int qos; int retain; char *topic; char *source_id; @@ -793,7 +800,9 @@ int db__message_release(struct mosquitto_db *db, struct mosquitto *context, uint while(tail){ msg_index++; if(tail->mid == mid && tail->direction == dir){ - qos = tail->store->qos; + if(tail->store->qos != 2){ + return MOSQ_ERR_PROTOCOL; + } topic = tail->store->topic; retain = tail->retain; source_id = tail->store->source_id; @@ -802,7 +811,7 @@ int db__message_release(struct mosquitto_db *db, struct mosquitto *context, uint * denied/dropped and is being processed so the client doesn't * keep resending it. That means we don't send it to other * clients. */ - if(!topic || !sub__messages_queue(db, source_id, topic, qos, retain, &tail->store)){ + if(!topic || !sub__messages_queue(db, source_id, topic, 2, retain, &tail->store)){ db__message_remove(db, context, &tail, last); deleted = true; }else{ diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index bf13eebb56..0b69a8cc67 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -545,10 +545,10 @@ int persist__restore(struct mosquitto_db *db); void db__limits_set(int inflight, unsigned long inflight_bytes, int queued, unsigned long queued_bytes); /* Return the number of in-flight messages in count. */ int db__message_count(int *count); -int db__message_delete(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir); +int db__message_delete(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, int qos); int db__message_insert(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, int qos, bool retain, struct mosquitto_msg_store *stored); int db__message_release(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir); -int db__message_update(struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, enum mosquitto_msg_state state); +int db__message_update(struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, enum mosquitto_msg_state state, int qos); int db__message_write(struct mosquitto_db *db, struct mosquitto *context); void db__message_dequeue_first(struct mosquitto *context); int db__messages_delete(struct mosquitto_db *db, struct mosquitto *context); diff --git a/test/broker/02-subpub-qos1-bad-pubcomp.py b/test/broker/02-subpub-qos1-bad-pubcomp.py new file mode 100755 index 0000000000..6c38d9b60a --- /dev/null +++ b/test/broker/02-subpub-qos1-bad-pubcomp.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python + +# Test what the broker does if receiving a PUBCOMP in response to a QoS 1 PUBLISH. + +import inspect, os, sys +# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder +cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) +if cmd_subfolder not in sys.path: + sys.path.insert(0, cmd_subfolder) + +import mosq_test +import time + +rc = 1 +keepalive = 60 + +connect_packet = mosq_test.gen_connect("subpub-qos1-test", keepalive=keepalive) +connack_packet = mosq_test.gen_connack(rc=0) + +mid = 1 +subscribe_packet = mosq_test.gen_subscribe(mid, "subpub/qos1", 1) +suback_packet = mosq_test.gen_suback(mid, 1) + +mid = 1 +publish_packet2 = mosq_test.gen_publish("subpub/qos1", qos=1, mid=mid, payload="message") + + +helper_connect = mosq_test.gen_connect("helper", keepalive=keepalive) +helper_connack = mosq_test.gen_connack(rc=0) + +mid = 1 +publish1s_packet = mosq_test.gen_publish("subpub/qos1", qos=1, mid=mid, payload="message") +puback1s_packet = mosq_test.gen_puback(mid) + +mid = 1 +publish1r_packet = mosq_test.gen_publish("subpub/qos1", qos=1, mid=mid, payload="message") +pubcomp1r_packet = mosq_test.gen_pubcomp(mid) + +pingreq_packet = mosq_test.gen_pingreq() +pingresp_packet = mosq_test.gen_pingresp() + +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) + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback") + + helper = mosq_test.do_client_connect(helper_connect, helper_connack, timeout=20, port=port) + mosq_test.do_send_receive(helper, publish1s_packet, puback1s_packet, "puback 1s") + helper.close() + + if mosq_test.expect_packet(sock, "publish 1r", publish1r_packet): + sock.send(pubcomp1r_packet) + sock.send(pingreq_packet) + p = sock.recv(len(pingresp_packet)) + if len(p) == 0: + rc = 0 + + sock.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/02-subpub-qos1-bad-pubrec.py b/test/broker/02-subpub-qos1-bad-pubrec.py new file mode 100755 index 0000000000..9f926fd060 --- /dev/null +++ b/test/broker/02-subpub-qos1-bad-pubrec.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python + +# Test what the broker does if receiving a PUBREC in response to a QoS 1 PUBLISH. + +import inspect, os, sys +# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder +cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) +if cmd_subfolder not in sys.path: + sys.path.insert(0, cmd_subfolder) + +import mosq_test +import time + +rc = 1 +keepalive = 60 + +connect_packet = mosq_test.gen_connect("subpub-qos1-test", keepalive=keepalive) +connack_packet = mosq_test.gen_connack(rc=0) + +mid = 1 +subscribe_packet = mosq_test.gen_subscribe(mid, "subpub/qos1", 1) +suback_packet = mosq_test.gen_suback(mid, 1) + +helper_connect = mosq_test.gen_connect("helper", keepalive=keepalive) +helper_connack = mosq_test.gen_connack(rc=0) + +mid = 1 +publish1s_packet = mosq_test.gen_publish("subpub/qos1", qos=1, mid=mid, payload="message") +puback1s_packet = mosq_test.gen_puback(mid) + +mid = 1 +publish1r_packet = mosq_test.gen_publish("subpub/qos1", qos=1, mid=mid, payload="message") +pubrec1r_packet = mosq_test.gen_pubrec(mid) + +pingreq_packet = mosq_test.gen_pingreq() +pingresp_packet = mosq_test.gen_pingresp() + +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) + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback") + + helper = mosq_test.do_client_connect(helper_connect, helper_connack, timeout=20, port=port) + mosq_test.do_send_receive(helper, publish1s_packet, puback1s_packet, "puback 1s") + helper.close() + + if mosq_test.expect_packet(sock, "publish 1r", publish1r_packet): + sock.send(pubrec1r_packet) + sock.send(pingreq_packet) + p = sock.recv(len(pingresp_packet)) + if len(p) == 0: + rc = 0 + + sock.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/02-subpub-qos2-bad-puback-1.py b/test/broker/02-subpub-qos2-bad-puback-1.py new file mode 100755 index 0000000000..e228c3d561 --- /dev/null +++ b/test/broker/02-subpub-qos2-bad-puback-1.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python + +# Test what the broker does if receiving a PUBACK in response to a QoS 2 PUBLISH. + +import inspect, os, sys +# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder +cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) +if cmd_subfolder not in sys.path: + sys.path.insert(0, cmd_subfolder) + +import mosq_test +import time + +rc = 1 +keepalive = 60 + +connect_packet = mosq_test.gen_connect("subpub-qos2-test", keepalive=keepalive) +connack_packet = mosq_test.gen_connack(rc=0) + +mid = 1 +subscribe_packet = mosq_test.gen_subscribe(mid, "subpub/qos2", 2) +suback_packet = mosq_test.gen_suback(mid, 2) + +helper_connect = mosq_test.gen_connect("helper", keepalive=keepalive) +helper_connack = mosq_test.gen_connack(rc=0) + +mid = 1 +publish1s_packet = mosq_test.gen_publish("subpub/qos2", qos=2, mid=mid, payload="message") +pubrec1s_packet = mosq_test.gen_pubrec(mid) +pubrel1s_packet = mosq_test.gen_pubrel(mid) +pubcomp1s_packet = mosq_test.gen_pubcomp(mid) + +mid = 1 +publish1r_packet = mosq_test.gen_publish("subpub/qos2", qos=2, mid=mid, payload="message") +puback1r_packet = mosq_test.gen_puback(mid) + +pingreq_packet = mosq_test.gen_pingreq() +pingresp_packet = mosq_test.gen_pingresp() + +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) + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback") + + helper = mosq_test.do_client_connect(helper_connect, helper_connack, timeout=20, port=port) + mosq_test.do_send_receive(helper, publish1s_packet, pubrec1s_packet, "pubrec 1s") + mosq_test.do_send_receive(helper, pubrel1s_packet, pubcomp1s_packet, "pubcomp 1s") + helper.close() + + if mosq_test.expect_packet(sock, "publish 1r", publish1r_packet): + sock.send(puback1r_packet) + sock.send(pingreq_packet) + p = sock.recv(len(pingresp_packet)) + if len(p) == 0: + rc = 0 + + sock.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/02-subpub-qos2-bad-puback-2.py b/test/broker/02-subpub-qos2-bad-puback-2.py new file mode 100755 index 0000000000..67189990fc --- /dev/null +++ b/test/broker/02-subpub-qos2-bad-puback-2.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python + +# Test what the broker does if receiving a PUBACK in response to a QoS 2 PUBREL. + +import inspect, os, sys +# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder +cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) +if cmd_subfolder not in sys.path: + sys.path.insert(0, cmd_subfolder) + +import mosq_test +import time + +rc = 1 +keepalive = 60 + +connect_packet = mosq_test.gen_connect("subpub-qos2-test", keepalive=keepalive) +connack_packet = mosq_test.gen_connack(rc=0) + +mid = 1 +subscribe_packet = mosq_test.gen_subscribe(mid, "subpub/qos2", 2) +suback_packet = mosq_test.gen_suback(mid, 2) + +helper_connect = mosq_test.gen_connect("helper", keepalive=keepalive) +helper_connack = mosq_test.gen_connack(rc=0) + +mid = 1 +publish1s_packet = mosq_test.gen_publish("subpub/qos2", qos=2, mid=mid, payload="message") +pubrec1s_packet = mosq_test.gen_pubrec(mid) +pubrel1s_packet = mosq_test.gen_pubrel(mid) +pubcomp1s_packet = mosq_test.gen_pubcomp(mid) + +mid = 1 +publish1r_packet = mosq_test.gen_publish("subpub/qos2", qos=2, mid=mid, payload="message") +pubrec1r_packet = mosq_test.gen_pubrec(mid) +pubrel1r_packet = mosq_test.gen_pubrel(mid) +puback1r_packet = mosq_test.gen_puback(mid) + +pingreq_packet = mosq_test.gen_pingreq() +pingresp_packet = mosq_test.gen_pingresp() + +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) + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback") + + helper = mosq_test.do_client_connect(helper_connect, helper_connack, timeout=20, port=port) + mosq_test.do_send_receive(helper, publish1s_packet, pubrec1s_packet, "pubrec 1s") + mosq_test.do_send_receive(helper, pubrel1s_packet, pubcomp1s_packet, "pubcomp 1s") + helper.close() + + if mosq_test.expect_packet(sock, "publish 1r", publish1r_packet): + mosq_test.do_send_receive(sock, pubrec1s_packet, pubrel1s_packet, "pubrel 1r") + sock.send(puback1r_packet) + sock.send(pingreq_packet) + p = sock.recv(len(pingresp_packet)) + if len(p) == 0: + rc = 0 + + sock.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/02-subpub-qos2-bad-pubcomp.py b/test/broker/02-subpub-qos2-bad-pubcomp.py new file mode 100755 index 0000000000..acaac55251 --- /dev/null +++ b/test/broker/02-subpub-qos2-bad-pubcomp.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python + +# Test what the broker does if receiving a PUBCOMP in response to a QoS 2 PUBLISH. + +import inspect, os, sys +# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder +cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) +if cmd_subfolder not in sys.path: + sys.path.insert(0, cmd_subfolder) + +import mosq_test +import time + +rc = 1 +keepalive = 60 + +connect_packet = mosq_test.gen_connect("subpub-qos2-test", keepalive=keepalive) +connack_packet = mosq_test.gen_connack(rc=0) + +mid = 1 +subscribe_packet = mosq_test.gen_subscribe(mid, "subpub/qos2", 2) +suback_packet = mosq_test.gen_suback(mid, 2) + +helper_connect = mosq_test.gen_connect("helper", keepalive=keepalive) +helper_connack = mosq_test.gen_connack(rc=0) + +mid = 1 +publish1s_packet = mosq_test.gen_publish("subpub/qos2", qos=2, mid=mid, payload="message") +pubrec1s_packet = mosq_test.gen_pubrec(mid) +pubrel1s_packet = mosq_test.gen_pubrel(mid) +pubcomp1s_packet = mosq_test.gen_pubcomp(mid) + +mid = 1 +publish1r_packet = mosq_test.gen_publish("subpub/qos2", qos=2, mid=mid, payload="message") +pubcomp1r_packet = mosq_test.gen_pubcomp(mid) + +pingreq_packet = mosq_test.gen_pingreq() +pingresp_packet = mosq_test.gen_pingresp() + +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) + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback") + + helper = mosq_test.do_client_connect(helper_connect, helper_connack, timeout=20, port=port) + mosq_test.do_send_receive(helper, publish1s_packet, pubrec1s_packet, "pubrec 1s") + mosq_test.do_send_receive(helper, pubrel1s_packet, pubcomp1s_packet, "pubcomp 1s") + helper.close() + + if mosq_test.expect_packet(sock, "publish 1r", publish1r_packet): + sock.send(pubcomp1r_packet) + sock.send(pingreq_packet) + p = sock.recv(len(pingresp_packet)) + if len(p) == 0: + rc = 0 + + sock.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index c70f1f7d67..08f1b0ff29 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -45,6 +45,11 @@ endif ./02-subpub-qos0.py ./02-subpub-qos1.py ./02-subpub-qos2.py + ./02-subpub-qos1-bad-pubrec.py + ./02-subpub-qos1-bad-pubcomp.py + ./02-subpub-qos2-bad-puback-1.py + ./02-subpub-qos2-bad-puback-2.py + ./02-subpub-qos2-bad-pubcomp.py ./02-unsubscribe-qos0.py ./02-unsubscribe-qos1.py ./02-unsubscribe-qos2.py diff --git a/test/broker/ptest.py b/test/broker/ptest.py index f39049e1b8..a9d9a9a020 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -28,6 +28,11 @@ (1, './02-subpub-qos0.py'), (1, './02-subpub-qos1.py'), (1, './02-subpub-qos2.py'), + (1, './02-subpub-qos1-bad-pubrec.py'), + (1, './02-subpub-qos1-bad-pubcomp.py'), + (1, './02-subpub-qos2-bad-puback-1.py'), + (1, './02-subpub-qos2-bad-puback-2.py'), + (1, './02-subpub-qos2-bad-pubcomp.py'), (1, './02-unsubscribe-qos0.py'), (1, './02-unsubscribe-qos1.py'), (1, './02-unsubscribe-qos2.py'), From 84d5028c2ec46eca68fc4ce7cd64b9770eb0abd9 Mon Sep 17 00:00:00 2001 From: Steven Lawrance Date: Wed, 30 Jan 2019 15:22:30 +0100 Subject: [PATCH 214/254] Include sys/socket.h for AF_INET definition Without this, mosquitto doesn't build on FreeBSD with websockets enabled Signed-off-by: Steven Lawrance --- src/websockets.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/websockets.c b/src/websockets.c index 6ac446f610..163c222eb8 100644 --- a/src/websockets.c +++ b/src/websockets.c @@ -41,6 +41,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include extern struct mosquitto_db int_db; From 36b5421c599f8cc5e76900428e362fd946b689eb Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 30 Jan 2019 15:01:34 +0000 Subject: [PATCH 215/254] Fix and tests for security bug #543401. --- ChangeLog.txt | 11 ++ src/security_default.c | 57 +++++---- test/broker/09-pwfile-parse-invalid.py | 169 +++++++++++++++++++++++++ test/broker/Makefile | 1 + test/broker/ptest.py | 1 + test/mosq_test.py | 8 +- 6 files changed, 223 insertions(+), 24 deletions(-) create mode 100755 test/broker/09-pwfile-parse-invalid.py diff --git a/ChangeLog.txt b/ChangeLog.txt index 6bb4cae9de..c7146ff549 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,6 +1,17 @@ 1.5.6 - 201901xx ================ +Security: +- CVE-2018-xxxxx: If Mosquitto is configured to use a password file for + authentication, any malformed data in the password file will be treated as + valid. This typically means that the malformed data becomes a username and no + password. If this occurs, clients can circumvent authentication and get access + to the broker by using the malformed username. In particular, a blank line + will be treated as a valid empty username. Other security measures are + unaffected. Users who have only used the mosquitto_passwd utility to create + and modify their password files are unaffected by this vulnerability. + Affects version 1.0 to 1.5.5 inclusive. + Broker: - Fixed comment handling for config options that have optional arguments. - Improved documentation around bridge topic remapping. diff --git a/src/security_default.c b/src/security_default.c index 26d8b59e60..743020c1a9 100644 --- a/src/security_default.c +++ b/src/security_default.c @@ -623,6 +623,9 @@ static int pwfile__parse(const char *file, struct mosquitto__unpwd **root) while(!feof(pwfile)){ if(fgets(buf, 256, pwfile)){ + if(buf[0] == '#') continue; + if(!strchr(buf, ':')) continue; + username = strtok_r(buf, ":", &saveptr); if(username){ unpwd = mosquitto__calloc(1, sizeof(struct mosquitto__unpwd)); @@ -655,8 +658,13 @@ static int pwfile__parse(const char *file, struct mosquitto__unpwd **root) unpwd->password[len-1] = '\0'; len = strlen(unpwd->password); } + + HASH_ADD_KEYPTR(hh, *root, unpwd->username, strlen(unpwd->username), unpwd); + }else{ + log__printf(NULL, MOSQ_LOG_NOTICE, "Warning: Invalid line in password file '%s': %s", file, buf); + mosquitto__free(unpwd->username); + mosquitto__free(unpwd); } - HASH_ADD_KEYPTR(hh, *root, unpwd->username, strlen(unpwd->username), unpwd); } } } @@ -693,34 +701,39 @@ static int unpwd__file_parse(struct mosquitto__unpwd **unpwd, const char *passwo token = strtok(NULL, "$"); if(token){ rc = base64__decode(token, &salt, &salt_len); - if(rc){ - log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to decode password salt for user %s.", u->username); - return MOSQ_ERR_INVAL; - } - u->salt = salt; - u->salt_len = salt_len; - token = strtok(NULL, "$"); - if(token){ - rc = base64__decode(token, &password, &password_len); - if(rc){ - log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to decode password for user %s.", u->username); - return MOSQ_ERR_INVAL; + if(rc == MOSQ_ERR_SUCCESS && salt_len == 12){ + u->salt = salt; + u->salt_len = salt_len; + token = strtok(NULL, "$"); + if(token){ + rc = base64__decode(token, &password, &password_len); + if(rc == MOSQ_ERR_SUCCESS && password_len == 64){ + mosquitto__free(u->password); + u->password = (char *)password; + u->password_len = password_len; + }else{ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to decode password for user %s, removing entry.", u->username); + HASH_DEL(*unpwd, u); + } + }else{ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid password hash for user %s, removing entry.", u->username); + HASH_DEL(*unpwd, u); } - mosquitto__free(u->password); - u->password = (char *)password; - u->password_len = password_len; }else{ - log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid password hash for user %s.", u->username); - return MOSQ_ERR_INVAL; + log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to decode password salt for user %s, removing entry.", u->username); + HASH_DEL(*unpwd, u); } }else{ - log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid password hash for user %s.", u->username); - return MOSQ_ERR_INVAL; + log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid password hash for user %s, removing entry.", u->username); + HASH_DEL(*unpwd, u); } }else{ - log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid password hash for user %s.", u->username); - return MOSQ_ERR_INVAL; + log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid password hash for user %s, removing entry.", u->username); + HASH_DEL(*unpwd, u); } + }else{ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Missing password hash for user %s, removing entry.", u->username); + HASH_DEL(*unpwd, u); } } #endif diff --git a/test/broker/09-pwfile-parse-invalid.py b/test/broker/09-pwfile-parse-invalid.py new file mode 100755 index 0000000000..6a8652344e --- /dev/null +++ b/test/broker/09-pwfile-parse-invalid.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python + +# Test for CVE-2018-xxxxx. + +import inspect, os, sys +# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder +cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) +if cmd_subfolder not in sys.path: + sys.path.insert(0, cmd_subfolder) + +import mosq_test +import signal + +def write_config(filename, port, per_listener): + with open(filename, 'w') as f: + f.write("per_listener_settings %s\n" % (per_listener)) + f.write("port %d\n" % (port)) + f.write("password_file %s\n" % (filename.replace('.conf', '.pwfile'))) + f.write("allow_anonymous false") + +def write_pwfile(filename, bad_line1, bad_line2): + with open(filename, 'w') as f: + if bad_line1 is not None: + f.write('%s\n' % (bad_line1)) + # Username test, password test + f.write('test:$6$njERlZMi/7DzNB9E$iiavfuXvUm8iyDZArTy7smTxh07GXXOrOsqxfW6gkOYVXHGk+W+i/8d3xDxrMwEPygEBhoA8A/gjQC0N2M4Lkw==\n') + # Username empty, password 0 length + f.write('empty:$6$o+53eGXtmlfHeYrg$FY7X9DNQ4uU1j0NiPmGOOSU05ZSzhqNmNhXIof/0nLpVb1zDhcRHdaC72E3YryH7dtTiG/r6jH6C8J+30cZBgA==\n') + if bad_line2 is not None: + f.write('%s\n' % (bad_line2)) + +def do_test(port, connack_rc, username, password): + rc = 1 + keepalive = 60 + connect_packet = mosq_test.gen_connect("username-password-check", keepalive=keepalive, username=username, password=password) + connack_packet = mosq_test.gen_connack(rc=connack_rc) + + try: + sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port) + rc = 0 + sock.close() + finally: + if rc: + exit(rc) + + +def username_password_tests(port): + broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port) + + try: + do_test(port, connack_rc=0, username='test', password='test') + do_test(port, connack_rc=5, username='test', password='bad') + do_test(port, connack_rc=5, username='test', password='') + do_test(port, connack_rc=5, username='test', password=None) + do_test(port, connack_rc=5, username='empty', password='test') + do_test(port, connack_rc=5, username='empty', password='bad') + do_test(port, connack_rc=0, username='empty', password='') + do_test(port, connack_rc=5, username='empty', password=None) + do_test(port, connack_rc=5, username='bad', password='test') + do_test(port, connack_rc=5, username='bad', password='bad') + do_test(port, connack_rc=5, username='bad', password='') + do_test(port, connack_rc=5, username='bad', password=None) + do_test(port, connack_rc=5, username='', password='test') + do_test(port, connack_rc=5, username='', password='bad') + do_test(port, connack_rc=5, username='', password='') + do_test(port, connack_rc=5, username='', password=None) + do_test(port, connack_rc=5, username=None, password='test') + do_test(port, connack_rc=5, username=None, password='bad') + do_test(port, connack_rc=5, username=None, password='') + do_test(port, connack_rc=5, username=None, password=None) + except ValueError: + pass + finally: + broker.terminate() + broker.wait() + + +def all_tests(port): + # Valid file, single user + write_pwfile(pw_file, bad_line1=None, bad_line2=None) + username_password_tests(port) + + # Invalid file, first line blank + write_pwfile(pw_file, bad_line1='', bad_line2=None) + username_password_tests(port) + + # Invalid file, last line blank + write_pwfile(pw_file, bad_line1=None, bad_line2='') + username_password_tests(port) + + # Invalid file, first and last line blank + write_pwfile(pw_file, bad_line1='', bad_line2='') + username_password_tests(port) + + # Invalid file, first line 'comment' + write_pwfile(pw_file, bad_line1='#comment', bad_line2=None) + username_password_tests(port) + + # Invalid file, last line 'comment' + write_pwfile(pw_file, bad_line1=None, bad_line2='#comment') + username_password_tests(port) + + # Invalid file, first and last line 'comment' + write_pwfile(pw_file, bad_line1='#comment', bad_line2='#comment') + username_password_tests(port) + + # Invalid file, first line blank and last line 'comment' + write_pwfile(pw_file, bad_line1='', bad_line2='#comment') + username_password_tests(port) + + # Invalid file, first line incomplete + write_pwfile(pw_file, bad_line1='bad:', bad_line2=None) + username_password_tests(port) + + # Invalid file, first line incomplete, but with "password" + write_pwfile(pw_file, bad_line1='bad:bad', bad_line2=None) + username_password_tests(port) + + # Invalid file, first line incomplete, partial password hash + write_pwfile(pw_file, bad_line1='bad:$', bad_line2=None) + username_password_tests(port) + + # Invalid file, first line incomplete, partial password hash + write_pwfile(pw_file, bad_line1='bad:$6', bad_line2=None) + username_password_tests(port) + + # Invalid file, first line incomplete, partial password hash + write_pwfile(pw_file, bad_line1='bad:$6$', bad_line2=None) + username_password_tests(port) + + # Valid file, first line incomplete, has valid salt but no password hash + write_pwfile(pw_file, bad_line1='bad:$6$njERlZMi/7DzNB9E', bad_line2=None) + username_password_tests(port) + + # Valid file, first line incomplete, has valid salt but no password hash + write_pwfile(pw_file, bad_line1='bad:$6$njERlZMi/7DzNB9E$', bad_line2=None) + username_password_tests(port) + + # Valid file, first line has invalid hash designator + write_pwfile(pw_file, bad_line1='bad:$5$njERlZMi/7DzNB9E$iiavfuXvUm8iyDZArTy7smTxh07GXXOrOsqxfW6gkOYVXHGk+W+i/8d3xDxrMwEPygEBhoA8A/gjQC0N2M4Lkw==', bad_line2=None) + username_password_tests(port) + + # Invalid file, missing username but valid password hash + write_pwfile(pw_file, bad_line1=':$6$njERlZMi/7DzNB9E$iiavfuXvUm8iyDZArTy7smTxh07GXXOrOsqxfW6gkOYVXHGk+W+i/8d3xDxrMwEPygEBhoA8A/gjQC0N2M4Lkw==', bad_line2=None) + username_password_tests(port) + + # Valid file, valid username but password salt not base64 + write_pwfile(pw_file, bad_line1='bad:$6$njER{ZMi/7DzNB9E$iiavfuXvUm8iyDZArTy7smTxh07GXXOrOsqxfW6gkOYVXHGk+W+i/8d3xDxrMwEPygEBhoA8A/gjQC0N2M4Lkw==', bad_line2=None) + username_password_tests(port) + + # Valid file, valid username but password hash not base64 + write_pwfile(pw_file, bad_line1='bad:$6$njERlZMi/7DzNB9E$iiavfuXv{}8iyDZArTy7smTxh07GXXOrOsqxfW6gkOYVXHGk+W+i/8d3xDxrMwEPygEBhoA8A/gjQC0N2M4Lkw==', bad_line2=None) + username_password_tests(port) + + + +port = mosq_test.get_port() +conf_file = os.path.basename(__file__).replace('.py', '.conf') +pw_file = os.path.basename(__file__).replace('.py', '.pwfile') + +try: + write_config(conf_file, port, "false") + all_tests(port) + + write_config(conf_file, port, "true") + all_tests(port) +finally: + os.remove(conf_file) + os.remove(pw_file) diff --git a/test/broker/Makefile b/test/broker/Makefile index 08f1b0ff29..3299d7dbe1 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -128,6 +128,7 @@ endif ./09-plugin-auth-defer-unpwd-fail.py ./09-plugin-auth-msg-params.py ./09-plugin-auth-context-params.py + ./09-pwfile-parse-invalid.py 10 : ./10-listener-mount-point.py diff --git a/test/broker/ptest.py b/test/broker/ptest.py index a9d9a9a020..eb10895da5 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -100,6 +100,7 @@ (1, './09-plugin-auth-defer-unpwd-fail.py'), (1, './09-plugin-auth-msg-params.py'), (1, './09-plugin-auth-context-params.py'), + (1, './09-pwfile-parse-invalid.py'), (2, './10-listener-mount-point.py'), diff --git a/test/mosq_test.py b/test/mosq_test.py index a28f2eb1ce..10323323ab 100644 --- a/test/mosq_test.py +++ b/test/mosq_test.py @@ -6,7 +6,7 @@ import sys import time -def start_broker(filename, cmd=None, port=0, use_conf=False): +def start_broker(filename, cmd=None, port=0, use_conf=False, expect_fail=False): delay = 0.1 if use_conf == True: @@ -43,7 +43,11 @@ def start_broker(filename, cmd=None, port=0, use_conf=False): c.close() time.sleep(delay) return broker - raise IOError + + if expect_fail == False: + raise IOError + else: + return None def start_client(filename, cmd, env, port=1888): if cmd is None: From d8505624d0d0de164cee140d5d7b985bc9df35de Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 30 Jan 2019 15:29:20 +0000 Subject: [PATCH 216/254] Fix and tests for security bug #541870. --- ChangeLog.txt | 6 +++ src/security_default.c | 6 ++- test/broker/09-acl-empty-file.py | 71 ++++++++++++++++++++++++++++++++ test/broker/Makefile | 1 + test/broker/ptest.py | 1 + 5 files changed, 84 insertions(+), 1 deletion(-) create mode 100755 test/broker/09-acl-empty-file.py diff --git a/ChangeLog.txt b/ChangeLog.txt index c7146ff549..215ca2041f 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -11,6 +11,12 @@ Security: unaffected. Users who have only used the mosquitto_passwd utility to create and modify their password files are unaffected by this vulnerability. Affects version 1.0 to 1.5.5 inclusive. +- CVE-2018-xxxxx: If an ACL file is empty, or has only blank lines or + comments, then mosquitto treats the ACL file as not being defined, which + means that no topic access is denied. Although denying access to all topics + is not a useful configuration, this behaviour is unexpected and could lead + to access being incorrectly granted in some circumstances. This is now + fixed. Affects versions 1.0 to 1.5.5 inclusive. Broker: - Fixed comment handling for config options that have optional arguments. diff --git a/src/security_default.c b/src/security_default.c index 743020c1a9..5a886a53df 100644 --- a/src/security_default.c +++ b/src/security_default.c @@ -317,7 +317,7 @@ int mosquitto_acl_check_default(struct mosquitto_db *db, struct mosquitto *conte }else{ security_opts = &db->config->security_options; } - if(!security_opts->acl_list && !security_opts->acl_patterns){ + if(!security_opts->acl_file && !security_opts->acl_list && !security_opts->acl_patterns){ return MOSQ_ERR_PLUGIN_DEFER; } @@ -535,6 +535,10 @@ static int aclfile__parse(struct mosquitto_db *db, struct mosquitto__security_op fclose(aclfptr); return 1; } + }else{ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid line in acl_file \"%s\": %s.", security_opts->acl_file, buf); + fclose(aclfptr); + return 1; } } } diff --git a/test/broker/09-acl-empty-file.py b/test/broker/09-acl-empty-file.py new file mode 100755 index 0000000000..a6d71cf60b --- /dev/null +++ b/test/broker/09-acl-empty-file.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python + +# Test for CVE-2018-xxxxx + +import inspect, os, sys +# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder +cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) +if cmd_subfolder not in sys.path: + sys.path.insert(0, cmd_subfolder) + +import mosq_test +import signal + +def write_config(filename, port, per_listener): + with open(filename, 'w') as f: + f.write("per_listener_settings %s\n" % (per_listener)) + f.write("port %d\n" % (port)) + f.write("acl_file %s\n" % (filename.replace('.conf', '.acl'))) + +def write_acl(filename): + with open(filename, 'w') as f: + f.write('#comment\n') + f.write('\n') + + +def do_test(port, per_listener): + conf_file = os.path.basename(__file__).replace('.py', '.conf') + write_config(conf_file, port, per_listener) + + acl_file = os.path.basename(__file__).replace('.py', '.acl') + write_acl(acl_file) + + rc = 1 + keepalive = 60 + connect_packet = mosq_test.gen_connect("acl-check", keepalive=keepalive) + connack_packet = mosq_test.gen_connack(rc=0) + + mid = 1 + publish_packet = mosq_test.gen_publish("test/topic", qos=0, payload="message") + subscribe_packet = mosq_test.gen_subscribe(mid, "test/topic", 0) + suback_packet = mosq_test.gen_suback(mid, 0) + + pingreq_packet = mosq_test.gen_pingreq() + pingresp_packet = mosq_test.gen_pingresp() + + broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port) + + try: + sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port) + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback") + + sock.send(publish_packet) + + # If we receive the message, this will fail. + mosq_test.do_send_receive(sock, pingreq_packet, pingresp_packet, "pingresp") + rc = 0 + + sock.close() + finally: + os.remove(conf_file) + os.remove(acl_file) + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + exit(rc) + +port = mosq_test.get_port() +do_test(port, "false") +do_test(port, "true") diff --git a/test/broker/Makefile b/test/broker/Makefile index 3299d7dbe1..d3b3e43889 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -118,6 +118,7 @@ endif endif 09 : + ./09-acl-empty-file.py ./09-plugin-auth-unpwd-success.py ./09-plugin-auth-unpwd-fail.py ./09-plugin-auth-acl-sub.py diff --git a/test/broker/ptest.py b/test/broker/ptest.py index eb10895da5..28f14f97e2 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -90,6 +90,7 @@ (2, './08-tls-psk-pub.py'), (3, './08-tls-psk-bridge.py'), + (1, './09-acl-empty-file.py'), (1, './09-plugin-auth-unpwd-success.py'), (1, './09-plugin-auth-unpwd-fail.py'), (1, './09-plugin-auth-acl-sub.py'), From c40957a7d8f2d866cd919f2d53f4927c785fcef1 Mon Sep 17 00:00:00 2001 From: Roger Light Date: Thu, 31 Jan 2019 21:50:42 +0000 Subject: [PATCH 217/254] Fix and tests for CVE-2018-12546. --- ChangeLog.txt | 6 + man/mosquitto.conf.5.xml | 18 ++ mosquitto.conf | 9 + src/conf.c | 3 + src/database.c | 24 ++- src/db_dump/Makefile | 2 +- src/db_dump/db_dump.c | 148 +++++++------- src/handle_connect.c | 34 +--- src/handle_publish.c | 4 +- src/mosquitto_broker_internal.h | 6 +- src/persist.c | 180 ++++++++++++------ src/persist.h | 2 +- src/security_default.c | 43 +++++ src/subs.c | 21 ++ ...4-retain-check-source-persist-diff-port.py | 117 ++++++++++++ test/broker/04-retain-check-source-persist.py | 106 +++++++++++ test/broker/04-retain-check-source.py | 87 +++++++++ test/broker/Makefile | 3 + test/broker/ptest.py | 3 + 19 files changed, 644 insertions(+), 172 deletions(-) create mode 100755 test/broker/04-retain-check-source-persist-diff-port.py create mode 100755 test/broker/04-retain-check-source-persist.py create mode 100755 test/broker/04-retain-check-source.py diff --git a/ChangeLog.txt b/ChangeLog.txt index 215ca2041f..6d22cf5cea 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -17,6 +17,12 @@ Security: is not a useful configuration, this behaviour is unexpected and could lead to access being incorrectly granted in some circumstances. This is now fixed. Affects versions 1.0 to 1.5.5 inclusive. +- Fix CVE-2018-12546. If a client publishes a retained message to a topic that + they have access to, and then their access to that topic is revoked, the + retained message will still be delivered to future subscribers. This + behaviour may be undesirable in some applications, so a configuration option + `check_retain_source` has been introduced to enforce checking of the + retained message source on publish. Broker: - Fixed comment handling for config options that have optional arguments. diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml index 8b212e2db7..d941c98577 100644 --- a/man/mosquitto.conf.5.xml +++ b/man/mosquitto.conf.5.xml @@ -294,6 +294,24 @@ Reloaded on reload signal. + + [ true | false ] + + This option affects the scenario when a client + subscribes to a topic that has retained messages. It is + possible that the client that published the retained + message to the topic had access at the time they + published, but that access has been subsequently + removed. If is set + to true, the default, the source of a retained message + will be checked for access rights before it is + republished. When set to false, no check will be made + and the retained message will always be + published. + This option applies globally, regardless of the + option. + + prefix diff --git a/mosquitto.conf b/mosquitto.conf index 96450050d9..e8c43397fa 100644 --- a/mosquitto.conf +++ b/mosquitto.conf @@ -148,6 +148,15 @@ # setting behaviour from previous versions of mosquitto. #per_listener_settings false +# This option affects the scenario when a client subscribes to a topic that has +# retained messages. It is possible that the client that published the retained +# message to the topic had access at the time they published, but that access +# has been subsequently removed. If check_retain_source is set to true, the +# default, the source of a retained message will be checked for access rights +# before it is republished. When set to false, no check will be made and the +# retained message will always be published. This affects all listeners. +#check_retain_source true + # ================================================================= # Default listener diff --git a/src/conf.c b/src/conf.c index c995babef2..f81219f36d 100644 --- a/src/conf.c +++ b/src/conf.c @@ -1093,6 +1093,9 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct #else log__printf(NULL, MOSQ_LOG_WARNING, "Warning: TLS support not available."); #endif + }else if(!strcmp(token, "check_retain_source")){ + conf__set_cur_security_options(config, cur_listener, &cur_security_options); + if(conf__parse_bool(&token, "check_retain_source", &config->check_retain_source, saveptr)) return MOSQ_ERR_INVAL; }else if(!strcmp(token, "ciphers")){ #ifdef WITH_TLS if(reload) continue; // Listeners not valid for reloading. diff --git a/src/database.c b/src/database.c index 2f76de1280..8253cb4115 100644 --- a/src/database.c +++ b/src/database.c @@ -200,6 +200,7 @@ void db__msg_store_remove(struct mosquitto_db *db, struct mosquitto_msg_store *s db->msg_store_bytes -= store->payloadlen; mosquitto__free(store->source_id); + mosquitto__free(store->source_username); if(store->dest_ids){ for(i=0; idest_id_count; i++){ mosquitto__free(store->dest_ids[i]); @@ -587,18 +588,19 @@ int db__messages_easy_queue(struct mosquitto_db *db, struct mosquitto *context, } memcpy(UHPA_ACCESS(payload_uhpa, payloadlen), payload, payloadlen); + if(db__message_store(db, context, 0, topic_heap, qos, payloadlen, &payload_uhpa, retain, &stored, 0)) return 1; + if(context && context->id){ source_id = context->id; }else{ source_id = ""; } - if(db__message_store(db, source_id, 0, topic_heap, qos, payloadlen, &payload_uhpa, retain, &stored, 0)) return 1; return sub__messages_queue(db, source_id, topic_heap, qos, retain, &stored); } /* This function requires topic to be allocated on the heap. Once called, it owns topic and will free it on error. Likewise payload. */ -int db__message_store(struct mosquitto_db *db, const char *source, uint16_t source_mid, char *topic, int qos, uint32_t payloadlen, mosquitto__payload_uhpa *payload, int retain, struct mosquitto_msg_store **stored, dbid_t store_id) +int db__message_store(struct mosquitto_db *db, const struct mosquitto *source, uint16_t source_mid, char *topic, int qos, uint32_t payloadlen, mosquitto__payload_uhpa *payload, int retain, struct mosquitto_msg_store **stored, dbid_t store_id) { struct mosquitto_msg_store *temp = NULL; int rc = MOSQ_ERR_SUCCESS; @@ -606,7 +608,7 @@ int db__message_store(struct mosquitto_db *db, const char *source, uint16_t sour assert(db); assert(stored); - temp = mosquitto__malloc(sizeof(struct mosquitto_msg_store)); + temp = mosquitto__calloc(1, sizeof(struct mosquitto_msg_store)); if(!temp){ log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); rc = MOSQ_ERR_NOMEM; @@ -617,8 +619,8 @@ int db__message_store(struct mosquitto_db *db, const char *source, uint16_t sour temp->payload.ptr = NULL; temp->ref_count = 0; - if(source){ - temp->source_id = mosquitto__strdup(source); + if(source && source->id){ + temp->source_id = mosquitto__strdup(source->id); }else{ temp->source_id = mosquitto__strdup(""); } @@ -627,6 +629,17 @@ int db__message_store(struct mosquitto_db *db, const char *source, uint16_t sour rc = MOSQ_ERR_NOMEM; goto error; } + + if(source && source->username){ + temp->source_username = mosquitto__strdup(source->username); + if(!temp->source_username){ + rc = MOSQ_ERR_NOMEM; + goto error; + } + } + if(source){ + temp->source_listener = source->listener; + } temp->source_mid = source_mid; temp->mid = 0; temp->qos = qos; @@ -659,6 +672,7 @@ int db__message_store(struct mosquitto_db *db, const char *source, uint16_t sour mosquitto__free(topic); if(temp){ mosquitto__free(temp->source_id); + mosquitto__free(temp->source_username); mosquitto__free(temp->topic); mosquitto__free(temp); } diff --git a/src/db_dump/Makefile b/src/db_dump/Makefile index 13ae261b53..202af870ce 100644 --- a/src/db_dump/Makefile +++ b/src/db_dump/Makefile @@ -1,6 +1,6 @@ include ../../config.mk -CFLAGS_FINAL=${CFLAGS} -I.. -I../../lib -I../.. +CFLAGS_FINAL=${CFLAGS} -I.. -I../../lib -I../.. -I../deps .PHONY: all clean reallyclean diff --git a/src/db_dump/db_dump.c b/src/db_dump/db_dump.c index e009cce5c5..62bf24bec2 100644 --- a/src/db_dump/db_dump.c +++ b/src/db_dump/db_dump.c @@ -83,7 +83,9 @@ struct db_msg uint8_t qos, retain; uint8_t *payload; char *source_id; + char *source_username; char *topic; + uint16_t source_port; }; static uint32_t db_version; @@ -177,6 +179,8 @@ print_db_msg(struct db_msg *msg, int length) printf("\tLength: %d\n", length); printf("\tStore ID: %" PRIu64 "\n", msg->store_id); printf("\tSource ID: %s\n", msg->source_id); + printf("\tSource Username: %s\n", msg->source_username); + printf("\tSource Port: %d\n", msg->source_port); printf("\tSource MID: %d\n", msg->source_mid); printf("\tMID: %d\n", msg->mid); printf("\tTopic: %s\n", msg->topic); @@ -194,26 +198,49 @@ print_db_msg(struct db_msg *msg, int length) } +static int persist__read_string(FILE *db_fptr, char **str) +{ + uint16_t i16temp; + uint16_t slen; + char *s = NULL; + + if(fread(&i16temp, 1, sizeof(uint16_t), db_fptr) != sizeof(uint16_t)){ + return MOSQ_ERR_INVAL; + } + + slen = ntohs(i16temp); + if(slen){ + s = mosquitto__malloc(slen+1); + if(!s){ + fclose(db_fptr); + fprintf(stderr, "Error: Out of memory.\n"); + return MOSQ_ERR_NOMEM; + } + if(fread(s, 1, slen, db_fptr) != slen){ + mosquitto__free(s); + fprintf(stderr, "Error: %s.\n", strerror(errno)); + return MOSQ_ERR_INVAL; + } + s[slen] = '\0'; + } + + *str = s; + return MOSQ_ERR_SUCCESS; +} + + static int db__client_chunk_restore(struct mosquitto_db *db, FILE *db_fd, struct db_client *client) { - uint16_t i16temp, slen; + uint16_t i16temp; int rc = 0; struct client_chunk *cc; - read_e(db_fd, &i16temp, sizeof(uint16_t)); - slen = ntohs(i16temp); - if(!slen){ + rc = persist__read_string(db_fd, &client->client_id); + if(rc){ fprintf(stderr, "Error: Corrupt persistent database."); fclose(db_fd); - return 1; + return rc; } - client->client_id = calloc(slen+1, sizeof(char)); - if(!client->client_id){ - fclose(db_fd); - fprintf(stderr, "Error: Out of memory."); - return 1; - } - read_e(db_fd, client->client_id, slen); read_e(db_fd, &i16temp, sizeof(uint16_t)); client->last_mid = ntohs(i16temp); @@ -245,24 +272,17 @@ static int db__client_chunk_restore(struct mosquitto_db *db, FILE *db_fd, struct static int db__client_msg_chunk_restore(struct mosquitto_db *db, FILE *db_fd, uint32_t length, struct db_client_msg *msg) { dbid_t i64temp; - uint16_t i16temp, slen; + uint16_t i16temp; struct client_chunk *cc; struct msg_store_chunk *msc; + int rc; - read_e(db_fd, &i16temp, sizeof(uint16_t)); - slen = ntohs(i16temp); - if(!slen){ + rc = persist__read_string(db_fd, &msg->client_id); + if(rc){ fprintf(stderr, "Error: Corrupt persistent database."); fclose(db_fd); - return 1; + return rc; } - msg->client_id = calloc(slen+1, sizeof(char)); - if(!msg->client_id){ - fclose(db_fd); - fprintf(stderr, "Error: Out of memory."); - return 1; - } - read_e(db_fd, msg->client_id, slen); read_e(db_fd, &i64temp, sizeof(dbid_t)); msg->store_id = i64temp; @@ -301,58 +321,48 @@ static int db__msg_store_chunk_restore(struct mosquitto_db *db, FILE *db_fd, uin { dbid_t i64temp; uint32_t i32temp; - uint16_t i16temp, slen; + uint16_t i16temp; int rc = 0; struct msg_store_chunk *mcs; read_e(db_fd, &i64temp, sizeof(dbid_t)); msg->store_id = i64temp; - read_e(db_fd, &i16temp, sizeof(uint16_t)); - slen = ntohs(i16temp); - if(slen){ - msg->source_id = calloc(slen+1, sizeof(char)); - if(!msg->source_id){ - fclose(db_fd); - fprintf(stderr, "Error: Out of memory."); - return 1; - } - if(fread(msg->source_id, 1, slen, db_fd) != slen){ + rc = persist__read_string(db_fd, &msg->source_id); + if(rc){ + fprintf(stderr, "Error: Corrupt persistent database."); + fclose(db_fd); + return rc; + } + if(db_version == 4){ + rc = persist__read_string(db_fd, &msg->source_username); + if(rc){ fprintf(stderr, "Error: %s.", strerror(errno)); fclose(db_fd); free(msg->source_id); + free(msg->topic); + free(msg->payload); + free(msg->source_id); return 1; } + read_e(db_fd, &i16temp, sizeof(uint16_t)); + msg->source_port = ntohs(i16temp); } + + read_e(db_fd, &i16temp, sizeof(uint16_t)); msg->source_mid = ntohs(i16temp); read_e(db_fd, &i16temp, sizeof(uint16_t)); msg->mid = ntohs(i16temp); - read_e(db_fd, &i16temp, sizeof(uint16_t)); - slen = ntohs(i16temp); - if(slen){ - msg->topic = calloc(slen+1, sizeof(char)); - if(!msg->topic){ - fclose(db_fd); - free(msg->source_id); - fprintf(stderr, "Error: Out of memory."); - return 1; - } - if(fread(msg->topic, 1, slen, db_fd) != slen){ - fprintf(stderr, "Error: %s.", strerror(errno)); - fclose(db_fd); - free(msg->source_id); - free(msg->topic); - return 1; - } - }else{ - fprintf(stderr, "Error: Invalid msg_store chunk when restoring persistent database."); + rc = persist__read_string(db_fd, &msg->topic); + if(rc){ + fprintf(stderr, "Error: Corrupt persistent database."); fclose(db_fd); - free(msg->source_id); - return 1; + return rc; } + read_e(db_fd, &msg->qos, sizeof(uint8_t)); read_e(db_fd, &msg->retain, sizeof(uint8_t)); @@ -415,29 +425,23 @@ static int db__retain_chunk_restore(struct mosquitto_db *db, FILE *db_fd) static int db__sub_chunk_restore(struct mosquitto_db *db, FILE *db_fd, uint32_t length, struct db_sub *sub) { - uint16_t i16temp, slen; int rc = 0; struct client_chunk *cc; - read_e(db_fd, &i16temp, sizeof(uint16_t)); - slen = ntohs(i16temp); - sub->client_id = calloc(slen+1, sizeof(char)); - if(!sub->client_id){ + rc = persist__read_string(db_fd, &sub->client_id); + if(rc){ + fprintf(stderr, "Error: Corrupt persistent database."); fclose(db_fd); - fprintf(stderr, "Error: Out of memory."); - return 1; + return rc; } - read_e(db_fd, sub->client_id, slen); - read_e(db_fd, &i16temp, sizeof(uint16_t)); - slen = ntohs(i16temp); - sub->topic = calloc(slen+1, sizeof(char)); - if(!sub->topic){ + + rc = persist__read_string(db_fd, &sub->topic); + if(rc){ + fprintf(stderr, "Error: Corrupt persistent database."); fclose(db_fd); - fprintf(stderr, "Error: Out of memory."); - free(sub->client_id); - return 1; + return rc; } - read_e(db_fd, sub->topic, slen); + read_e(db_fd, &sub->qos, sizeof(uint8_t)); if(client_stats){ diff --git a/src/handle_connect.c b/src/handle_connect.c index b9b0fefd8e..f47edb3b35 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -123,13 +123,11 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) uint8_t username_flag, password_flag; char *username = NULL, *password = NULL; int rc; - struct mosquitto__acl_user *acl_tail; struct mosquitto *found_context; int slen; uint16_t slen16; struct mosquitto__subleaf *leaf; int i; - struct mosquitto__security_options *security_opts; #ifdef WITH_TLS X509 *client_cert = NULL; X509_NAME *name; @@ -613,36 +611,8 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) do_disconnect(db, found_context); } - /* Associate user with its ACL, assuming we have ACLs loaded. */ - if(db->config->per_listener_settings){ - if(!context->listener){ - return 1; - } - security_opts = &context->listener->security_options; - }else{ - security_opts = &db->config->security_options; - } - - if(security_opts->acl_list){ - acl_tail = security_opts->acl_list; - while(acl_tail){ - if(context->username){ - if(acl_tail->username && !strcmp(context->username, acl_tail->username)){ - context->acl_list = acl_tail; - break; - } - }else{ - if(acl_tail->username == NULL){ - context->acl_list = acl_tail; - break; - } - } - acl_tail = acl_tail->next; - } - }else{ - context->acl_list = NULL; - } - + rc = acl__find_acls(db, context); + if(rc) return rc; if(will_struct){ context->will = will_struct; diff --git a/src/handle_publish.c b/src/handle_publish.c index 54976afce7..76b3ee8943 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -184,7 +184,7 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) } if(!stored){ dup = 0; - if(db__message_store(db, context->id, mid, topic, qos, payloadlen, &payload, retain, &stored, 0)){ + if(db__message_store(db, context, mid, topic, qos, payloadlen, &payload, retain, &stored, 0)){ return 1; } }else{ @@ -229,7 +229,7 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) case 2: db__message_store_find(context, mid, &stored); if(!stored){ - if(db__message_store(db, context->id, mid, NULL, qos, 0, NULL, false, &stored, 0)){ + if(db__message_store(db, context, mid, NULL, qos, 0, NULL, false, &stored, 0)){ return 1; } res = db__message_insert(db, context, mid, mosq_md_in, qos, false, stored); diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index 0b69a8cc67..c3655981a5 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -248,6 +248,7 @@ struct mosquitto__config { bool allow_duplicate_messages; int autosave_interval; bool autosave_on_changes; + bool check_retain_source; char *clientid_prefixes; bool connection_messages; bool daemon; @@ -312,6 +313,8 @@ struct mosquitto_msg_store{ struct mosquitto_msg_store *prev; dbid_t db_id; char *source_id; + char *source_username; + struct mosquitto__listener *source_listener; char **dest_ids; int dest_id_count; int ref_count; @@ -553,7 +556,7 @@ int db__message_write(struct mosquitto_db *db, struct mosquitto *context); void db__message_dequeue_first(struct mosquitto *context); int db__messages_delete(struct mosquitto_db *db, struct mosquitto *context); int db__messages_easy_queue(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int qos, uint32_t payloadlen, const void *payload, int retain); -int db__message_store(struct mosquitto_db *db, const char *source, uint16_t source_mid, char *topic, int qos, uint32_t payloadlen, mosquitto__payload_uhpa *payload, int retain, struct mosquitto_msg_store **stored, dbid_t store_id); +int db__message_store(struct mosquitto_db *db, const struct mosquitto *source, uint16_t source_mid, char *topic, int qos, uint32_t payloadlen, mosquitto__payload_uhpa *payload, int retain, struct mosquitto_msg_store **stored, dbid_t store_id); int db__message_store_find(struct mosquitto *context, uint16_t mid, struct mosquitto_msg_store **stored); void db__msg_store_add(struct mosquitto_db *db, struct mosquitto_msg_store *store); void db__msg_store_remove(struct mosquitto_db *db, struct mosquitto_msg_store *store); @@ -607,6 +610,7 @@ void bridge__packet_cleanup(struct mosquitto *context); /* ============================================================ * Security related functions * ============================================================ */ +int acl__find_acls(struct mosquitto_db *db, struct mosquitto *context); int mosquitto_security_module_init(struct mosquitto_db *db); int mosquitto_security_module_cleanup(struct mosquitto_db *db); diff --git a/src/persist.c b/src/persist.c index 3299356d17..2f40086925 100644 --- a/src/persist.c +++ b/src/persist.c @@ -39,6 +39,8 @@ static uint32_t db_version; static int persist__restore_sub(struct mosquitto_db *db, const char *client_id, const char *sub, int qos); +static int persist__read_string(FILE *db_fptr, char **str); +static int persist__write_string(FILE *db_fptr, const char *str, bool nullok); static struct mosquitto *persist__find_or_add_context(struct mosquitto_db *db, const char *client_id, uint16_t last_mid) { @@ -139,7 +141,7 @@ static int persist__message_store_write(struct mosquitto_db *db, FILE *db_fptr) uint32_t length; dbid_t i64temp; uint32_t i32temp; - uint16_t i16temp, slen, tlen; + uint16_t i16temp, tlen; uint8_t i8temp; struct mosquitto_msg_store *stored; bool force_no_retain; @@ -168,10 +170,19 @@ static int persist__message_store_write(struct mosquitto_db *db, FILE *db_fptr) }else{ tlen = 0; } - length = htonl(sizeof(dbid_t) + 2+strlen(stored->source_id) + + length = sizeof(dbid_t) + 2+strlen(stored->source_id) + sizeof(uint16_t) + sizeof(uint16_t) + 2+tlen + sizeof(uint32_t) + - stored->payloadlen + sizeof(uint8_t) + sizeof(uint8_t)); + stored->payloadlen + sizeof(uint8_t) + sizeof(uint8_t) + + 2*sizeof(uint16_t); + + if(stored->source_id){ + length += strlen(stored->source_id); + } + if(stored->source_username){ + length += strlen(stored->source_username); + } + length = htonl(length); i16temp = htons(DB_CHUNK_MSG_STORE); write_e(db_fptr, &i16temp, sizeof(uint16_t)); @@ -180,12 +191,15 @@ static int persist__message_store_write(struct mosquitto_db *db, FILE *db_fptr) i64temp = stored->db_id; write_e(db_fptr, &i64temp, sizeof(dbid_t)); - slen = strlen(stored->source_id); - i16temp = htons(slen); - write_e(db_fptr, &i16temp, sizeof(uint16_t)); - if(slen){ - write_e(db_fptr, stored->source_id, slen); + if(persist__write_string(db_fptr, stored->source_id, false)) return 1; + if(persist__write_string(db_fptr, stored->source_username, true)) return 1; + if(stored->source_listener){ + i16temp = htons(stored->source_listener->port); + }else{ + i16temp = 0; } + write_e(db_fptr, &i16temp, sizeof(uint16_t)); + i16temp = htons(stored->source_mid); write_e(db_fptr, &i16temp, sizeof(uint16_t)); @@ -214,6 +228,7 @@ static int persist__message_store_write(struct mosquitto_db *db, FILE *db_fptr) if(stored->payloadlen){ write_e(db_fptr, UHPA_ACCESS_PAYLOAD(stored), (unsigned int)stored->payloadlen); } + stored = stored->next; } @@ -265,6 +280,60 @@ static int persist__client_write(struct mosquitto_db *db, FILE *db_fptr) return 1; } + +static int persist__read_string(FILE *db_fptr, char **str) +{ + uint16_t i16temp; + uint16_t slen; + char *s = NULL; + + if(fread(&i16temp, 1, sizeof(uint16_t), db_fptr) != sizeof(uint16_t)){ + return MOSQ_ERR_INVAL; + } + + slen = ntohs(i16temp); + if(slen){ + s = mosquitto__malloc(slen+1); + if(!s){ + fclose(db_fptr); + log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); + return MOSQ_ERR_NOMEM; + } + if(fread(s, 1, slen, db_fptr) != slen){ + mosquitto__free(s); + return MOSQ_ERR_NOMEM; + } + s[slen] = '\0'; + } + + *str = s; + return MOSQ_ERR_SUCCESS; +} + + +static int persist__write_string(FILE *db_fptr, const char *str, bool nullok) +{ + uint16_t i16temp, slen; + + if(str){ + slen = strlen(str); + i16temp = htons(slen); + write_e(db_fptr, &i16temp, sizeof(uint16_t)); + write_e(db_fptr, str, slen); + }else if(nullok){ + i16temp = htons(0); + write_e(db_fptr, &i16temp, sizeof(uint16_t)); + }else{ + return 1; + } + + return MOSQ_ERR_SUCCESS; +error: + log__printf(NULL, MOSQ_LOG_ERR, "Error: %s.", strerror(errno)); + return 1; +} + + static int persist__subs_retain_write(struct mosquitto_db *db, FILE *db_fptr, struct mosquitto__subhier *node, const char *topic, int level) { struct mosquitto__subhier *subhier, *subhier_tmp; @@ -642,10 +711,10 @@ static int persist__msg_store_chunk_restore(struct mosquitto_db *db, FILE *db_fp { dbid_t i64temp, store_id; uint32_t i32temp, payloadlen = 0; - uint16_t i16temp, slen, source_mid; + uint16_t i16temp, source_mid, source_port = 0; uint8_t qos, retain; mosquitto__payload_uhpa payload; - char *source_id = NULL; + struct mosquitto source; char *topic = NULL; int rc = 0; struct mosquitto_msg_store *stored = NULL; @@ -664,41 +733,45 @@ static int persist__msg_store_chunk_restore(struct mosquitto_db *db, FILE *db_fp read_e(db_fptr, &i64temp, sizeof(dbid_t)); store_id = i64temp; - read_e(db_fptr, &i16temp, sizeof(uint16_t)); - slen = ntohs(i16temp); - if(slen){ - source_id = mosquitto__malloc(slen+1); - if(!source_id){ + memset(&source, 0, sizeof(struct mosquitto)); + + rc = persist__read_string(db_fptr, &source.id); + if(rc){ + mosquitto__free(load); + return rc; + } + if(db_version == 4){ + rc = persist__read_string(db_fptr, &source.username); + if(rc){ mosquitto__free(load); - fclose(db_fptr); - log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); - return MOSQ_ERR_NOMEM; + return rc; + } + read_e(db_fptr, &i16temp, sizeof(uint16_t)); + source_port = ntohs(i16temp); + if(source_port){ + for(int i=0; iconfig->listener_count; i++){ + if(db->config->listeners[i].port == source_port){ + source.listener = &db->config->listeners[i]; + break; + } + } } - read_e(db_fptr, source_id, slen); - source_id[slen] = '\0'; } + read_e(db_fptr, &i16temp, sizeof(uint16_t)); source_mid = ntohs(i16temp); /* This is the mid - don't need it */ read_e(db_fptr, &i16temp, sizeof(uint16_t)); - read_e(db_fptr, &i16temp, sizeof(uint16_t)); - slen = ntohs(i16temp); - if(slen){ - topic = mosquitto__malloc(slen+1); - if(!topic){ - mosquitto__free(load); - fclose(db_fptr); - mosquitto__free(source_id); - log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); - return MOSQ_ERR_NOMEM; - } - read_e(db_fptr, topic, slen); - topic[slen] = '\0'; - }else{ - topic = NULL; + rc = persist__read_string(db_fptr, &topic); + if(rc){ + mosquitto__free(load); + fclose(db_fptr); + mosquitto__free(source.id); + return rc; } + read_e(db_fptr, &qos, sizeof(uint8_t)); read_e(db_fptr, &retain, sizeof(uint8_t)); @@ -709,7 +782,7 @@ static int persist__msg_store_chunk_restore(struct mosquitto_db *db, FILE *db_fp if(UHPA_ALLOC(payload, payloadlen) == 0){ mosquitto__free(load); fclose(db_fptr); - mosquitto__free(source_id); + mosquitto__free(source.id); mosquitto__free(topic); log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; @@ -717,8 +790,8 @@ static int persist__msg_store_chunk_restore(struct mosquitto_db *db, FILE *db_fp read_e(db_fptr, UHPA_ACCESS(payload, payloadlen), payloadlen); } - rc = db__message_store(db, source_id, source_mid, topic, qos, payloadlen, &payload, retain, &stored, store_id); - mosquitto__free(source_id); + rc = db__message_store(db, &source, source_mid, topic, qos, payloadlen, &payload, retain, &stored, store_id); + mosquitto__free(source.id); if(rc == MOSQ_ERR_SUCCESS){ load->db_id = stored->db_id; @@ -737,7 +810,7 @@ static int persist__msg_store_chunk_restore(struct mosquitto_db *db, FILE *db_fp err = strerror(errno); log__printf(NULL, MOSQ_LOG_ERR, "Error: %s.", err); fclose(db_fptr); - mosquitto__free(source_id); + mosquitto__free(source.id); mosquitto__free(topic); UHPA_FREE(payload, payloadlen); return 1; @@ -768,35 +841,24 @@ static int persist__retain_chunk_restore(struct mosquitto_db *db, FILE *db_fptr) static int persist__sub_chunk_restore(struct mosquitto_db *db, FILE *db_fptr) { - uint16_t i16temp, slen; uint8_t qos; char *client_id; char *topic; int rc = 0; char *err; - read_e(db_fptr, &i16temp, sizeof(uint16_t)); - slen = ntohs(i16temp); - client_id = mosquitto__malloc(slen+1); - if(!client_id){ + rc = persist__read_string(db_fptr, &client_id); + if(rc){ fclose(db_fptr); - log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); - return MOSQ_ERR_NOMEM; + return rc; } - read_e(db_fptr, client_id, slen); - client_id[slen] = '\0'; - read_e(db_fptr, &i16temp, sizeof(uint16_t)); - slen = ntohs(i16temp); - topic = mosquitto__malloc(slen+1); - if(!topic){ - fclose(db_fptr); - log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); + rc = persist__read_string(db_fptr, &topic); + if(rc){ mosquitto__free(client_id); - return MOSQ_ERR_NOMEM; + fclose(db_fptr); + return rc; } - read_e(db_fptr, topic, slen); - topic[slen] = '\0'; read_e(db_fptr, &qos, sizeof(uint8_t)); if(persist__restore_sub(db, client_id, topic, qos)){ @@ -852,7 +914,9 @@ int persist__restore(struct mosquitto_db *db) * Is your DB change still compatible with previous versions? */ if(db_version > MOSQ_DB_VERSION && db_version != 0){ - if(db_version == 2){ + if(db_version == 3){ + /* Addition of source_username and source_port to msg_store chunk in v4, v1.5.6 */ + }else if(db_version == 2){ /* Addition of disconnect_t to client chunk in v3. */ }else{ fclose(fptr); diff --git a/src/persist.h b/src/persist.h index 63a1a0cd7f..04f263425d 100644 --- a/src/persist.h +++ b/src/persist.h @@ -17,7 +17,7 @@ and the Eclipse Distribution License is available at #ifndef PERSIST_H #define PERSIST_H -#define MOSQ_DB_VERSION 3 +#define MOSQ_DB_VERSION 4 /* DB read/write */ const unsigned char magic[15] = {0x00, 0xB5, 0x00, 'm','o','s','q','u','i','t','t','o',' ','d','b'}; diff --git a/src/security_default.c b/src/security_default.c index 5a886a53df..44089d9bf2 100644 --- a/src/security_default.c +++ b/src/security_default.c @@ -610,6 +610,49 @@ static int acl__cleanup(struct mosquitto_db *db, bool reload) return MOSQ_ERR_SUCCESS; } + +int acl__find_acls(struct mosquitto_db *db, struct mosquitto *context) +{ + struct mosquitto__acl_user *acl_tail; + struct mosquitto__security_options *security_opts; + + /* Associate user with its ACL, assuming we have ACLs loaded. */ + if(db->config->per_listener_settings){ + if(!context->listener){ + return MOSQ_ERR_INVAL; + } + security_opts = &context->listener->security_options; + }else{ + security_opts = &db->config->security_options; + } + + if(security_opts->acl_list){ + acl_tail = security_opts->acl_list; + while(acl_tail){ + if(context->username){ + if(acl_tail->username && !strcmp(context->username, acl_tail->username)){ + context->acl_list = acl_tail; + break; + } + }else{ + if(acl_tail->username == NULL){ + context->acl_list = acl_tail; + break; + } + } + acl_tail = acl_tail->next; + } + if(context->username && context->acl_list == NULL){ + return MOSQ_ERR_INVAL; + } + }else{ + context->acl_list = NULL; + } + + return MOSQ_ERR_SUCCESS; +} + + static int pwfile__parse(const char *file, struct mosquitto__unpwd **root) { FILE *pwfile; diff --git a/src/subs.c b/src/subs.c index 5953055c3c..bae4cb439b 100644 --- a/src/subs.c +++ b/src/subs.c @@ -659,6 +659,27 @@ static int retain__process(struct mosquitto_db *db, struct mosquitto_msg_store * return rc; } + /* Check for original source access */ + if(db->config->check_retain_source && retained->source_id){ + struct mosquitto retain_ctxt; + memset(&retain_ctxt, 0, sizeof(struct mosquitto)); + + retain_ctxt.id = retained->source_id; + retain_ctxt.username = retained->source_username; + retain_ctxt.listener = retained->source_listener; + + rc = acl__find_acls(db, &retain_ctxt); + if(rc) return rc; + + rc = mosquitto_acl_check(db, &retain_ctxt, retained->topic, retained->payloadlen, UHPA_ACCESS(retained->payload, retained->payloadlen), + retained->qos, retained->retain, MOSQ_ACL_WRITE); + if(rc == MOSQ_ERR_ACL_DENIED){ + return MOSQ_ERR_SUCCESS; + }else if(rc != MOSQ_ERR_SUCCESS){ + return rc; + } + } + if (db->config->upgrade_outgoing_qos){ qos = sub_qos; } else { diff --git a/test/broker/04-retain-check-source-persist-diff-port.py b/test/broker/04-retain-check-source-persist-diff-port.py new file mode 100755 index 0000000000..c26ebe5fa4 --- /dev/null +++ b/test/broker/04-retain-check-source-persist-diff-port.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python + +# Test for CVE-2018-12546, with the broker being stopped to write the persistence file, plus subscriber on different port. + +import inspect, os, sys +# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder +cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) +if cmd_subfolder not in sys.path: + sys.path.insert(0, cmd_subfolder) + +import mosq_test +import signal + +def write_config(filename, port1, port2, per_listener): + with open(filename, 'w') as f: + f.write("per_listener_settings %s\n" % (per_listener)) + f.write("check_retain_source true\n") + f.write("port %d\n" % (port1)) + f.write("acl_file %s\n" % (filename.replace('.conf', '.acl'))) + f.write("persistence true\n") + f.write("persistence_file %s\n" % (filename.replace('.conf', '.db'))) + f.write("listener %d\n" % (port2)) + +def write_acl_1(filename, username): + with open(filename, 'w') as f: + if username is not None: + f.write('user %s\n' % (username)) + f.write('topic readwrite test/topic\n') + +def write_acl_2(filename, username): + with open(filename, 'w') as f: + if username is not None: + f.write('user %s\n' % (username)) + f.write('topic read test/topic\n') + + +def do_test(per_listener, username): + conf_file = os.path.basename(__file__).replace('.py', '.conf') + write_config(conf_file, port1, port2, per_listener) + + persistence_file = os.path.basename(__file__).replace('.py', '.db') + try: + os.remove(persistence_file) + except OSError: + pass + + acl_file = os.path.basename(__file__).replace('.py', '.acl') + write_acl_1(acl_file, username) + + + rc = 1 + keepalive = 60 + connect_packet = mosq_test.gen_connect("retain-check", keepalive=keepalive, username=username) + connack_packet = mosq_test.gen_connack(rc=0) + + if per_listener == "true": + u = None + else: + # If per listener is false, then the second client will be denied + # unless we provide a username + u = username + + connect2_packet = mosq_test.gen_connect("retain-recv", keepalive=keepalive, username=u) + connack2_packet = mosq_test.gen_connack(rc=0) + + mid = 1 + publish_packet = mosq_test.gen_publish("test/topic", qos=0, payload="retained message", retain=True) + subscribe_packet = mosq_test.gen_subscribe(mid, "test/topic", 0) + suback_packet = mosq_test.gen_suback(mid, 0) + + pingreq_packet = mosq_test.gen_pingreq() + pingresp_packet = mosq_test.gen_pingresp() + + broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port1) + + try: + sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port1) + sock.send(publish_packet) + sock.close() + + sock = mosq_test.do_client_connect(connect2_packet, connack2_packet, port=port2) + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback 1") + + if mosq_test.expect_packet(sock, "publish", publish_packet): + sock.close() + + # Remove "write" ability + write_acl_2(acl_file, username) + broker.terminate() + broker.wait() + + broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port1) + + sock = mosq_test.do_client_connect(connect2_packet, connack2_packet, port=port2) + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback 2") + # If we receive the retained message here, it is a failure. + mosq_test.do_send_receive(sock, pingreq_packet, pingresp_packet, "pingresp") + rc = 0 + + sock.close() + finally: + broker.terminate() + broker.wait() + os.remove(conf_file) + os.remove(acl_file) + os.remove(persistence_file) + (stdo, stde) = broker.communicate() + if rc: + print(stde) + exit(rc) + + +(port1, port2) = mosq_test.get_port(2) +do_test("true", username=None) +do_test("true", username="test") +do_test("false", username=None) +do_test("false", username="test") diff --git a/test/broker/04-retain-check-source-persist.py b/test/broker/04-retain-check-source-persist.py new file mode 100755 index 0000000000..d383908ee3 --- /dev/null +++ b/test/broker/04-retain-check-source-persist.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python + +# Test for CVE-2018-12546, with the broker being stopped to write the persistence file. + +import inspect, os, sys +# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder +cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) +if cmd_subfolder not in sys.path: + sys.path.insert(0, cmd_subfolder) + +import mosq_test +import signal + +def write_config(filename, port, per_listener): + with open(filename, 'w') as f: + f.write("per_listener_settings %s\n" % (per_listener)) + f.write("check_retain_source true\n") + f.write("port %d\n" % (port)) + f.write("acl_file %s\n" % (filename.replace('.conf', '.acl'))) + f.write("persistence true\n") + f.write("persistence_file %s\n" % (filename.replace('.conf', '.db'))) + +def write_acl_1(filename, username): + with open(filename, 'w') as f: + if username is not None: + f.write('user %s\n' % (username)) + f.write('topic readwrite test/topic\n') + +def write_acl_2(filename, username): + with open(filename, 'w') as f: + if username is not None: + f.write('user %s\n' % (username)) + f.write('topic read test/topic\n') + + +def do_test(per_listener, username): + conf_file = os.path.basename(__file__).replace('.py', '.conf') + write_config(conf_file, port, per_listener) + + persistence_file = os.path.basename(__file__).replace('.py', '.db') + try: + os.remove(persistence_file) + except OSError: + pass + + acl_file = os.path.basename(__file__).replace('.py', '.acl') + write_acl_1(acl_file, username) + + + rc = 1 + keepalive = 60 + connect_packet = mosq_test.gen_connect("retain-check", keepalive=keepalive, username=username) + connack_packet = mosq_test.gen_connack(rc=0) + + mid = 1 + publish_packet = mosq_test.gen_publish("test/topic", qos=0, payload="retained message", retain=True) + subscribe_packet = mosq_test.gen_subscribe(mid, "test/topic", 0) + suback_packet = mosq_test.gen_suback(mid, 0) + + pingreq_packet = mosq_test.gen_pingreq() + pingresp_packet = mosq_test.gen_pingresp() + + broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port) + + try: + sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port) + sock.send(publish_packet) + sock.close() + + sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port) + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback 1") + + if mosq_test.expect_packet(sock, "publish", publish_packet): + sock.close() + + # Remove "write" ability + write_acl_2(acl_file, username) + broker.terminate() + broker.wait() + + broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port) + + sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port) + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback 2") + # If we receive the retained message here, it is a failure. + mosq_test.do_send_receive(sock, pingreq_packet, pingresp_packet, "pingresp") + rc = 0 + + sock.close() + finally: + broker.terminate() + broker.wait() + os.remove(conf_file) + os.remove(acl_file) + os.remove(persistence_file) + (stdo, stde) = broker.communicate() + if rc: + print(stde) + exit(rc) + + +port = mosq_test.get_port() +do_test("true", username=None) +do_test("true", username="test") +do_test("false", username=None) +do_test("false", username="test") diff --git a/test/broker/04-retain-check-source.py b/test/broker/04-retain-check-source.py new file mode 100755 index 0000000000..4ef512752e --- /dev/null +++ b/test/broker/04-retain-check-source.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python + +# Test for CVE-2018-12546 + +import inspect, os, sys +# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder +cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) +if cmd_subfolder not in sys.path: + sys.path.insert(0, cmd_subfolder) + +import mosq_test +import signal + +def write_config(filename, port, per_listener): + with open(filename, 'w') as f: + f.write("per_listener_settings %s\n" % (per_listener)) + f.write("check_retain_source true\n") + f.write("port %d\n" % (port)) + f.write("acl_file %s\n" % (filename.replace('.conf', '.acl'))) + +def write_acl_1(filename): + with open(filename, 'w') as f: + f.write('topic readwrite test/topic\n') + +def write_acl_2(filename): + with open(filename, 'w') as f: + f.write('topic read test/topic\n') + + +def do_test(per_listener): + conf_file = os.path.basename(__file__).replace('.py', '.conf') + write_config(conf_file, port, per_listener) + + acl_file = os.path.basename(__file__).replace('.py', '.acl') + write_acl_1(acl_file) + + + rc = 1 + keepalive = 60 + connect_packet = mosq_test.gen_connect("retain-check", keepalive=keepalive) + connack_packet = mosq_test.gen_connack(rc=0) + + mid = 1 + publish_packet = mosq_test.gen_publish("test/topic", qos=0, payload="retained message", retain=True) + subscribe_packet = mosq_test.gen_subscribe(mid, "test/topic", 0) + suback_packet = mosq_test.gen_suback(mid, 0) + + pingreq_packet = mosq_test.gen_pingreq() + pingresp_packet = mosq_test.gen_pingresp() + + broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port) + + try: + sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port) + sock.send(publish_packet) + sock.close() + + sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port) + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback 1") + + if mosq_test.expect_packet(sock, "publish", publish_packet): + sock.close() + + # Remove "write" ability + write_acl_2(acl_file) + broker.send_signal(signal.SIGHUP) + + sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port) + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback 2") + # If we receive the retained message here, it is a failure. + mosq_test.do_send_receive(sock, pingreq_packet, pingresp_packet, "pingresp") + rc = 0 + + sock.close() + finally: + os.remove(conf_file) + os.remove(acl_file) + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + exit(rc) + +port = mosq_test.get_port() +do_test("true") +do_test("false") diff --git a/test/broker/Makefile b/test/broker/Makefile index d3b3e43889..715b97c717 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -76,6 +76,9 @@ endif ./04-retain-qos1-qos0.py ./04-retain-qos0-clear.py ./04-retain-upgrade-outgoing-qos.py + ./04-retain-check-source.py + ./04-retain-check-source-persist.py + ./04-retain-check-source-persist-diff-port.py 05 : ./05-clean-session-qos1.py diff --git a/test/broker/ptest.py b/test/broker/ptest.py index 28f14f97e2..f21ae8ce2b 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -57,6 +57,9 @@ (1, './04-retain-qos1-qos0.py'), (1, './04-retain-qos0-clear.py'), (1, './04-retain-upgrade-outgoing-qos.py'), + (1, './04-retain-check-source.py'), + (1, './04-retain-check-source-persist.py'), + (2, './04-retain-check-source-persist-diff-port.py'), (1, './05-clean-session-qos1.py'), From 9df6da16ec01d9f46c71ef07b4bb39d1c8f8a06e Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sun, 3 Feb 2019 08:07:32 +0000 Subject: [PATCH 218/254] Improve documentation of use_identity_as_username. Closes #1134. Thanks to Adrian P. --- man/mosquitto.conf.5.xml | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml index d941c98577..9f164f16b7 100644 --- a/man/mosquitto.conf.5.xml +++ b/man/mosquitto.conf.5.xml @@ -64,15 +64,17 @@ certificate in order to connect successfully. In this case, the second and third options, use_identity_as_username and use_subject_as_username, become relevant. If set to true, - use_identity_as_user causes the Common Name (CN) from the client - certificate to be used instead of the MQTT username for access - control purposes. The password is not replaced because it is - assumed that only authenticated clients have valid certificates. If - use_identity_as_username is false, the client must authenticate as - normal (if required by password_file) through the MQTT options. The - same principle applies for the use_subject_as_username option, but - the entire certificate subject is used as the username instead of - just the CN. + use_identity_as_username causes the Common Name (CN) from the + client certificate to be used instead of the MQTT username for + access control purposes. The password is not used because it is + assumed that only authenticated clients have valid certificates. + This means that any CA certificates you include in cafile or capath + will be able to issue client certificates that are valid for + connecting to your broker. If use_identity_as_username is false, + the client must authenticate as normal (if required by + password_file) through the MQTT options. The same principle applies + for the use_subject_as_username option, but the entire certificate + subject is used as the username instead of just the CN. When using pre-shared-key based encryption through the psk_hint and psk_file options, the client must provide a valid identity and key in order to connect to the broker before any MQTT communication From ce1d0ae3642aa480f89ee279426d9d6ec7ec7014 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sun, 3 Feb 2019 08:26:00 +0000 Subject: [PATCH 219/254] Man page can now be built on any system. Closes #1139. Huge thanks to Chris Mayo. --- ChangeLog.txt | 1 + config.mk | 2 +- man/html.xsl | 2 +- man/manpage.xsl | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 6d22cf5cea..0c59e5ad25 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -38,6 +38,7 @@ Build: - Fix comparison of boolean values in CMake build. Closes #1101. - Fix compilation when openssl deprecated APIs are not available. Closes #1094. +- Man pages can now be built on any system. Closes #1139. 1.5.5 - 20181211 diff --git a/config.mk b/config.mk index 0ee3fa4459..ce92090d95 100644 --- a/config.mk +++ b/config.mk @@ -111,7 +111,7 @@ VERSION=1.5.5 SOVERSION=1 # Man page generation requires xsltproc and docbook-xsl -XSLTPROC=xsltproc +XSLTPROC=xsltproc --nonet # For html generation DB_HTML_XSL=man/html.xsl diff --git a/man/html.xsl b/man/html.xsl index 44f0018714..3fba92a248 100644 --- a/man/html.xsl +++ b/man/html.xsl @@ -1,6 +1,6 @@ - + man.css diff --git a/man/manpage.xsl b/man/manpage.xsl index 0ebd8d4a4e..ec4e6b7004 100644 --- a/man/manpage.xsl +++ b/man/manpage.xsl @@ -1,6 +1,6 @@ - + 0 From 29a1936c772a45bad709547a980a560d48e6f720 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sun, 3 Feb 2019 20:36:44 +0000 Subject: [PATCH 220/254] Fix spaces not being allowed in the bridge remote_username option. Closes #1131. Thanks to beville. --- ChangeLog.txt | 2 ++ src/conf.c | 16 +--------------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 0c59e5ad25..f17e68a081 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -28,6 +28,8 @@ Broker: - Fixed comment handling for config options that have optional arguments. - Improved documentation around bridge topic remapping. - Handle mismatched handshakes (e.g. QoS1 PUBLISH with QoS2 reply) properly. +- Fix spaces not being allowed in the bridge remote_username option. Closes + #1131. Library: - Fix TLS connections not working over SOCKS. diff --git a/src/conf.c b/src/conf.c index f81219f36d..8479fd257e 100644 --- a/src/conf.c +++ b/src/conf.c @@ -2026,21 +2026,7 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } - token = strtok_r(NULL, " ", &saveptr); - if(token){ - if(cur_bridge->remote_username){ - log__printf(NULL, MOSQ_LOG_ERR, "Error: Duplicate username value in bridge configuration."); - return MOSQ_ERR_INVAL; - } - cur_bridge->remote_username = mosquitto__strdup(token); - if(!cur_bridge->remote_username){ - log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); - return MOSQ_ERR_NOMEM; - } - }else{ - log__printf(NULL, MOSQ_LOG_ERR, "Error: Empty username value in configuration."); - return MOSQ_ERR_INVAL; - } + if(conf__parse_string(&token, "bridge remote_username", &cur_bridge->remote_username, saveptr)) return MOSQ_ERR_INVAL; #else log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif From ab8b57ff54a160bf61a0bcfa008c956804e651c4 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sun, 3 Feb 2019 20:46:23 +0000 Subject: [PATCH 221/254] Allow broker to always restart on Windows when using `log_dest file`. Closes #1080. Thanks to lcouz. --- ChangeLog.txt | 2 ++ lib/util_mosq.c | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index f17e68a081..e72b92112b 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -30,6 +30,8 @@ Broker: - Handle mismatched handshakes (e.g. QoS1 PUBLISH with QoS2 reply) properly. - Fix spaces not being allowed in the bridge remote_username option. Closes #1131. +- Allow broker to always restart on Windows when using `log_dest file`. Closes + #1080. Library: - Fix TLS connections not working over SOCKS. diff --git a/lib/util_mosq.c b/lib/util_mosq.c index 72666872f3..350d1ccc36 100644 --- a/lib/util_mosq.c +++ b/lib/util_mosq.c @@ -404,6 +404,21 @@ FILE *mosquitto__fopen(const char *path, const char *mode, bool restrict_read) char username[UNLEN + 1]; int ulen = UNLEN; SECURITY_DESCRIPTOR sd; + DWORD dwCreationDisposition; + + switch(mode[0]){ + case 'a': + dwCreationDisposition = OPEN_ALWAYS; + break; + case 'r': + dwCreationDisposition = OPEN_EXISTING; + break; + case 'w': + dwCreationDisposition = CREATE_ALWAYS; + break; + default: + return NULL; + } GetUserName(username, &ulen); if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { @@ -424,7 +439,7 @@ FILE *mosquitto__fopen(const char *path, const char *mode, bool restrict_read) hfile = CreateFile(buf, GENERIC_READ | GENERIC_WRITE, 0, &sec, - CREATE_NEW, + dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); From d6a690aa8d10070db8a75417560056998a39b6aa Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sun, 3 Feb 2019 22:01:33 +0000 Subject: [PATCH 222/254] Fix Will not being sent for Websockets clients. Closes #1143. Thanks to salcedo. --- ChangeLog.txt | 1 + lib/mosquitto_internal.h | 3 +-- src/context.c | 14 +++++++++----- src/loop.c | 10 ++-------- src/mosquitto_broker_internal.h | 1 + 5 files changed, 14 insertions(+), 15 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index e72b92112b..46e45e394f 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -32,6 +32,7 @@ Broker: #1131. - Allow broker to always restart on Windows when using `log_dest file`. Closes #1080. +- Fix Will not being sent for Websockets clients. Closes #1143. Library: - Fix TLS connections not working over SOCKS. diff --git a/lib/mosquitto_internal.h b/lib/mosquitto_internal.h index c6b3d6e526..55d3862607 100644 --- a/lib/mosquitto_internal.h +++ b/lib/mosquitto_internal.h @@ -208,8 +208,7 @@ struct mosquitto { #endif bool clean_session; #ifdef WITH_BROKER - char *old_id; /* for when a duplicate client connects, but we still want to - know what the id was */ + bool removed_from_by_id; /* True if removed from by_id hash */ bool is_dropping; bool is_bridge; struct mosquitto__bridge *bridge; diff --git a/src/context.c b/src/context.c index e8cbfdfc45..b7e4756544 100644 --- a/src/context.c +++ b/src/context.c @@ -157,14 +157,10 @@ void context__cleanup(struct mosquitto_db *db, struct mosquitto *context, bool d assert(db); /* db can only be NULL here if the client hasn't sent a CONNECT and hence wouldn't have an id. */ - HASH_DELETE(hh_id, db->contexts_by_id, context); + context__remove_from_by_id(db, context); mosquitto__free(context->id); context->id = NULL; } - if(context->old_id){ - mosquitto__free(context->old_id); - context->old_id = NULL; - } packet__cleanup(&(context->in_packet)); if(context->current_out_packet){ packet__cleanup(context->current_out_packet); @@ -260,3 +256,11 @@ void context__free_disused(struct mosquitto_db *db) db->ll_for_free = NULL; } + +void context__remove_from_by_id(struct mosquitto_db *db, struct mosquitto *context) +{ + if(context->removed_from_by_id == false && context->id){ + HASH_DELETE(hh_id, db->contexts_by_id, context); + context->removed_from_by_id = true; + } +} diff --git a/src/loop.c b/src/loop.c index 8d08474917..980de51899 100644 --- a/src/loop.c +++ b/src/loop.c @@ -644,19 +644,13 @@ void do_disconnect(struct mosquitto_db *db, struct mosquitto *context) context->sock = INVALID_SOCKET; context->pollfd_index = -1; } - if(context->id){ - HASH_DELETE(hh_id, db->contexts_by_id, context); - context->old_id = context->id; - context->id = NULL; - } + context__remove_from_by_id(db, context); }else #endif { if(db->config->connection_messages == true){ if(context->id){ id = context->id; - }else if(context->old_id){ - id = context->old_id; }else{ id = ""; } @@ -681,7 +675,7 @@ void do_disconnect(struct mosquitto_db *db, struct mosquitto *context) #endif context__add_to_disused(db, context); if(context->id){ - HASH_DELETE(hh_id, db->contexts_by_id, context); + context__remove_from_by_id(db, context); mosquitto__free(context->id); context->id = NULL; } diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index c3655981a5..3130584152 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -587,6 +587,7 @@ void context__disconnect(struct mosquitto_db *db, struct mosquitto *context); void context__add_to_disused(struct mosquitto_db *db, struct mosquitto *context); void context__free_disused(struct mosquitto_db *db); void context__send_will(struct mosquitto_db *db, struct mosquitto *context); +void context__remove_from_by_id(struct mosquitto_db *db, struct mosquitto *context); /* ============================================================ * Logging functions From 17b52bd5d104baaaa4be46c6b99f06876d497057 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sat, 2 Feb 2019 22:39:47 +0000 Subject: [PATCH 223/254] Windows: Fix possible crash when client disconnects. Closes #1137. Thanks to Kris Mattheus. --- ChangeLog.txt | 1 + src/websockets.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 46e45e394f..f4a9ddcf43 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -33,6 +33,7 @@ Broker: - Allow broker to always restart on Windows when using `log_dest file`. Closes #1080. - Fix Will not being sent for Websockets clients. Closes #1143. +- Windows: Fix possible crash when client disconnects. Closes #1137. Library: - Fix TLS connections not working over SOCKS. diff --git a/src/websockets.c b/src/websockets.c index 163c222eb8..4db2e8dfc3 100644 --- a/src/websockets.c +++ b/src/websockets.c @@ -247,7 +247,7 @@ static int callback_mqtt(struct libwebsocket_context *context, } mosq = u->mosq; if(mosq){ - if(mosq->sock > 0){ + if(mosq->sock != INVALID_SOCKET){ HASH_DELETE(hh_sock, db->contexts_by_sock, mosq); mosq->sock = INVALID_SOCKET; mosq->pollfd_index = -1; From f952ae3a672cfc7f7d97f1a37e049e2a25d37d68 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sun, 3 Feb 2019 22:26:10 +0000 Subject: [PATCH 224/254] Fixed durable clients being unable to receive messages when offline. This occurred when per_listener_settings was set to true. Closes #1081. Thanks to dwin-wangjt. --- ChangeLog.txt | 2 ++ lib/net_mosq.c | 2 -- lib/util_mosq.c | 5 ----- man/mosquitto.conf.5.xml | 4 ++++ mosquitto.conf | 4 ++++ 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index f4a9ddcf43..7785799e04 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -34,6 +34,8 @@ Broker: #1080. - Fix Will not being sent for Websockets clients. Closes #1143. - Windows: Fix possible crash when client disconnects. Closes #1137. +- Fixed durable clients being unable to receive messages when offline, when + per_listener_settings was set to true. Closes #1081. Library: - Fix TLS connections not working over SOCKS. diff --git a/lib/net_mosq.c b/lib/net_mosq.c index c7de615af1..ed783cadd2 100644 --- a/lib/net_mosq.c +++ b/lib/net_mosq.c @@ -174,8 +174,6 @@ int net__socket_close(struct mosquitto *mosq) #ifdef WITH_BROKER if(mosq->listener){ mosq->listener->client_count--; - assert(mosq->listener->client_count >= 0); - mosq->listener = NULL; } #endif diff --git a/lib/util_mosq.c b/lib/util_mosq.c index 350d1ccc36..4caed72b1a 100644 --- a/lib/util_mosq.c +++ b/lib/util_mosq.c @@ -89,11 +89,6 @@ int mosquitto__check_keepalive(struct mosquitto *mosq) pthread_mutex_unlock(&mosq->msgtime_mutex); }else{ #ifdef WITH_BROKER - if(mosq->listener){ - mosq->listener->client_count--; - assert(mosq->listener->client_count >= 0); - } - mosq->listener = NULL; net__socket_close(db, mosq); #else net__socket_close(mosq); diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml index 9f164f16b7..60337bf9dc 100644 --- a/man/mosquitto.conf.5.xml +++ b/man/mosquitto.conf.5.xml @@ -535,6 +535,10 @@ , , . + Note that if set to true, then a durable client (i.e. + with clean session set to false) that has disconnected + will use the ACL settings defined for the listener that + it was most recently connected to. The default behaviour is for this to be set to false, which maintains the settings behaviour from previous versions of diff --git a/mosquitto.conf b/mosquitto.conf index e8c43397fa..d0ec0df7b6 100644 --- a/mosquitto.conf +++ b/mosquitto.conf @@ -144,6 +144,10 @@ # password_file acl_file psk_file auth_plugin auth_opt_* allow_anonymous # auto_id_prefix allow_zero_length_clientid # +# Note that if set to true, then a durable client (i.e. with clean session set +# to false) that has disconnected will use the ACL settings defined for the +# listener that it was most recently connected to. +# # The default behaviour is for this to be set to false, which maintains the # setting behaviour from previous versions of mosquitto. #per_listener_settings false From 1c075988ca266874b99cd81877db5a87524c227b Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 6 Feb 2019 09:10:05 +0000 Subject: [PATCH 225/254] Log message for disconnecting a client with invalid UTF-8 topic. Closes #1144. Thanks to Kris Mattheus. --- ChangeLog.txt | 2 ++ src/handle_publish.c | 1 + 2 files changed, 3 insertions(+) diff --git a/ChangeLog.txt b/ChangeLog.txt index 7785799e04..3764ebfd51 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -36,6 +36,8 @@ Broker: - Windows: Fix possible crash when client disconnects. Closes #1137. - Fixed durable clients being unable to receive messages when offline, when per_listener_settings was set to true. Closes #1081. +- Add log message for the case where a client is disconnected for sending a + topic with invalid UTF-8. Closes #1144. Library: - Fix TLS connections not working over SOCKS. diff --git a/src/handle_publish.c b/src/handle_publish.c index 76b3ee8943..2402869bed 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -70,6 +70,7 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) } if(mosquitto_validate_utf8(topic, slen) != MOSQ_ERR_SUCCESS){ + log__printf(NULL, MOSQ_LOG_INFO, "Client %s sent topic with invalid UTF-8, disconnecting.", context->id); mosquitto__free(topic); return 1; } From 7ff9c3763b0d2bd1c6cd7e8769ae7d3ac9150edf Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 6 Feb 2019 12:22:29 +0000 Subject: [PATCH 226/254] Fix socks build when using cmake. --- lib/net_mosq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/net_mosq.c b/lib/net_mosq.c index ed783cadd2..3d47259702 100644 --- a/lib/net_mosq.c +++ b/lib/net_mosq.c @@ -665,7 +665,7 @@ int net__socket_connect(struct mosquitto *mosq, const char *host, uint16_t port, mosq->sock = sock; -#ifdef WITH_SOCKS +#if defined(WITH_SOCKS) && !defined(WITH_BROKER) if(!mosq->socks5_host) #endif { From a4f68869bfd02f2c8ce0ccad770f10a673d7aeda Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 6 Feb 2019 12:23:27 +0000 Subject: [PATCH 227/254] Fix cmake client build with TLS. --- client/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 56b5c73eb4..8daeda6a4c 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -1,5 +1,6 @@ include_directories(${mosquitto_SOURCE_DIR} ${mosquitto_SOURCE_DIR}/lib - ${STDBOOL_H_PATH} ${STDINT_H_PATH} ${PTHREAD_INCLUDE_DIR}) + ${STDBOOL_H_PATH} ${STDINT_H_PATH} ${PTHREAD_INCLUDE_DIR} + ${OPENSSL_INCLUDE_DIR}) link_directories(${mosquitto_BINARY_DIR}/lib) set(shared_src client_shared.c client_shared.h) From 05458eb35d76f96dff73a948bdb0519b4939cb70 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 6 Feb 2019 13:42:49 +0000 Subject: [PATCH 228/254] Fix some unused variable warnings. --- client/client_shared.c | 4 ++++ src/conf.c | 4 ++++ src/context.c | 2 ++ src/loop.c | 4 ++-- 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/client/client_shared.c b/client/client_shared.c index 8f993dc98d..981eea3a0e 100644 --- a/client/client_shared.c +++ b/client/client_shared.c @@ -34,7 +34,9 @@ and the Eclipse Distribution License is available at #include #include "client_shared.h" +#ifdef WITH_SOCKS static int mosquitto__parse_socks_url(struct mosq_config *cfg, char *url); +#endif static int client_config_line_proc(struct mosq_config *cfg, int pub_or_sub, int argc, char *argv[]); @@ -884,7 +886,9 @@ int client_config_line_proc(struct mosq_config *cfg, int pub_or_sub, int argc, c int client_opts_set(struct mosquitto *mosq, struct mosq_config *cfg) { +#ifdef WITH_SOCKS int rc; +#endif if(cfg->will_topic && mosquitto_will_set(mosq, cfg->will_topic, cfg->will_payloadlen, cfg->will_payload, cfg->will_qos, diff --git a/src/conf.c b/src/conf.c index 8479fd257e..14d3528442 100644 --- a/src/conf.c +++ b/src/conf.c @@ -269,7 +269,9 @@ void config__init(struct mosquitto_db *db, struct mosquitto__config *config) void config__cleanup(struct mosquitto__config *config) { int i; +#ifdef WITH_BRIDGE int j; +#endif mosquitto__free(config->clientid_prefixes); mosquitto__free(config->persistence_location); @@ -583,7 +585,9 @@ int config__read(struct mosquitto_db *db, struct mosquitto__config *config, bool int rc = MOSQ_ERR_SUCCESS; struct config_recurse cr; int lineno = 0; +#ifdef WITH_PERSISTENCE int len; +#endif struct mosquitto__config config_reload; int i; diff --git a/src/context.c b/src/context.c index b7e4756544..0a9ac17587 100644 --- a/src/context.c +++ b/src/context.c @@ -99,7 +99,9 @@ void context__cleanup(struct mosquitto_db *db, struct mosquitto *context, bool d { struct mosquitto__packet *packet; struct mosquitto_client_msg *msg, *next; +#ifdef WITH_BRIDGE int i; +#endif if(!context) return; diff --git a/src/loop.c b/src/loop.c index 980de51899..7535b6d0e8 100644 --- a/src/loop.c +++ b/src/loop.c @@ -128,11 +128,11 @@ int mosquitto_main_loop(struct mosquitto_db *db, mosq_sock_t *listensock, int li #endif #ifdef WITH_BRIDGE int rc; + int err; + socklen_t len; #endif time_t expiration_check_time = 0; char *id; - int err; - socklen_t len; #ifndef WIN32 sigemptyset(&sigblock); From 1b5c900e77901d4cb18997ae94d9ee90c3919f93 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 6 Feb 2019 15:44:53 +0000 Subject: [PATCH 229/254] Update CVE details and bump version number. --- CMakeLists.txt | 2 +- ChangeLog.txt | 8 ++++---- config.mk | 2 +- installer/mosquitto.nsi | 2 +- installer/mosquitto64.nsi | 2 +- lib/mosquitto.h | 2 +- set-version.sh | 2 +- snap/snapcraft.yaml | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8439e43b46..d37dc207c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ project(mosquitto) cmake_minimum_required(VERSION 2.8) # Only for version 3 and up. cmake_policy(SET CMP0042 NEW) -set (VERSION 1.5.5) +set (VERSION 1.5.6) add_definitions (-DCMAKE -DVERSION=\"${VERSION}\") diff --git a/ChangeLog.txt b/ChangeLog.txt index 3764ebfd51..322a23a15c 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,8 +1,8 @@ -1.5.6 - 201901xx +1.5.6 - 20190206 ================ Security: -- CVE-2018-xxxxx: If Mosquitto is configured to use a password file for +- CVE-2018-12551: If Mosquitto is configured to use a password file for authentication, any malformed data in the password file will be treated as valid. This typically means that the malformed data becomes a username and no password. If this occurs, clients can circumvent authentication and get access @@ -11,13 +11,13 @@ Security: unaffected. Users who have only used the mosquitto_passwd utility to create and modify their password files are unaffected by this vulnerability. Affects version 1.0 to 1.5.5 inclusive. -- CVE-2018-xxxxx: If an ACL file is empty, or has only blank lines or +- CVE-2018-12550: If an ACL file is empty, or has only blank lines or comments, then mosquitto treats the ACL file as not being defined, which means that no topic access is denied. Although denying access to all topics is not a useful configuration, this behaviour is unexpected and could lead to access being incorrectly granted in some circumstances. This is now fixed. Affects versions 1.0 to 1.5.5 inclusive. -- Fix CVE-2018-12546. If a client publishes a retained message to a topic that +- CVE-2018-12546. If a client publishes a retained message to a topic that they have access to, and then their access to that topic is revoked, the retained message will still be delivered to future subscribers. This behaviour may be undesirable in some applications, so a configuration option diff --git a/config.mk b/config.mk index ce92090d95..98210587ac 100644 --- a/config.mk +++ b/config.mk @@ -105,7 +105,7 @@ WITH_BUNDLED_DEPS:=yes # Also bump lib/mosquitto.h, CMakeLists.txt, # installer/mosquitto.nsi, installer/mosquitto64.nsi -VERSION=1.5.5 +VERSION=1.5.6 # Client library SO version. Bump if incompatible API/ABI changes are made. SOVERSION=1 diff --git a/installer/mosquitto.nsi b/installer/mosquitto.nsi index 0574e0b10e..bdcff77c8e 100644 --- a/installer/mosquitto.nsi +++ b/installer/mosquitto.nsi @@ -9,7 +9,7 @@ !define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' Name "Eclipse Mosquitto" -!define VERSION 1.5.5 +!define VERSION 1.5.6 OutFile "mosquitto-${VERSION}-install-windows-x86.exe" InstallDir "$PROGRAMFILES\mosquitto" diff --git a/installer/mosquitto64.nsi b/installer/mosquitto64.nsi index 5e9706c4b5..9368779de2 100644 --- a/installer/mosquitto64.nsi +++ b/installer/mosquitto64.nsi @@ -9,7 +9,7 @@ !define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' Name "Eclipse Mosquitto" -!define VERSION 1.5.5 +!define VERSION 1.5.6 OutFile "mosquitto-${VERSION}-install-windows-x64.exe" !include "x64.nsh" diff --git a/lib/mosquitto.h b/lib/mosquitto.h index 57a22ec341..767b854a28 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -47,7 +47,7 @@ extern "C" { #define LIBMOSQUITTO_MAJOR 1 #define LIBMOSQUITTO_MINOR 5 -#define LIBMOSQUITTO_REVISION 5 +#define LIBMOSQUITTO_REVISION 6 /* LIBMOSQUITTO_VERSION_NUMBER looks like 1002001 for e.g. version 1.2.1. */ #define LIBMOSQUITTO_VERSION_NUMBER (LIBMOSQUITTO_MAJOR*1000000+LIBMOSQUITTO_MINOR*1000+LIBMOSQUITTO_REVISION) diff --git a/set-version.sh b/set-version.sh index ec105f6bdb..69469c8859 100755 --- a/set-version.sh +++ b/set-version.sh @@ -2,7 +2,7 @@ MAJOR=1 MINOR=5 -REVISION=5 +REVISION=6 sed -i "s/^VERSION=.*/VERSION=${MAJOR}.${MINOR}.${REVISION}/" config.mk diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index b337fe0be4..970ae55c4a 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,5 +1,5 @@ name: mosquitto -version: 1.5.5 +version: 1.5.6 summary: Eclipse Mosquitto MQTT broker description: This is a message broker that supports version 3.1 and 3.1.1 of the MQTT protocol. From ff36baa49e37eb27d998314d46f01ddd914fdd65 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 7 Feb 2019 15:33:46 +0000 Subject: [PATCH 230/254] Bump Docker version. --- docker/1.5/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/1.5/Dockerfile b/docker/1.5/Dockerfile index 2c9b15c67f..0681f4ed74 100644 --- a/docker/1.5/Dockerfile +++ b/docker/1.5/Dockerfile @@ -3,8 +3,8 @@ FROM alpine:3.8 LABEL maintainer="Roger Light " \ description="Eclipse Mosquitto MQTT Broker" -ENV VERSION=1.5.5 \ - DOWNLOAD_SHA256=fcdb47e340864c545146681af7253399cc292e41775afd76400fda5b0d23d668 \ +ENV VERSION=1.5.6 \ + DOWNLOAD_SHA256=d5bdc13cc668350026376d57fc14de10aaee029f6840707677637d15e0751a40 \ GPG_KEYS=A0D6EEA1DCAE49A635A3B2F0779B22DFB3E717B7 \ LWS_VERSION=2.4.2 From 9378016b19521aa6c281f475267c5cb67ea967d1 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 8 Feb 2019 21:34:08 +0000 Subject: [PATCH 231/254] Fix build failure when using WITH_ADNS=yes --- ChangeLog.txt | 7 +++++++ src/bridge.c | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 322a23a15c..b6dd793f42 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,10 @@ +1.5.7 - 201902xx +================ + +Broker: +- Fix build failure when using WITH_ADNS=yes + + 1.5.6 - 20190206 ================ diff --git a/src/bridge.c b/src/bridge.c index 6e4b94fa6c..d9611f0d47 100644 --- a/src/bridge.c +++ b/src/bridge.c @@ -228,7 +228,7 @@ int bridge__connect_step3(struct mosquitto_db *db, struct mosquitto *context) { int rc; - rc = net__socket_connect_step3(context, context->bridge->addresses[context->bridge->cur_address].address, context->bridge->addresses[context->bridge->cur_address].port, NULL, false); + rc = net__socket_connect_step3(context, context->bridge->addresses[context->bridge->cur_address].address); if(rc > 0){ if(rc == MOSQ_ERR_TLS){ net__socket_close(db, context); From 2e1c2c430fe88344fc69fb1aefeee584a891baa6 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 8 Feb 2019 22:47:25 +0000 Subject: [PATCH 232/254] `per_listener_settings true` must come before other security settings. Produce error if this is not the case. Closes #1164, thanks to momoskitto. --- ChangeLog.txt | 2 ++ src/conf.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index b6dd793f42..c5516f1acd 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -3,6 +3,8 @@ Broker: - Fix build failure when using WITH_ADNS=yes +- Ensure that an error occurs if `per_listener_settings true` is given after + other security options. Closes #1149. 1.5.6 - 20190206 diff --git a/src/conf.c b/src/conf.c index 14d3528442..0e822c9519 100644 --- a/src/conf.c +++ b/src/conf.c @@ -62,6 +62,8 @@ struct config_recurse { extern SERVICE_STATUS_HANDLE service_handle; #endif +static struct mosquitto__security_options *cur_security_options = NULL; + static int conf__parse_bool(char **token, const char *name, bool *value, char *saveptr); static int conf__parse_int(char **token, const char *name, int *value, char *saveptr); static int conf__parse_ssize_t(char **token, const char *name, ssize_t *value, char *saveptr); @@ -743,7 +745,6 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct struct mosquitto__listener *cur_listener = &config->default_listener; int i; int lineno_ext; - struct mosquitto__security_options *cur_security_options = NULL; *lineno = 0; From 715da2860252a83207db0f99a425b7f491836381 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 8 Feb 2019 23:52:11 +0000 Subject: [PATCH 233/254] Fix include_dir not sorting config files before loading. Thanks to momoskitto. --- ChangeLog.txt | 2 ++ src/conf.c | 78 +++++++++---------------------------------- src/conf_includedir.c | 13 ++++++-- 3 files changed, 27 insertions(+), 66 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index c5516f1acd..e64cf37c43 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -5,6 +5,8 @@ Broker: - Fix build failure when using WITH_ADNS=yes - Ensure that an error occurs if `per_listener_settings true` is given after other security options. Closes #1149. +- Fix include_dir not sorting config files before loading. This was partially + fixed in 1.5 previously. 1.5.6 - 20190206 diff --git a/src/conf.c b/src/conf.c index 0e822c9519..aea01f0d11 100644 --- a/src/conf.c +++ b/src/conf.c @@ -732,15 +732,6 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct time_t expiration_mult; char *key; - char *conf_file; -#ifdef WIN32 - HANDLE fh; - char dirpath[MAX_PATH]; - WIN32_FIND_DATA find_data; -#else - DIR *dh; - struct dirent *de; -#endif int len; struct mosquitto__listener *cur_listener = &config->default_listener; int i; @@ -1219,66 +1210,27 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct log__printf(NULL, MOSQ_LOG_ERR, "Error: Empty include_dir value in configuration."); return 1; } -#ifdef WIN32 - snprintf(dirpath, MAX_PATH, "%s\\*.conf", token); - fh = FindFirstFile(dirpath, &find_data); - if(fh == INVALID_HANDLE_VALUE){ - /* No files found */ - continue; - } - do{ - len = strlen(token)+1+strlen(find_data.cFileName)+1; - conf_file = mosquitto__malloc(len+1); - if(!conf_file){ - FindClose(fh); - return MOSQ_ERR_NOMEM; - } - snprintf(conf_file, len, "%s\\%s", token, find_data.cFileName); - conf_file[len] = '\0'; + char **files; + int file_count; + rc = config__get_dir_files(token, &files, &file_count); + if(rc) return rc; - rc = config__read_file(config, reload, conf_file, cr, level+1, &lineno_ext); + for(i=0; id_name) > 5){ - if(!strcmp(&de->d_name[strlen(de->d_name)-5], ".conf")){ - len = strlen(token)+1+strlen(de->d_name)+1; - conf_file = mosquitto__malloc(len+1); - if(!conf_file){ - closedir(dh); - return MOSQ_ERR_NOMEM; - } - snprintf(conf_file, len, "%s/%s", token, de->d_name); - conf_file[len] = '\0'; - - rc = config__read_file(config, reload, conf_file, cr, level+1, &lineno_ext); - if(rc){ - closedir(dh); - log__printf(NULL, MOSQ_LOG_ERR, "Error found at %s:%d.", conf_file, lineno_ext); - mosquitto__free(conf_file); - return rc; - } - mosquitto__free(conf_file); - } - } + for(i=0; i Date: Sat, 9 Feb 2019 13:52:09 +0000 Subject: [PATCH 234/254] Don't require C99 compiler. --- ChangeLog.txt | 3 +++ src/persist.c | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index e64cf37c43..cbe6ae2c19 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -8,6 +8,9 @@ Broker: - Fix include_dir not sorting config files before loading. This was partially fixed in 1.5 previously. +Build: +- Don't require C99 compiler. + 1.5.6 - 20190206 ================ diff --git a/src/persist.c b/src/persist.c index 2f40086925..13b34d2cd3 100644 --- a/src/persist.c +++ b/src/persist.c @@ -720,6 +720,7 @@ static int persist__msg_store_chunk_restore(struct mosquitto_db *db, FILE *db_fp struct mosquitto_msg_store *stored = NULL; struct mosquitto_msg_store_load *load; char *err; + int i; payload.ptr = NULL; @@ -749,7 +750,7 @@ static int persist__msg_store_chunk_restore(struct mosquitto_db *db, FILE *db_fp read_e(db_fptr, &i16temp, sizeof(uint16_t)); source_port = ntohs(i16temp); if(source_port){ - for(int i=0; iconfig->listener_count; i++){ + for(i=0; iconfig->listener_count; i++){ if(db->config->listeners[i].port == source_port){ source.listener = &db->config->listeners[i]; break; From e72d1d6ff5ba2ee6b43273c52c7c9616d73d6726 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 12 Feb 2019 11:26:23 +0000 Subject: [PATCH 235/254] Fix `mosquitto_topic_matches_sub()` rc with sub=="topic/#abc". This now returns MOSQ_ERR_INVAL as expected. --- ChangeLog.txt | 5 +++++ lib/util_mosq.c | 9 ++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index cbe6ae2c19..dcd4a96590 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -8,6 +8,11 @@ Broker: - Fix include_dir not sorting config files before loading. This was partially fixed in 1.5 previously. +Library: +- Fix `mosquitto_topic_matches_sub()` not returning MOSQ_ERR_INVAL for + invalid subscriptions like `topic/#abc`. This only affects the return value, + not the match/no match result, which was already correct. + Build: - Don't require C99 compiler. diff --git a/lib/util_mosq.c b/lib/util_mosq.c index 4caed72b1a..ee1ddf07d7 100644 --- a/lib/util_mosq.c +++ b/lib/util_mosq.c @@ -245,6 +245,7 @@ int mosquitto_topic_matches_sub2(const char *sub, size_t sublen, const char *top { int spos, tpos; bool multilevel_wildcard = false; + int i; if(!result) return MOSQ_ERR_INVAL; *result = false; @@ -270,7 +271,7 @@ int mosquitto_topic_matches_sub2(const char *sub, size_t sublen, const char *top tpos = 0; while(spos < sublen && tpos <= topiclen){ - if(sub[spos] == topic[tpos]){ + if(tpos == topiclen || sub[spos] == topic[tpos]){ if(tpos == topiclen-1){ /* Check for e.g. foo matching foo/# */ if(spos == sublen-3 @@ -336,6 +337,12 @@ int mosquitto_topic_matches_sub2(const char *sub, size_t sublen, const char *top multilevel_wildcard = true; return MOSQ_ERR_SUCCESS; } + + for(i=spos; i Date: Tue, 12 Feb 2019 10:52:54 +0000 Subject: [PATCH 236/254] Fix property write test after function changes. --- test/unit/property_write.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/unit/property_write.c b/test/unit/property_write.c index c689ba75a2..7a4a3d04a1 100644 --- a/test/unit/property_write.c +++ b/test/unit/property_write.c @@ -27,7 +27,7 @@ static void byte_prop_write_helper( packet.packet_length = packet.remaining_length+10; packet.payload = calloc(packet.remaining_length+10, 1); - property__write_all(&packet, &property); + property__write_all(&packet, &property, true); packet.pos = 0; rc = property__read_all(command, &packet, &properties); @@ -68,7 +68,7 @@ static void int32_prop_write_helper( packet.packet_length = packet.remaining_length+10; packet.payload = calloc(packet.remaining_length+10, 1); - property__write_all(&packet, &property); + property__write_all(&packet, &property, true); packet.pos = 0; rc = property__read_all(command, &packet, &properties); @@ -109,7 +109,7 @@ static void int16_prop_write_helper( packet.packet_length = packet.remaining_length+10; packet.payload = calloc(packet.remaining_length+10, 1); - property__write_all(&packet, &property); + property__write_all(&packet, &property, true); packet.pos = 0; rc = property__read_all(command, &packet, &properties); @@ -150,7 +150,7 @@ static void string_prop_write_helper( packet.packet_length = packet.remaining_length+10; packet.payload = calloc(packet.remaining_length+10, 1); - property__write_all(&packet, &property); + property__write_all(&packet, &property, true); packet.pos = 0; rc = property__read_all(command, &packet, &properties); @@ -196,7 +196,7 @@ static void binary_prop_write_helper( packet.packet_length = packet.remaining_length+10; packet.payload = calloc(packet.remaining_length+10, 1); - property__write_all(&packet, &property); + property__write_all(&packet, &property, true); packet.pos = 0; rc = property__read_all(command, &packet, &properties); @@ -242,7 +242,7 @@ static void string_pair_prop_write_helper( packet.packet_length = packet.remaining_length+10; packet.payload = calloc(packet.remaining_length+10, 1); - property__write_all(&packet, &property); + property__write_all(&packet, &property, true); packet.pos = 0; rc = property__read_all(CMD_CONNECT, &packet, &properties); @@ -290,7 +290,7 @@ static void varint_prop_write_helper( packet.packet_length = packet.remaining_length+10; packet.payload = calloc(packet.remaining_length+10, 1); - property__write_all(&packet, &property); + property__write_all(&packet, &property, true); packet.pos = 0; rc = property__read_all(CMD_PUBLISH, &packet, &properties); @@ -334,7 +334,7 @@ static void TEST_bad_identifier(void) packet.packet_length = 10; packet.remaining_length = 8; packet.payload = payload; - rc = property__write_all(&packet, &property); + rc = property__write_all(&packet, &property, true); CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL); } From bb914b985cfe2d1ef00ad7b76e2eea4f068478a3 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 12 Feb 2019 11:28:53 +0000 Subject: [PATCH 237/254] Fix `mosquitto_topic_matches_sub()` rc with sub=="topic/#abc". This now returns MOSQ_ERR_INVAL as expected. --- lib/util_topic.c | 15 +++++++++++++-- test/unit/util_topic_test.c | 6 +++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/util_topic.c b/lib/util_topic.c index 45a2d311db..18fbceb1a1 100644 --- a/lib/util_topic.c +++ b/lib/util_topic.c @@ -179,7 +179,7 @@ int mosquitto_topic_matches_sub2(const char *sub, size_t sublen, const char *top if(topic[tpos] == '+' || topic[tpos] == '#'){ return MOSQ_ERR_INVAL; } - if(sub[spos] != topic[tpos]){ + if(tpos == topiclen || sub[spos] != topic[tpos]){ /* Check for wildcard matches */ if(sub[spos] == '+'){ /* Check for bad "+foo" or "a/+foo" subscription */ if(spos > 0 && sub[spos-1] != '/'){ @@ -198,10 +198,11 @@ int mosquitto_topic_matches_sub2(const char *sub, size_t sublen, const char *top return MOSQ_ERR_SUCCESS; } }else if(sub[spos] == '#'){ + /* Check for bad "foo#" subscription */ if(spos > 0 && sub[spos-1] != '/'){ return MOSQ_ERR_INVAL; } - multilevel_wildcard = true; + /* Check for # not the final character of the sub, e.g. "#foo" */ if(spos+1 != sublen){ return MOSQ_ERR_INVAL; }else{ @@ -221,9 +222,19 @@ int mosquitto_topic_matches_sub2(const char *sub, size_t sublen, const char *top multilevel_wildcard = true; return MOSQ_ERR_SUCCESS; } + + /* There is no match at this point, but is the sub invalid? */ + for(int i=spos; i Date: Tue, 12 Feb 2019 11:34:13 +0000 Subject: [PATCH 238/254] Fix datatype_read test. --- lib/packet_datatypes.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/packet_datatypes.c b/lib/packet_datatypes.c index 41dd9d942d..335cb9f02d 100644 --- a/lib/packet_datatypes.c +++ b/lib/packet_datatypes.c @@ -130,6 +130,7 @@ int packet__read_string(struct mosquitto__packet *packet, char **str, int *lengt if(mosquitto_validate_utf8(*str, *length)){ mosquitto__free(*str); *str = NULL; + *length = -1; return MOSQ_ERR_MALFORMED_UTF8; } From e2f269bda83c903ef8f54c6a0dde892a32cdb344 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 12 Feb 2019 17:12:38 +0000 Subject: [PATCH 239/254] Test duration printing on ptest. --- test/broker/ptest.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/broker/ptest.py b/test/broker/ptest.py index 52b4bd6032..b6b766fb62 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -156,6 +156,7 @@ def next_test(tests, ports): if test[0] == 1: port = ports.pop() p = subprocess.Popen([test[1], str(port)]) + p.start_time = time.time() p.mosq_port = port return p elif test[0] == 2: @@ -167,6 +168,7 @@ def next_test(tests, ports): port2 = ports.pop() p = subprocess.Popen([test[1], str(port1), str(port2)]) + p.start_time = time.time() p.mosq_port = (port1, port2) return p elif test[0] == 3: @@ -179,6 +181,7 @@ def next_test(tests, ports): port3 = ports.pop() p = subprocess.Popen([test[1], str(port1), str(port2), str(port3)]) + p.start_time = time.time() p.mosq_port = (port1, port2, port3) return p else: @@ -211,16 +214,21 @@ def run_tests(tests, ports): ports.append(t.mosq_port) t.terminate() t.wait() + runtime = time.time() - t.start_time #(stdo, stde) = t.communicate() if t.returncode == 1: - print("\033[31m" + t.args[0] + "\033[0m") + print("%0.3fs : \033[31m%s\033[0m" % (runtime, t.args[0])) failed = failed + 1 + failed_tests.append(t.args[0]) else: passed = passed + 1 - print("\033[32m" + t.args[0] + "\033[0m") + print("%0.3fs : \033[32m%s\033[0m" % (runtime, t.args[0])) print("Passed: %d\nFailed: %d\nTotal: %d" % (passed, failed, passed+failed)) if failed > 0: + print("Failing tests:") + for f in failed_tests: + print(f) sys.exit(1) From 016ce7dca53e7a6b13f2739406b6a7fba4d88b94 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 12 Feb 2019 18:28:54 +0000 Subject: [PATCH 240/254] Simplify ptest implementation. --- test/broker/ptest.py | 48 +++++++++++++++----------------------------- 1 file changed, 16 insertions(+), 32 deletions(-) diff --git a/test/broker/ptest.py b/test/broker/ptest.py index b6b766fb62..df029c1e30 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -153,39 +153,23 @@ def next_test(tests, ports): return test = tests.pop() - if test[0] == 1: - port = ports.pop() - p = subprocess.Popen([test[1], str(port)]) - p.start_time = time.time() - p.mosq_port = port - return p - elif test[0] == 2: - if len(ports) < 2: - tests.insert(0,test) - return None - else: - port1 = ports.pop() - port2 = ports.pop() - - p = subprocess.Popen([test[1], str(port1), str(port2)]) - p.start_time = time.time() - p.mosq_port = (port1, port2) - return p - elif test[0] == 3: - if len(ports) < 3: - tests.insert(0,test) - return None - else: - port1 = ports.pop() - port2 = ports.pop() - port3 = ports.pop() - - p = subprocess.Popen([test[1], str(port1), str(port2), str(port3)]) - p.start_time = time.time() - p.mosq_port = (port1, port2, port3) - return p - else: + proc_ports = () + + if len(ports) < test[0]: + tests.insert(0, test) return None + else: + args = [test[1]] + + for i in range(0, test[0]): + proc_port = ports.pop() + proc_ports = proc_ports + (proc_port,) + args.append(str(proc_port)) + + proc = subprocess.Popen(args) + proc.start_time = time.time() + proc.mosq_port = proc_ports + return proc def run_tests(tests, ports): From 950ad8d16f66f083fb93bac53eaede51aa855284 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 12 Feb 2019 18:29:05 +0000 Subject: [PATCH 241/254] Speed up pattern matching test. --- test/broker/03-pattern-matching.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/broker/03-pattern-matching.py b/test/broker/03-pattern-matching.py index 31d43edd19..66ff2ef28b 100755 --- a/test/broker/03-pattern-matching.py +++ b/test/broker/03-pattern-matching.py @@ -20,11 +20,9 @@ def pattern_test(sub_topic, pub_topic): unsuback_packet = mosq_test.gen_unsuback(mid) port = mosq_test.get_port() - broker = subprocess.Popen(['../../src/mosquitto', '-p', str(port)], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port) try: - time.sleep(0.5) - sock = mosq_test.do_client_connect(connect_packet, connack_packet, timeout=20, port=port) mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback") @@ -48,7 +46,7 @@ def pattern_test(sub_topic, pub_topic): if rc: print(stde) print(stdo) - raise + sys.exit(rc) return rc From b4a94f59009944c90e60c64df8f7d200d86dbb81 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 12 Feb 2019 18:51:19 +0000 Subject: [PATCH 242/254] Fix some ssl tests. --- test/broker/08-ssl-connect-cert-auth-expired.py | 2 +- test/broker/08-ssl-connect-cert-auth-revoked.py | 2 +- test/broker/08-ssl-connect-cert-auth-without.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/broker/08-ssl-connect-cert-auth-expired.py b/test/broker/08-ssl-connect-cert-auth-expired.py index bfa5bc11c7..836a9b8257 100755 --- a/test/broker/08-ssl-connect-cert-auth-expired.py +++ b/test/broker/08-ssl-connect-cert-auth-expired.py @@ -26,7 +26,6 @@ def write_config(filename, port1, port2): rc = 1 keepalive = 10 connect_packet = mosq_test.gen_connect("connect-success-test", keepalive=keepalive) -connack_packet = mosq_test.gen_connack(rc=0) broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port2, use_conf=True) @@ -36,6 +35,7 @@ def write_config(filename, port1, port2): ssock.settimeout(20) try: ssock.connect(("localhost", port1)) + mosq_test.do_send_receive(ssock, connect_packet, "", "connack") except ssl.SSLError as err: if err.errno == 1: rc = 0 diff --git a/test/broker/08-ssl-connect-cert-auth-revoked.py b/test/broker/08-ssl-connect-cert-auth-revoked.py index 60d08305d0..97b8f432c5 100755 --- a/test/broker/08-ssl-connect-cert-auth-revoked.py +++ b/test/broker/08-ssl-connect-cert-auth-revoked.py @@ -23,7 +23,6 @@ def write_config(filename, port1, port2): rc = 1 keepalive = 10 connect_packet = mosq_test.gen_connect("connect-revoked-test", keepalive=keepalive) -connack_packet = mosq_test.gen_connack(rc=0) broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port2, use_conf=True) @@ -33,6 +32,7 @@ def write_config(filename, port1, port2): ssock.settimeout(20) try: ssock.connect(("localhost", port1)) + mosq_test.do_send_receive(ssock, connect_packet, "", "connack") except ssl.SSLError as err: if err.errno == 1 and "certificate revoked" in err.strerror: rc = 0 diff --git a/test/broker/08-ssl-connect-cert-auth-without.py b/test/broker/08-ssl-connect-cert-auth-without.py index 7df9a3b2c9..f31141e70d 100755 --- a/test/broker/08-ssl-connect-cert-auth-without.py +++ b/test/broker/08-ssl-connect-cert-auth-without.py @@ -24,7 +24,6 @@ def write_config(filename, port1, port2): rc = 1 keepalive = 10 connect_packet = mosq_test.gen_connect("connect-cert-test", keepalive=keepalive) -connack_packet = mosq_test.gen_connack(rc=0) broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port2, use_conf=True) @@ -33,6 +32,7 @@ def write_config(filename, port1, port2): ssock.settimeout(20) try: ssock.connect(("localhost", port1)) + mosq_test.do_send_receive(ssock, connect_packet, "", "connack") except ssl.SSLError as err: if err.errno == 1: rc = 0 From baa4642bd3fb748924858c4e70c0badf2c0fb848 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 12 Feb 2019 19:06:14 +0000 Subject: [PATCH 243/254] Generic ptest implementation. --- test/broker/Makefile | 2 +- test/broker/{ptest.py => test.py} | 79 +------------------ test/lib/Makefile | 2 +- test/lib/ptest.py | 124 ------------------------------ test/lib/test.py | 71 +++++++++++++++++ test/ptest.py | 78 +++++++++++++++++++ 6 files changed, 154 insertions(+), 202 deletions(-) rename test/broker/{ptest.py => test.py} (71%) delete mode 100755 test/lib/ptest.py create mode 100755 test/lib/test.py create mode 100755 test/ptest.py diff --git a/test/broker/Makefile b/test/broker/Makefile index 76448dfe13..2847332571 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -13,7 +13,7 @@ test-compile : $(MAKE) -C c ptest : test-compile - ./ptest.py + ./test.py test : test-compile 01 02 03 04 05 06 07 08 09 10 11 12 diff --git a/test/broker/ptest.py b/test/broker/test.py similarity index 71% rename from test/broker/ptest.py rename to test/broker/test.py index df029c1e30..200cf55be0 100755 --- a/test/broker/ptest.py +++ b/test/broker/test.py @@ -1,10 +1,8 @@ #!/usr/bin/env python3 -import subprocess -import time -import sys +import mosq_test_helper +import ptest -max_running = 10 tests = [ #(ports required, 'path'), (1, './01-connect-bad-packet.py'), @@ -145,75 +143,4 @@ (1, './12-prop-response-topic-correlation-data.py'), ] -minport = 1888 -ports = list(range(minport, minport+max_running+1)) - -def next_test(tests, ports): - if len(tests) == 0 or len(ports) == 0: - return - - test = tests.pop() - proc_ports = () - - if len(ports) < test[0]: - tests.insert(0, test) - return None - else: - args = [test[1]] - - for i in range(0, test[0]): - proc_port = ports.pop() - proc_ports = proc_ports + (proc_port,) - args.append(str(proc_port)) - - proc = subprocess.Popen(args) - proc.start_time = time.time() - proc.mosq_port = proc_ports - return proc - - -def run_tests(tests, ports): - passed = 0 - failed = 0 - - failed_tests = [] - - running_tests = [] - while len(tests) > 0 or len(running_tests) > 0: - if len(running_tests) <= max_running: - t = next_test(tests, ports) - if t is None: - time.sleep(0.1) - else: - running_tests.append(t) - - for t in running_tests: - t.poll() - if t.returncode is not None: - running_tests.remove(t) - if isinstance(t.mosq_port, tuple): - for portret in t.mosq_port: - ports.append(portret) - else: - ports.append(t.mosq_port) - t.terminate() - t.wait() - runtime = time.time() - t.start_time - #(stdo, stde) = t.communicate() - if t.returncode == 1: - print("%0.3fs : \033[31m%s\033[0m" % (runtime, t.args[0])) - failed = failed + 1 - failed_tests.append(t.args[0]) - else: - passed = passed + 1 - print("%0.3fs : \033[32m%s\033[0m" % (runtime, t.args[0])) - - print("Passed: %d\nFailed: %d\nTotal: %d" % (passed, failed, passed+failed)) - if failed > 0: - print("Failing tests:") - for f in failed_tests: - print(f) - sys.exit(1) - - -run_tests(tests, ports) +ptest.run_tests(tests) diff --git a/test/lib/Makefile b/test/lib/Makefile index 49f3088b87..d88f58a1df 100644 --- a/test/lib/Makefile +++ b/test/lib/Makefile @@ -8,7 +8,7 @@ LD_LIBRARY_PATH=../../lib all : ptest : test-compile - ./ptest.py + ./test.py test : c cpp diff --git a/test/lib/ptest.py b/test/lib/ptest.py deleted file mode 100755 index c12142a111..0000000000 --- a/test/lib/ptest.py +++ /dev/null @@ -1,124 +0,0 @@ -#!/usr/bin/env python3 - -import subprocess -import time -import sys - -max_running = 10 -tests = [ - ('./01-con-discon-success.py', 'c/01-con-discon-success.test'), - ('./01-keepalive-pingreq.py', 'c/01-keepalive-pingreq.test'), - ('./01-server-keepalive-pingreq.py', 'c/01-server-keepalive-pingreq.test'), - ('./01-no-clean-session.py', 'c/01-no-clean-session.test'), - ('./01-unpwd-set.py', 'c/01-unpwd-set.test'), - ('./01-will-set.py', 'c/01-will-set.test'), - ('./01-will-unpwd-set.py', 'c/01-will-unpwd-set.test'), - ('./02-subscribe-qos0.py', 'c/02-subscribe-qos0.test'), - ('./02-subscribe-qos1.py', 'c/02-subscribe-qos1.test'), - ('./02-subscribe-qos2.py', 'c/02-subscribe-qos2.test'), - ('./02-unsubscribe.py', 'c/02-unsubscribe.test'), - ('./03-publish-b2c-qos1.py', 'c/03-publish-b2c-qos1.test'), - ('./03-publish-b2c-qos2.py', 'c/03-publish-b2c-qos2.test'), - ('./03-publish-c2b-qos1-len.py', 'c/03-publish-c2b-qos1-len.test'), - ('./03-publish-c2b-qos2-len.py', 'c/03-publish-c2b-qos2-len.test'), - ('./03-publish-b2c-qos2-len.py', 'c/03-publish-b2c-qos2-len.test'), - ('./03-publish-c2b-qos1-disconnect.py', 'c/03-publish-c2b-qos1-disconnect.test'), - ('./03-publish-c2b-qos2-disconnect.py', 'c/03-publish-c2b-qos2-disconnect.test'), - ('./03-publish-c2b-qos2.py', 'c/03-publish-c2b-qos2.test'), - ('./03-publish-c2b-qos1-receive-maximum.py', 'c/03-publish-c2b-qos1-receive-maximum.test'), - ('./03-publish-c2b-qos2-receive-maximum-1.py', 'c/03-publish-c2b-qos2-receive-maximum-1.test'), - ('./03-publish-c2b-qos2-receive-maximum-2.py', 'c/03-publish-c2b-qos2-receive-maximum-2.test'), - ('./03-publish-c2b-qos2-pubrec-error.py', 'c/03-publish-c2b-qos2-pubrec-error.test'), - ('./03-publish-c2b-qos2-maximum-qos-0.py', 'c/03-publish-c2b-qos2-maximum-qos-0.test'), - ('./03-publish-c2b-qos2-maximum-qos-1.py', 'c/03-publish-c2b-qos2-maximum-qos-1.test'), - ('./03-publish-qos0-no-payload.py', 'c/03-publish-qos0-no-payload.test'), - ('./03-publish-qos0.py', 'c/03-publish-qos0.test'), - ('./03-request-response.py', 'c/03-request-response.test'), - ('./03-request-response-correlation.py', 'c/03-request-response-correlation.test'), - ('./04-retain-qos0.py', 'c/04-retain-qos0.test'), - ('./08-ssl-bad-cacert.py', 'c/08-ssl-bad-cacert.test'), - ('./08-ssl-connect-cert-auth-enc.py', 'c/08-ssl-connect-cert-auth-enc.test'), - ('./08-ssl-connect-cert-auth.py', 'c/08-ssl-connect-cert-auth.test'), - ('./08-ssl-connect-no-auth.py', 'c/08-ssl-connect-no-auth.test'), - ('./09-util-topic-tokenise.py', 'c/09-util-topic-tokenise.test'), - ('./11-prop-send-payload-format.py', 'c/11-prop-send-payload-format.test'), - ('./11-prop-send-content-type.py', 'c/11-prop-send-content-type.test'), - - ('./01-con-discon-success.py', 'cpp/01-con-discon-success.test'), - ('./01-keepalive-pingreq.py', 'cpp/01-keepalive-pingreq.test'), - ('./01-no-clean-session.py', 'cpp/01-no-clean-session.test'), - ('./01-unpwd-set.py', 'cpp/01-unpwd-set.test'), - ('./01-will-set.py', 'cpp/01-will-set.test'), - ('./01-will-unpwd-set.py', 'cpp/01-will-unpwd-set.test'), - ('./02-subscribe-qos0.py', 'cpp/02-subscribe-qos0.test'), - ('./02-subscribe-qos1.py', 'cpp/02-subscribe-qos1.test'), - ('./02-subscribe-qos2.py', 'cpp/02-subscribe-qos2.test'), - ('./02-unsubscribe.py', 'cpp/02-unsubscribe.test'), - ('./03-publish-b2c-qos1.py', 'cpp/03-publish-b2c-qos1.test'), - ('./03-publish-b2c-qos2.py', 'cpp/03-publish-b2c-qos2.test'), - ('./03-publish-c2b-qos1-disconnect.py', 'cpp/03-publish-c2b-qos1-disconnect.test'), - ('./03-publish-c2b-qos2-disconnect.py', 'cpp/03-publish-c2b-qos2-disconnect.test'), - ('./03-publish-c2b-qos2.py', 'cpp/03-publish-c2b-qos2.test'), - ('./03-publish-qos0-no-payload.py', 'cpp/03-publish-qos0-no-payload.test'), - ('./03-publish-qos0.py', 'cpp/03-publish-qos0.test'), - ('./04-retain-qos0.py', 'cpp/04-retain-qos0.test'), - ('./08-ssl-bad-cacert.py', 'cpp/08-ssl-bad-cacert.test'), - ('./08-ssl-connect-cert-auth-enc.py', 'cpp/08-ssl-connect-cert-auth-enc.test'), - ('./08-ssl-connect-cert-auth.py', 'cpp/08-ssl-connect-cert-auth.test'), - ('./08-ssl-connect-no-auth.py', 'cpp/08-ssl-connect-no-auth.test'), - ('./09-util-topic-tokenise.py', 'cpp/09-util-topic-tokenise.test'), - ] - -minport = 1888 -ports = list(range(minport, minport+max_running+1)) - -def next_test(tests, ports): - if len(tests) == 0 or len(ports) == 0: - return - - test = tests.pop() - port = ports.pop() - p = subprocess.Popen([test[0], test[1], str(port)]) - p.mosq_port = port - return p - -def run_tests(tests, ports): - passed = 0 - failed = 0 - - failed_tests = [] - - running_tests = [] - while len(tests) > 0 or len(running_tests) > 0: - if len(running_tests) <= max_running: - t = next_test(tests, ports) - if t is None: - time.sleep(0.1) - else: - running_tests.append(t) - - for t in running_tests: - t.poll() - if t.returncode is not None: - running_tests.remove(t) - if isinstance(t.mosq_port, tuple): - for portret in t.mosq_port: - ports.append(portret) - else: - ports.append(t.mosq_port) - t.terminate() - t.wait() - #(stdo, stde) = t.communicate() - if t.returncode == 1: - print("\033[31m %s %s\033[0m" % (t.args[0], t.args[1])) - failed = failed + 1 - else: - passed = passed + 1 - print("\033[32m %s %s\033[0m" % (t.args[0], t.args[1])) - - print("Passed: %d\nFailed: %d\nTotal: %d" % (passed, failed, passed+failed)) - if failed > 0: - sys.exit(1) - - -run_tests(tests, ports) diff --git a/test/lib/test.py b/test/lib/test.py new file mode 100755 index 0000000000..76d7dc0d4d --- /dev/null +++ b/test/lib/test.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 + +import mosq_test_helper +import ptest + +tests = [ + (1, ['./01-con-discon-success.py', 'c/01-con-discon-success.test']), + (1, ['./01-keepalive-pingreq.py', 'c/01-keepalive-pingreq.test']), + (1, ['./01-server-keepalive-pingreq.py', 'c/01-server-keepalive-pingreq.test']), + (1, ['./01-no-clean-session.py', 'c/01-no-clean-session.test']), + (1, ['./01-unpwd-set.py', 'c/01-unpwd-set.test']), + (1, ['./01-will-set.py', 'c/01-will-set.test']), + (1, ['./01-will-unpwd-set.py', 'c/01-will-unpwd-set.test']), + (1, ['./02-subscribe-qos0.py', 'c/02-subscribe-qos0.test']), + (1, ['./02-subscribe-qos1.py', 'c/02-subscribe-qos1.test']), + (1, ['./02-subscribe-qos2.py', 'c/02-subscribe-qos2.test']), + (1, ['./02-unsubscribe.py', 'c/02-unsubscribe.test']), + (1, ['./03-publish-b2c-qos1.py', 'c/03-publish-b2c-qos1.test']), + (1, ['./03-publish-b2c-qos2.py', 'c/03-publish-b2c-qos2.test']), + (1, ['./03-publish-c2b-qos1-len.py', 'c/03-publish-c2b-qos1-len.test']), + (1, ['./03-publish-c2b-qos2-len.py', 'c/03-publish-c2b-qos2-len.test']), + (1, ['./03-publish-b2c-qos2-len.py', 'c/03-publish-b2c-qos2-len.test']), + (1, ['./03-publish-c2b-qos1-disconnect.py', 'c/03-publish-c2b-qos1-disconnect.test']), + (1, ['./03-publish-c2b-qos2-disconnect.py', 'c/03-publish-c2b-qos2-disconnect.test']), + (1, ['./03-publish-c2b-qos2.py', 'c/03-publish-c2b-qos2.test']), + (1, ['./03-publish-c2b-qos1-receive-maximum.py', 'c/03-publish-c2b-qos1-receive-maximum.test']), + (1, ['./03-publish-c2b-qos2-receive-maximum-1.py', 'c/03-publish-c2b-qos2-receive-maximum-1.test']), + (1, ['./03-publish-c2b-qos2-receive-maximum-2.py', 'c/03-publish-c2b-qos2-receive-maximum-2.test']), + (1, ['./03-publish-c2b-qos2-pubrec-error.py', 'c/03-publish-c2b-qos2-pubrec-error.test']), + (1, ['./03-publish-c2b-qos2-maximum-qos-0.py', 'c/03-publish-c2b-qos2-maximum-qos-0.test']), + (1, ['./03-publish-c2b-qos2-maximum-qos-1.py', 'c/03-publish-c2b-qos2-maximum-qos-1.test']), + (1, ['./03-publish-qos0-no-payload.py', 'c/03-publish-qos0-no-payload.test']), + (1, ['./03-publish-qos0.py', 'c/03-publish-qos0.test']), + (1, ['./03-request-response.py', 'c/03-request-response.test']), + (1, ['./03-request-response-correlation.py', 'c/03-request-response-correlation.test']), + (1, ['./04-retain-qos0.py', 'c/04-retain-qos0.test']), + (1, ['./08-ssl-bad-cacert.py', 'c/08-ssl-bad-cacert.test']), + (1, ['./08-ssl-connect-cert-auth-enc.py', 'c/08-ssl-connect-cert-auth-enc.test']), + (1, ['./08-ssl-connect-cert-auth.py', 'c/08-ssl-connect-cert-auth.test']), + (1, ['./08-ssl-connect-no-auth.py', 'c/08-ssl-connect-no-auth.test']), + (1, ['./09-util-topic-tokenise.py', 'c/09-util-topic-tokenise.test']), + (1, ['./11-prop-send-payload-format.py', 'c/11-prop-send-payload-format.test']), + (1, ['./11-prop-send-content-type.py', 'c/11-prop-send-content-type.test']), + + (1, ['./01-con-discon-success.py', 'cpp/01-con-discon-success.test']), + (1, ['./01-keepalive-pingreq.py', 'cpp/01-keepalive-pingreq.test']), + (1, ['./01-no-clean-session.py', 'cpp/01-no-clean-session.test']), + (1, ['./01-unpwd-set.py', 'cpp/01-unpwd-set.test']), + (1, ['./01-will-set.py', 'cpp/01-will-set.test']), + (1, ['./01-will-unpwd-set.py', 'cpp/01-will-unpwd-set.test']), + (1, ['./02-subscribe-qos0.py', 'cpp/02-subscribe-qos0.test']), + (1, ['./02-subscribe-qos1.py', 'cpp/02-subscribe-qos1.test']), + (1, ['./02-subscribe-qos2.py', 'cpp/02-subscribe-qos2.test']), + (1, ['./02-unsubscribe.py', 'cpp/02-unsubscribe.test']), + (1, ['./03-publish-b2c-qos1.py', 'cpp/03-publish-b2c-qos1.test']), + (1, ['./03-publish-b2c-qos2.py', 'cpp/03-publish-b2c-qos2.test']), + (1, ['./03-publish-c2b-qos1-disconnect.py', 'cpp/03-publish-c2b-qos1-disconnect.test']), + (1, ['./03-publish-c2b-qos2-disconnect.py', 'cpp/03-publish-c2b-qos2-disconnect.test']), + (1, ['./03-publish-c2b-qos2.py', 'cpp/03-publish-c2b-qos2.test']), + (1, ['./03-publish-qos0-no-payload.py', 'cpp/03-publish-qos0-no-payload.test']), + (1, ['./03-publish-qos0.py', 'cpp/03-publish-qos0.test']), + (1, ['./04-retain-qos0.py', 'cpp/04-retain-qos0.test']), + (1, ['./08-ssl-bad-cacert.py', 'cpp/08-ssl-bad-cacert.test']), + (1, ['./08-ssl-connect-cert-auth-enc.py', 'cpp/08-ssl-connect-cert-auth-enc.test']), + (1, ['./08-ssl-connect-cert-auth.py', 'cpp/08-ssl-connect-cert-auth.test']), + (1, ['./08-ssl-connect-no-auth.py', 'cpp/08-ssl-connect-no-auth.test']), + (1, ['./09-util-topic-tokenise.py', 'cpp/09-util-topic-tokenise.test']), + ] + + +ptest.run_tests(tests) diff --git a/test/ptest.py b/test/ptest.py new file mode 100755 index 0000000000..233f609e2b --- /dev/null +++ b/test/ptest.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 + +import subprocess +import time +import sys + +def next_test(tests, ports): + if len(tests) == 0 or len(ports) == 0: + return + + test = tests.pop() + proc_ports = () + + if len(ports) < test[0]: + tests.insert(0, test) + return None + else: + if isinstance(test[1], (list,)): + args = test[1] + else: + args = [test[1]] + + for i in range(0, test[0]): + proc_port = ports.pop() + proc_ports = proc_ports + (proc_port,) + args.append(str(proc_port)) + + proc = subprocess.Popen(args) + proc.start_time = time.time() + proc.mosq_port = proc_ports + return proc + + +def run_tests(tests, minport=1888, max_running=20): + ports = list(range(minport, minport+max_running+1)) + start_time = time.time() + passed = 0 + failed = 0 + + failed_tests = [] + + running_tests = [] + while len(tests) > 0 or len(running_tests) > 0: + if len(running_tests) <= max_running: + t = next_test(tests, ports) + if t is None: + time.sleep(0.1) + else: + running_tests.append(t) + + for t in running_tests: + t.poll() + if t.returncode is not None: + running_tests.remove(t) + if isinstance(t.mosq_port, tuple): + for portret in t.mosq_port: + ports.append(portret) + else: + ports.append(t.mosq_port) + t.terminate() + t.wait() + runtime = time.time() - t.start_time + #(stdo, stde) = t.communicate() + if t.returncode == 1: + print("%0.3fs : \033[31m%s\033[0m" % (runtime, t.args[0])) + failed = failed + 1 + failed_tests.append(t.args[0]) + else: + passed = passed + 1 + print("%0.3fs : \033[32m%s\033[0m" % (runtime, t.args[0])) + + print("Passed: %d\nFailed: %d\nTotal: %d\nTotal time: %0.2f" % (passed, failed, passed+failed, time.time()-start_time)) + if failed > 0: + print("Failing tests:") + for f in failed_tests: + print(f) + sys.exit(1) + From 458a9840ad160fb815a8c53ef5f41e341f5f2554 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 14 Feb 2019 10:52:49 +0000 Subject: [PATCH 244/254] Bump version for test release. --- CMakeLists.txt | 2 +- config.mk | 2 +- installer/mosquitto.nsi | 2 +- installer/mosquitto64.nsi | 2 +- lib/mosquitto.h | 2 +- set-version.sh | 2 +- snap/snapcraft.yaml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d37dc207c0..ea6e073341 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ project(mosquitto) cmake_minimum_required(VERSION 2.8) # Only for version 3 and up. cmake_policy(SET CMP0042 NEW) -set (VERSION 1.5.6) +set (VERSION 1.5.90) add_definitions (-DCMAKE -DVERSION=\"${VERSION}\") diff --git a/config.mk b/config.mk index 39059ed778..cf4bef6261 100644 --- a/config.mk +++ b/config.mk @@ -104,7 +104,7 @@ WITH_COVERAGE:=no # Also bump lib/mosquitto.h, CMakeLists.txt, # installer/mosquitto.nsi, installer/mosquitto64.nsi -VERSION=1.5.6 +VERSION=1.5.90 # Client library SO version. Bump if incompatible API/ABI changes are made. SOVERSION=1 diff --git a/installer/mosquitto.nsi b/installer/mosquitto.nsi index bdcff77c8e..15c356f03c 100644 --- a/installer/mosquitto.nsi +++ b/installer/mosquitto.nsi @@ -9,7 +9,7 @@ !define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' Name "Eclipse Mosquitto" -!define VERSION 1.5.6 +!define VERSION 1.5.90 OutFile "mosquitto-${VERSION}-install-windows-x86.exe" InstallDir "$PROGRAMFILES\mosquitto" diff --git a/installer/mosquitto64.nsi b/installer/mosquitto64.nsi index 9368779de2..2da63198e5 100644 --- a/installer/mosquitto64.nsi +++ b/installer/mosquitto64.nsi @@ -9,7 +9,7 @@ !define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' Name "Eclipse Mosquitto" -!define VERSION 1.5.6 +!define VERSION 1.5.90 OutFile "mosquitto-${VERSION}-install-windows-x64.exe" !include "x64.nsh" diff --git a/lib/mosquitto.h b/lib/mosquitto.h index 1b3517cbd4..480937b5ee 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -48,7 +48,7 @@ extern "C" { #define LIBMOSQUITTO_MAJOR 1 #define LIBMOSQUITTO_MINOR 5 -#define LIBMOSQUITTO_REVISION 6 +#define LIBMOSQUITTO_REVISION 90 /* LIBMOSQUITTO_VERSION_NUMBER looks like 1002001 for e.g. version 1.2.1. */ #define LIBMOSQUITTO_VERSION_NUMBER (LIBMOSQUITTO_MAJOR*1000000+LIBMOSQUITTO_MINOR*1000+LIBMOSQUITTO_REVISION) diff --git a/set-version.sh b/set-version.sh index 69469c8859..5cb46a3c68 100755 --- a/set-version.sh +++ b/set-version.sh @@ -2,7 +2,7 @@ MAJOR=1 MINOR=5 -REVISION=6 +REVISION=90 sed -i "s/^VERSION=.*/VERSION=${MAJOR}.${MINOR}.${REVISION}/" config.mk diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 6eb584a18e..dced140beb 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,5 +1,5 @@ name: mosquitto -version: 1.5.6 +version: 1.5.90 summary: Eclipse Mosquitto MQTT broker description: This is a message broker that supports version 3.1 and 3.1.1 of the MQTT protocol. From 1ec0cea34af996d011d8726286bf6aff544090fb Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sun, 17 Feb 2019 09:30:06 +0000 Subject: [PATCH 245/254] Fix missing reason_code on v5 UNSUBACK. Closes #1167. Thanks to Christoph Krey. --- src/handle_unsubscribe.c | 62 +++++++++++++------ src/mosquitto_broker_internal.h | 2 +- src/send_unsuback.c | 5 +- .../broker/02-unsubscribe-qos2-multiple-v5.py | 34 ++++++++++ test/broker/Makefile | 1 + test/broker/test.py | 1 + test/mosq_test.py | 11 +++- 7 files changed, 91 insertions(+), 25 deletions(-) create mode 100755 test/broker/02-unsubscribe-qos2-multiple-v5.py diff --git a/src/handle_unsubscribe.c b/src/handle_unsubscribe.c index 6fb24e2d80..03d4025a99 100644 --- a/src/handle_unsubscribe.c +++ b/src/handle_unsubscribe.c @@ -31,6 +31,9 @@ int handle__unsubscribe(struct mosquitto_db *db, struct mosquitto *context) char *sub; int slen; int rc; + int reason_code_count = 0; + int reason_code_max; + uint8_t *reason_codes = NULL, *reason_tmp; mosquitto_property *properties = NULL; if(!context) return MOSQ_ERR_INVAL; @@ -57,32 +60,49 @@ int handle__unsubscribe(struct mosquitto_db *db, struct mosquitto *context) return MOSQ_ERR_PROTOCOL; } } + + reason_code_max = 10; + reason_codes = mosquitto__malloc(reason_code_max); + if(!reason_codes){ + return MOSQ_ERR_NOMEM; + } + while(context->in_packet.pos < context->in_packet.remaining_length){ sub = NULL; if(packet__read_string(&context->in_packet, &sub, &slen)){ return 1; } - if(sub){ - if(!slen){ - log__printf(NULL, MOSQ_LOG_INFO, - "Empty unsubscription string from %s, disconnecting.", - context->id); - mosquitto__free(sub); - return 1; - } - if(mosquitto_sub_topic_check(sub)){ - log__printf(NULL, MOSQ_LOG_INFO, - "Invalid unsubscription string from %s, disconnecting.", - context->id); - mosquitto__free(sub); - return 1; - } - - log__printf(NULL, MOSQ_LOG_DEBUG, "\t%s", sub); - sub__remove(db, context, sub, db->subs); - log__printf(NULL, MOSQ_LOG_UNSUBSCRIBE, "%s %s", context->id, sub); + if(!slen){ + log__printf(NULL, MOSQ_LOG_INFO, + "Empty unsubscription string from %s, disconnecting.", + context->id); mosquitto__free(sub); + return 1; + } + if(mosquitto_sub_topic_check(sub)){ + log__printf(NULL, MOSQ_LOG_INFO, + "Invalid unsubscription string from %s, disconnecting.", + context->id); + mosquitto__free(sub); + return 1; + } + + log__printf(NULL, MOSQ_LOG_DEBUG, "\t%s", sub); + sub__remove(db, context, sub, db->subs); + log__printf(NULL, MOSQ_LOG_UNSUBSCRIBE, "%s %s", context->id, sub); + mosquitto__free(sub); + + reason_codes[reason_code_count] = 0; + reason_code_count++; + if(reason_code_count == reason_code_max){ + reason_tmp = mosquitto__realloc(reason_codes, reason_code_max*2); + if(!reason_tmp){ + mosquitto__free(reason_codes); + return MOSQ_ERR_NOMEM; + } + reason_codes = reason_tmp; + reason_code_max *= 2; } } #ifdef WITH_PERSISTENCE @@ -92,6 +112,8 @@ int handle__unsubscribe(struct mosquitto_db *db, struct mosquitto *context) log__printf(NULL, MOSQ_LOG_DEBUG, "Sending UNSUBACK to %s", context->id); /* We don't use Reason String or User Property yet. */ - return send__unsuback(context, mid, NULL); + rc = send__unsuback(context, mid, reason_code_count, reason_codes, NULL); + mosquitto__free(reason_codes); + return rc; } diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index c998139095..3a2ac5179e 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -525,7 +525,7 @@ int restore_privileges(void); * ============================================================ */ int send__connack(struct mosquitto_db *db, struct mosquitto *context, int ack, int reason_code, const mosquitto_property *properties); int send__suback(struct mosquitto *context, uint16_t mid, uint32_t payloadlen, const void *payload); -int send__unsuback(struct mosquitto *context, uint16_t mid, const mosquitto_property *properties); +int send__unsuback(struct mosquitto *context, uint16_t mid, int reason_code_count, uint8_t *reason_codes, const mosquitto_property *properties); /* ============================================================ * Network functions diff --git a/src/send_unsuback.c b/src/send_unsuback.c index ee0c833395..9a310fac17 100644 --- a/src/send_unsuback.c +++ b/src/send_unsuback.c @@ -25,7 +25,7 @@ and the Eclipse Distribution License is available at #include "property_mosq.h" -int send__unsuback(struct mosquitto *mosq, uint16_t mid, const mosquitto_property *properties) +int send__unsuback(struct mosquitto *mosq, uint16_t mid, int reason_code_count, uint8_t *reason_codes, const mosquitto_property *properties) { struct mosquitto__packet *packet = NULL; int rc; @@ -41,7 +41,7 @@ int send__unsuback(struct mosquitto *mosq, uint16_t mid, const mosquitto_propert if(mosq->protocol == mosq_p_mqtt5){ proplen = property__get_length_all(properties); varbytes = packet__varint_bytes(proplen); - packet->remaining_length += varbytes + proplen; + packet->remaining_length += varbytes + proplen + reason_code_count; } rc = packet__alloc(packet); @@ -54,6 +54,7 @@ int send__unsuback(struct mosquitto *mosq, uint16_t mid, const mosquitto_propert if(mosq->protocol == mosq_p_mqtt5){ property__write_all(packet, properties, true); + packet__write_bytes(packet, reason_codes, reason_code_count); } return packet__queue(mosq, packet); diff --git a/test/broker/02-unsubscribe-qos2-multiple-v5.py b/test/broker/02-unsubscribe-qos2-multiple-v5.py new file mode 100755 index 0000000000..1e6c3f5344 --- /dev/null +++ b/test/broker/02-unsubscribe-qos2-multiple-v5.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python + +# Test whether a v5 UNSUBSCRIBE to multiple topics with QoS 2 results in the correct UNSUBACK packet. + +from mosq_test_helper import * + +rc = 1 +mid = 3 +keepalive = 60 +connect_packet = mosq_test.gen_connect("unsubscribe-qos2-test", keepalive=keepalive, proto_ver=5) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +unsubscribe_packet = mosq_test.gen_unsubscribe_multiple(mid, ["qos2/one", "qos2/two"], proto_ver=5) +unsuback_packet = mosq_test.gen_unsuback(mid, proto_ver=5, reason_code=[0, 0]) + +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, port=port) + mosq_test.do_send_receive(sock, unsubscribe_packet, unsuback_packet, "unsuback") + + rc = 0 + + sock.close() +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index 2847332571..3b5b6fe18d 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -76,6 +76,7 @@ endif ./02-unsubscribe-qos2-v5.py ./02-unsubscribe-invalid-no-topic.py ./02-unsubscribe-qos2-multiple.py + ./02-unsubscribe-qos2-multiple-v5.py ./02-subscribe-invalid-utf8.py ./02-subscribe-persistence-flipflop.py ./02-subhier-crash.py diff --git a/test/broker/test.py b/test/broker/test.py index 200cf55be0..526f58600c 100755 --- a/test/broker/test.py +++ b/test/broker/test.py @@ -57,6 +57,7 @@ (1, './02-unsubscribe-qos2-v5.py'), (1, './02-unsubscribe-invalid-no-topic.py'), (1, './02-unsubscribe-qos2-multiple.py'), + (1, './02-unsubscribe-qos2-multiple-v5.py'), (1, './02-subscribe-invalid-utf8.py'), (1, './02-subscribe-persistence-flipflop.py'), (1, './02-subhier-crash.py'), diff --git a/test/mosq_test.py b/test/mosq_test.py index e9da563f6f..bb5e9147b1 100644 --- a/test/mosq_test.py +++ b/test/mosq_test.py @@ -498,9 +498,16 @@ def gen_unsubscribe_multiple(mid, topics, proto_ver=4): return struct.pack("!BBH", 162, remaining_length, mid) + packet -def gen_unsuback(mid, proto_ver=4): +def gen_unsuback(mid, proto_ver=4, reason_code=0): if proto_ver == 5: - return struct.pack('!BBHB', 176, 3, mid, 0) + if isinstance(reason_code, list): + reason_code_count = len(reason_code) + p = struct.pack('!BBHB', 176, 3+reason_code_count, mid, 0) + for r in reason_code: + p += struct.pack('B', r) + return p + else: + return struct.pack('!BBHBB', 176, 4, mid, 0, reason_code) else: return struct.pack('!BBH', 176, 2, mid) From 1479c57e348d1b7bf2b6f253b264c551fc6cc5cc Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sun, 17 Feb 2019 10:14:02 +0000 Subject: [PATCH 246/254] v5 report reason code=no sub when unsubscribing. --- src/handle_unsubscribe.c | 6 ++++-- src/mosquitto_broker_internal.h | 2 +- src/subs.c | 10 ++++++---- test/broker/02-unsubscribe-qos2-multiple-v5.py | 12 +++++++++--- test/broker/02-unsubscribe-qos2-v5.py | 2 +- 5 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/handle_unsubscribe.c b/src/handle_unsubscribe.c index 03d4025a99..075bde4421 100644 --- a/src/handle_unsubscribe.c +++ b/src/handle_unsubscribe.c @@ -31,6 +31,7 @@ int handle__unsubscribe(struct mosquitto_db *db, struct mosquitto *context) char *sub; int slen; int rc; + uint8_t reason; int reason_code_count = 0; int reason_code_max; uint8_t *reason_codes = NULL, *reason_tmp; @@ -89,11 +90,12 @@ int handle__unsubscribe(struct mosquitto_db *db, struct mosquitto *context) } log__printf(NULL, MOSQ_LOG_DEBUG, "\t%s", sub); - sub__remove(db, context, sub, db->subs); + rc = sub__remove(db, context, sub, db->subs, &reason); log__printf(NULL, MOSQ_LOG_UNSUBSCRIBE, "%s %s", context->id, sub); mosquitto__free(sub); + if(rc) return rc; - reason_codes[reason_code_count] = 0; + reason_codes[reason_code_count] = reason; reason_code_count++; if(reason_code_count == reason_code_max){ reason_tmp = mosquitto__realloc(reason_codes, reason_code_max*2); diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index 3a2ac5179e..7d02f4327f 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -584,7 +584,7 @@ void sys_tree__update(struct mosquitto_db *db, int interval, time_t start_time); * ============================================================ */ int sub__add(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int qos, uint32_t identifier, int options, struct mosquitto__subhier **root); struct mosquitto__subhier *sub__add_hier_entry(struct mosquitto__subhier *parent, struct mosquitto__subhier **sibling, const char *topic, size_t len); -int sub__remove(struct mosquitto_db *db, struct mosquitto *context, const char *sub, struct mosquitto__subhier *root); +int sub__remove(struct mosquitto_db *db, struct mosquitto *context, const char *sub, struct mosquitto__subhier *root, uint8_t *reason); void sub__tree_print(struct mosquitto__subhier *root, int level); int sub__clean_session(struct mosquitto_db *db, struct mosquitto *context); int sub__retain_queue(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int sub_qos, uint32_t subscription_identifier); diff --git a/src/subs.c b/src/subs.c index 3a7480ee48..9fe52d523f 100644 --- a/src/subs.c +++ b/src/subs.c @@ -324,7 +324,7 @@ static int sub__add_recurse(struct mosquitto_db *db, struct mosquitto *context, } } -static int sub__remove_recurse(struct mosquitto_db *db, struct mosquitto *context, struct mosquitto__subhier *subhier, struct sub__token *tokens) +static int sub__remove_recurse(struct mosquitto_db *db, struct mosquitto *context, struct mosquitto__subhier *subhier, struct sub__token *tokens, uint8_t *reason) { struct mosquitto__subhier *branch; struct mosquitto__subleaf *leaf; @@ -357,6 +357,7 @@ static int sub__remove_recurse(struct mosquitto_db *db, struct mosquitto *contex break; } } + *reason = 0; return MOSQ_ERR_SUCCESS; } leaf = leaf->next; @@ -366,7 +367,7 @@ static int sub__remove_recurse(struct mosquitto_db *db, struct mosquitto *contex HASH_FIND(hh, subhier->children, UHPA_ACCESS_TOPIC(tokens), tokens->topic_len, branch); if(branch){ - sub__remove_recurse(db, context, branch, tokens->next); + sub__remove_recurse(db, context, branch, tokens->next, reason); if(!branch->children && !branch->subs && !branch->retained){ HASH_DELETE(hh, subhier->children, branch); UHPA_FREE_TOPIC(branch); @@ -478,7 +479,7 @@ int sub__add(struct mosquitto_db *db, struct mosquitto *context, const char *sub return rc; } -int sub__remove(struct mosquitto_db *db, struct mosquitto *context, const char *sub, struct mosquitto__subhier *root) +int sub__remove(struct mosquitto_db *db, struct mosquitto *context, const char *sub, struct mosquitto__subhier *root, uint8_t *reason) { int rc = 0; struct mosquitto__subhier *subhier; @@ -491,7 +492,8 @@ int sub__remove(struct mosquitto_db *db, struct mosquitto *context, const char * HASH_FIND(hh, root, UHPA_ACCESS_TOPIC(tokens), tokens->topic_len, subhier); if(subhier){ - rc = sub__remove_recurse(db, context, subhier, tokens); + *reason = MQTT_RC_NO_SUBSCRIPTION_EXISTED; + rc = sub__remove_recurse(db, context, subhier, tokens, reason); } sub__topic_tokens_free(tokens); diff --git a/test/broker/02-unsubscribe-qos2-multiple-v5.py b/test/broker/02-unsubscribe-qos2-multiple-v5.py index 1e6c3f5344..bbbc40cdbb 100755 --- a/test/broker/02-unsubscribe-qos2-multiple-v5.py +++ b/test/broker/02-unsubscribe-qos2-multiple-v5.py @@ -1,23 +1,29 @@ #!/usr/bin/env python -# Test whether a v5 UNSUBSCRIBE to multiple topics with QoS 2 results in the correct UNSUBACK packet. +# Test whether a v5 UNSUBSCRIBE to multiple topics with QoS 2 results in the +# correct UNSUBACK packet, when one subscription exists and the other does not. from mosq_test_helper import * rc = 1 -mid = 3 keepalive = 60 connect_packet = mosq_test.gen_connect("unsubscribe-qos2-test", keepalive=keepalive, proto_ver=5) connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) +mid = 1 +subscribe_packet = mosq_test.gen_subscribe(mid, "qos2/two", 2, proto_ver=5) +suback_packet = mosq_test.gen_suback(mid, 2, proto_ver=5) + +mid = 3 unsubscribe_packet = mosq_test.gen_unsubscribe_multiple(mid, ["qos2/one", "qos2/two"], proto_ver=5) -unsuback_packet = mosq_test.gen_unsuback(mid, proto_ver=5, reason_code=[0, 0]) +unsuback_packet = mosq_test.gen_unsuback(mid, proto_ver=5, reason_code=[17, 0]) 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, port=port) + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback") mosq_test.do_send_receive(sock, unsubscribe_packet, unsuback_packet, "unsuback") rc = 0 diff --git a/test/broker/02-unsubscribe-qos2-v5.py b/test/broker/02-unsubscribe-qos2-v5.py index a05a153915..2936c33b13 100755 --- a/test/broker/02-unsubscribe-qos2-v5.py +++ b/test/broker/02-unsubscribe-qos2-v5.py @@ -12,7 +12,7 @@ connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) unsubscribe_packet = mosq_test.gen_unsubscribe(mid, "qos2/test", proto_ver=5) -unsuback_packet = mosq_test.gen_unsuback(mid, proto_ver=5) +unsuback_packet = mosq_test.gen_unsuback(mid, proto_ver=5, reason_code=17) port = mosq_test.get_port() broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port) From c823073be6d960ca6949ce97206004401298d830 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sun, 17 Feb 2019 19:47:53 +0000 Subject: [PATCH 247/254] v5 unsubscribe test, single topic. --- test/lib/02-unsubscribe-v5.py | 54 ++++++++++++++++++++++++++++++++++ test/lib/Makefile | 1 + test/lib/c/02-unsubscribe-v5.c | 50 +++++++++++++++++++++++++++++++ test/lib/c/Makefile | 1 + test/lib/test.py | 1 + 5 files changed, 107 insertions(+) create mode 100755 test/lib/02-unsubscribe-v5.py create mode 100644 test/lib/c/02-unsubscribe-v5.c diff --git a/test/lib/02-unsubscribe-v5.py b/test/lib/02-unsubscribe-v5.py new file mode 100755 index 0000000000..9b55d276cc --- /dev/null +++ b/test/lib/02-unsubscribe-v5.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python + +# Test whether a v5 client sends a correct UNSUBSCRIBE packet, and handles the UNSUBACK. + +from mosq_test_helper import * + +port = mosq_test.get_lib_port() + +keepalive = 60 +connect_packet = mosq_test.gen_connect("unsubscribe-test", keepalive=keepalive, proto_ver=5) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +disconnect_packet = mosq_test.gen_disconnect(proto_ver=5) + +mid = 1 +unsubscribe_packet = mosq_test.gen_unsubscribe(mid, "unsubscribe/test", proto_ver=5) +unsuback_packet = mosq_test.gen_unsuback(mid, 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) + + if mosq_test.expect_packet(conn, "unsubscribe", unsubscribe_packet): + conn.send(unsuback_packet) + + if mosq_test.expect_packet(conn, "disconnect", disconnect_packet): + rc = 0 + + conn.close() +finally: + client.terminate() + client.wait() + sock.close() + +exit(rc) diff --git a/test/lib/Makefile b/test/lib/Makefile index d88f58a1df..00d963a738 100644 --- a/test/lib/Makefile +++ b/test/lib/Makefile @@ -32,6 +32,7 @@ c : test-compile ./02-subscribe-qos1.py $@/02-subscribe-qos1.test ./02-subscribe-qos2.py $@/02-subscribe-qos2.test ./02-unsubscribe.py $@/02-unsubscribe.test + ./02-unsubscribe-v5.py $@/02-unsubscribe-v5.test ./03-publish-qos0.py $@/03-publish-qos0.test ./03-publish-qos0-no-payload.py $@/03-publish-qos0-no-payload.test ./03-publish-c2b-qos1-disconnect.py $@/03-publish-c2b-qos1-disconnect.test diff --git a/test/lib/c/02-unsubscribe-v5.c b/test/lib/c/02-unsubscribe-v5.c new file mode 100644 index 0000000000..50e7377b20 --- /dev/null +++ b/test/lib/c/02-unsubscribe-v5.c @@ -0,0 +1,50 @@ +#include +#include +#include +#include + +static int run = -1; + +void on_connect(struct mosquitto *mosq, void *obj, int rc) +{ + if(rc){ + exit(1); + }else{ + mosquitto_unsubscribe(mosq, NULL, "unsubscribe/test"); + } +} + +void on_disconnect(struct mosquitto *mosq, void *obj, int rc) +{ + run = rc; +} + +void on_unsubscribe(struct mosquitto *mosq, void *obj, int mid) +{ + mosquitto_disconnect(mosq); +} + +int main(int argc, char *argv[]) +{ + int rc; + struct mosquitto *mosq; + + int port = atoi(argv[1]); + + mosquitto_lib_init(); + + mosq = mosquitto_new("unsubscribe-test", true, NULL); + mosquitto_int_option(mosq, MOSQ_OPT_PROTOCOL_VERSION, MQTT_PROTOCOL_V5); + mosquitto_connect_callback_set(mosq, on_connect); + mosquitto_disconnect_callback_set(mosq, on_disconnect); + mosquitto_unsubscribe_callback_set(mosq, on_unsubscribe); + + rc = mosquitto_connect(mosq, "localhost", port, 60); + + while(run == -1){ + mosquitto_loop(mosq, -1, 1); + } + + mosquitto_lib_cleanup(); + return run; +} diff --git a/test/lib/c/Makefile b/test/lib/c/Makefile index f02beb9024..79552efc44 100644 --- a/test/lib/c/Makefile +++ b/test/lib/c/Makefile @@ -15,6 +15,7 @@ SRC = \ 02-subscribe-qos1.c \ 02-subscribe-qos2.c \ 02-unsubscribe.c \ + 02-unsubscribe-v5.c \ 03-publish-qos0.c \ 03-publish-qos0-no-payload.c \ 03-publish-c2b-qos1-disconnect.c \ diff --git a/test/lib/test.py b/test/lib/test.py index 76d7dc0d4d..29c309bc94 100755 --- a/test/lib/test.py +++ b/test/lib/test.py @@ -15,6 +15,7 @@ (1, ['./02-subscribe-qos1.py', 'c/02-subscribe-qos1.test']), (1, ['./02-subscribe-qos2.py', 'c/02-subscribe-qos2.test']), (1, ['./02-unsubscribe.py', 'c/02-unsubscribe.test']), + (1, ['./02-unsubscribe-v5.py', 'c/02-unsubscribe-v5.test']), (1, ['./03-publish-b2c-qos1.py', 'c/03-publish-b2c-qos1.test']), (1, ['./03-publish-b2c-qos2.py', 'c/03-publish-b2c-qos2.test']), (1, ['./03-publish-c2b-qos1-len.py', 'c/03-publish-c2b-qos1-len.test']), From 66c1e2ccf0b28fe3af2f7016ea120133d270100d Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sun, 17 Feb 2019 20:59:16 +0000 Subject: [PATCH 248/254] Add mosquitto_unsubscribe_multiple(), plus tests. --- lib/actions.c | 51 +++++++------------- lib/linker.version | 1 + lib/mosquitto.h | 29 ++++++++++++ lib/send_mosq.h | 2 +- lib/send_unsubscribe.c | 21 +++++++-- src/handle_connack.c | 2 +- test/lib/02-unsubscribe-multiple-v5.py | 63 +++++++++++++++++++++++++ test/lib/Makefile | 1 + test/lib/c/02-unsubscribe-multiple-v5.c | 59 +++++++++++++++++++++++ test/lib/c/Makefile | 1 + test/lib/test.py | 1 + 11 files changed, 189 insertions(+), 42 deletions(-) create mode 100755 test/lib/02-unsubscribe-multiple-v5.py create mode 100644 test/lib/c/02-unsubscribe-multiple-v5.c diff --git a/lib/actions.c b/lib/actions.c index bc6e2e1a0f..3779318e68 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -146,39 +146,12 @@ int mosquitto_publish_v5(struct mosquitto *mosq, int *mid, const char *topic, in int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const char *sub, int qos) { - return mosquitto_subscribe_v5(mosq, mid, sub, qos, 0, NULL); + return mosquitto_subscribe_multiple(mosq, mid, 1, (char *const *const)&sub, qos, 0, NULL); } int mosquitto_subscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, int qos, int options, const mosquitto_property *properties) { - const mosquitto_property *outgoing_properties = NULL; - mosquitto_property local_property; - - int rc; - - if(!mosq) return MOSQ_ERR_INVAL; - if(qos < 0 || qos > 2) return MOSQ_ERR_INVAL; - if((options & 0x30) == 0x30 || (options & 0xC0) != 0) return MOSQ_ERR_INVAL; - if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED; - if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; - - if(mosquitto_sub_topic_check(sub)) return MOSQ_ERR_INVAL; - if(mosquitto_validate_utf8(sub, strlen(sub))) return MOSQ_ERR_MALFORMED_UTF8; - - if(properties){ - if(properties->client_generated){ - outgoing_properties = properties; - }else{ - memcpy(&local_property, properties, sizeof(mosquitto_property)); - local_property.client_generated = true; - local_property.next = NULL; - outgoing_properties = &local_property; - } - rc = mosquitto_property_check_all(CMD_SUBSCRIBE, outgoing_properties); - if(rc) return rc; - } - - return send__subscribe(mosq, mid, 1, (char *const *const)&sub, qos|options, outgoing_properties); + return mosquitto_subscribe_multiple(mosq, mid, 1, (char *const *const)&sub, qos, options, properties); } @@ -213,28 +186,31 @@ int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count if(mosquitto_validate_utf8(sub[i], strlen(sub[i]))) return MOSQ_ERR_MALFORMED_UTF8; } - return send__subscribe(mosq, mid, sub_count, sub, qos|options, properties); + return send__subscribe(mosq, mid, sub_count, sub, qos|options, outgoing_properties); } int mosquitto_unsubscribe(struct mosquitto *mosq, int *mid, const char *sub) { - return mosquitto_unsubscribe_v5(mosq, mid, sub, NULL); + return mosquitto_unsubscribe_multiple(mosq, mid, 1, (char *const *const)&sub, NULL); } int mosquitto_unsubscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, const mosquitto_property *properties) +{ + return mosquitto_unsubscribe_multiple(mosq, mid, 1, (char *const *const)&sub, properties); +} + +int mosquitto_unsubscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, const mosquitto_property *properties) { const mosquitto_property *outgoing_properties = NULL; mosquitto_property local_property; int rc; + int i; if(!mosq) return MOSQ_ERR_INVAL; if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED; if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; - if(mosquitto_sub_topic_check(sub)) return MOSQ_ERR_INVAL; - if(mosquitto_validate_utf8(sub, strlen(sub))) return MOSQ_ERR_MALFORMED_UTF8; - if(properties){ if(properties->client_generated){ outgoing_properties = properties; @@ -248,6 +224,11 @@ int mosquitto_unsubscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, if(rc) return rc; } - return send__unsubscribe(mosq, mid, sub, outgoing_properties); + for(i=0; iprotocol == mosq_p_mqtt5){ proplen = property__get_length_all(properties); varbytes = packet__varint_bytes(proplen); @@ -74,14 +79,20 @@ int send__unsubscribe(struct mosquitto *mosq, int *mid, const char *topic, const } /* Payload */ - packet__write_string(packet, topic, strlen(topic)); + for(i=0; iid, local_mid, topic); + for(i=0; iid, local_mid, topic[i]); + } # endif #else - log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending UNSUBSCRIBE (Mid: %d, Topic: %s)", mosq->id, local_mid, topic); + for(i=0; iid, local_mid, topic[i]); + } #endif return packet__queue(mosq, packet); } diff --git a/src/handle_connack.c b/src/handle_connack.c index 4853010072..b853a9b83c 100644 --- a/src/handle_connack.c +++ b/src/handle_connack.c @@ -91,7 +91,7 @@ int handle__connack(struct mosquitto_db *db, struct mosquitto *context) } }else{ if(context->bridge->attempt_unsubscribe){ - if(send__unsubscribe(context, NULL, context->bridge->topics[i].remote_topic, NULL)){ + if(send__unsubscribe(context, NULL, 1, &context->bridge->topics[i].remote_topic, NULL)){ /* direction = inwards only. This means we should not be subscribed * to the topic. It is possible that we used to be subscribed to * this topic so unsubscribe. */ diff --git a/test/lib/02-unsubscribe-multiple-v5.py b/test/lib/02-unsubscribe-multiple-v5.py new file mode 100755 index 0000000000..af564e6ad8 --- /dev/null +++ b/test/lib/02-unsubscribe-multiple-v5.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +# Test whether a v5 client sends a correct UNSUBSCRIBE packet with multiple +# topics, and handles the UNSUBACK. + +from mosq_test_helper import * + +port = mosq_test.get_lib_port() + +keepalive = 60 +connect_packet = mosq_test.gen_connect("unsubscribe-test", keepalive=keepalive, proto_ver=5) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +disconnect_packet = mosq_test.gen_disconnect(proto_ver=5) + +mid = 1 +subscribe_packet = mosq_test.gen_subscribe(mid, "unsubscribe/test", 2, proto_ver=5) +suback_packet = mosq_test.gen_suback(mid, 2, proto_ver=5) + +mid = 2 +unsubscribe_packet = mosq_test.gen_unsubscribe_multiple(mid, ["unsubscribe/test", "no-sub"], proto_ver=5) +unsuback_packet = mosq_test.gen_unsuback(mid, reason_code=[0, 17], 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) + +rc = 1 +try: + (conn, address) = sock.accept() + conn.settimeout(10) + + if mosq_test.expect_packet(conn, "connect", connect_packet): + conn.send(connack_packet) + + if mosq_test.expect_packet(conn, "subscribe", subscribe_packet): + conn.send(suback_packet) + + if mosq_test.expect_packet(conn, "unsubscribe", unsubscribe_packet): + conn.send(unsuback_packet) + + if mosq_test.expect_packet(conn, "disconnect", disconnect_packet): + rc = 0 + + conn.close() +finally: + client.terminate() + client.wait() + sock.close() + +exit(rc) diff --git a/test/lib/Makefile b/test/lib/Makefile index 00d963a738..9e55b52afc 100644 --- a/test/lib/Makefile +++ b/test/lib/Makefile @@ -33,6 +33,7 @@ c : test-compile ./02-subscribe-qos2.py $@/02-subscribe-qos2.test ./02-unsubscribe.py $@/02-unsubscribe.test ./02-unsubscribe-v5.py $@/02-unsubscribe-v5.test + ./02-unsubscribe-multiple-v5.py $@/02-unsubscribe-multiple-v5.test ./03-publish-qos0.py $@/03-publish-qos0.test ./03-publish-qos0-no-payload.py $@/03-publish-qos0-no-payload.test ./03-publish-c2b-qos1-disconnect.py $@/03-publish-c2b-qos1-disconnect.test diff --git a/test/lib/c/02-unsubscribe-multiple-v5.c b/test/lib/c/02-unsubscribe-multiple-v5.c new file mode 100644 index 0000000000..7403a6333f --- /dev/null +++ b/test/lib/c/02-unsubscribe-multiple-v5.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include + +static int run = -1; + +void on_connect(struct mosquitto *mosq, void *obj, int rc) +{ + if(rc){ + exit(1); + }else{ + mosquitto_subscribe(mosq, NULL, "unsubscribe/test", 2); + } +} + +void on_subscribe(struct mosquitto *mosq, void *obj, int mid, int sub_count, const int *subs) +{ + char *unsubs[] = {"unsubscribe/test", "no-sub"}; + + mosquitto_unsubscribe_multiple(mosq, NULL, 2, unsubs, NULL); +} + +void on_disconnect(struct mosquitto *mosq, void *obj, int rc) +{ + run = rc; +} + +void on_unsubscribe(struct mosquitto *mosq, void *obj, int mid) +{ + mosquitto_disconnect(mosq); +} + + +int main(int argc, char *argv[]) +{ + int rc; + struct mosquitto *mosq; + + int port = atoi(argv[1]); + + mosquitto_lib_init(); + + mosq = mosquitto_new("unsubscribe-test", true, NULL); + mosquitto_int_option(mosq, MOSQ_OPT_PROTOCOL_VERSION, MQTT_PROTOCOL_V5); + mosquitto_connect_callback_set(mosq, on_connect); + mosquitto_disconnect_callback_set(mosq, on_disconnect); + mosquitto_subscribe_callback_set(mosq, on_subscribe); + mosquitto_unsubscribe_callback_set(mosq, on_unsubscribe); + + rc = mosquitto_connect(mosq, "localhost", port, 60); + + while(run == -1){ + mosquitto_loop(mosq, -1, 1); + } + + mosquitto_lib_cleanup(); + return run; +} diff --git a/test/lib/c/Makefile b/test/lib/c/Makefile index 79552efc44..d89ab9ab16 100644 --- a/test/lib/c/Makefile +++ b/test/lib/c/Makefile @@ -16,6 +16,7 @@ SRC = \ 02-subscribe-qos2.c \ 02-unsubscribe.c \ 02-unsubscribe-v5.c \ + 02-unsubscribe-multiple-v5.c \ 03-publish-qos0.c \ 03-publish-qos0-no-payload.c \ 03-publish-c2b-qos1-disconnect.c \ diff --git a/test/lib/test.py b/test/lib/test.py index 29c309bc94..68df885507 100755 --- a/test/lib/test.py +++ b/test/lib/test.py @@ -16,6 +16,7 @@ (1, ['./02-subscribe-qos2.py', 'c/02-subscribe-qos2.test']), (1, ['./02-unsubscribe.py', 'c/02-unsubscribe.test']), (1, ['./02-unsubscribe-v5.py', 'c/02-unsubscribe-v5.test']), + (1, ['./02-unsubscribe-multiple-v5.py', 'c/02-unsubscribe-multiple-v5.test']), (1, ['./03-publish-b2c-qos1.py', 'c/03-publish-b2c-qos1.test']), (1, ['./03-publish-b2c-qos2.py', 'c/03-publish-b2c-qos2.test']), (1, ['./03-publish-c2b-qos1-len.py', 'c/03-publish-c2b-qos1-len.test']), From 8db16591faf0675adcc5fae36076014fc3b69542 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Mon, 18 Feb 2019 12:24:19 +0000 Subject: [PATCH 249/254] Test and fix for subscription identifiers not being updated. Closes #1169. Thanks to Christoph Krey. --- src/subs.c | 1 + test/broker/02-subpub-qos0-subscription-id.py | 41 ++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/subs.c b/src/subs.c index 9fe52d523f..ad71b73f44 100644 --- a/src/subs.c +++ b/src/subs.c @@ -263,6 +263,7 @@ static int sub__add_recurse(struct mosquitto_db *db, struct mosquitto *context, * need to update QoS. Return MOSQ_ERR_SUB_EXISTS to * indicate this to the calling function. */ leaf->qos = qos; + leaf->identifier = identifier; if(context->protocol == mosq_p_mqtt31 || context->protocol == mosq_p_mqtt5){ return MOSQ_ERR_SUB_EXISTS; }else{ diff --git a/test/broker/02-subpub-qos0-subscription-id.py b/test/broker/02-subpub-qos0-subscription-id.py index 4f9c1a1deb..c25dda549d 100755 --- a/test/broker/02-subpub-qos0-subscription-id.py +++ b/test/broker/02-subpub-qos0-subscription-id.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Do subscription identifiers work as expected? +# Does setting and updating subscription identifiers work as expected? # MQTT v5 from mosq_test_helper import * @@ -24,6 +24,24 @@ subscribe3_packet = mosq_test.gen_subscribe(mid, "subpub/noid", 0, proto_ver=5) suback3_packet = mosq_test.gen_suback(mid, 0, proto_ver=5) +# Updated version of subscribe1, now without a subscription identifier +mid = 4 +subscribe1u_packet = mosq_test.gen_subscribe(mid, "subpub/id1", 0, proto_ver=5) +suback1u_packet = mosq_test.gen_suback(mid, 0, proto_ver=5) + +# Updated version of subscribe2, with a new subscription identifier +mid = 5 +props = mqtt5_props.gen_varint_prop(mqtt5_props.PROP_SUBSCRIPTION_IDENTIFIER, 19) +subscribe2u_packet = mosq_test.gen_subscribe(mid, "subpub/+/id2", 0, proto_ver=5, properties=props) +suback2u_packet = mosq_test.gen_suback(mid, 0, proto_ver=5) + +# Updated version of subscribe3, now with a subscription identifier +mid = 6 +props = mqtt5_props.gen_varint_prop(mqtt5_props.PROP_SUBSCRIPTION_IDENTIFIER, 21) +subscribe3u_packet = mosq_test.gen_subscribe(mid, "subpub/noid", 0, proto_ver=5, properties=props) +suback3u_packet = mosq_test.gen_suback(mid, 0, proto_ver=5) + + publish1_packet = mosq_test.gen_publish("subpub/id1", qos=0, payload="message1", proto_ver=5) props = mqtt5_props.gen_varint_prop(mqtt5_props.PROP_SUBSCRIPTION_IDENTIFIER, 1) @@ -36,6 +54,18 @@ publish3_packet = mosq_test.gen_publish("subpub/noid", qos=0, payload="message3", proto_ver=5) +# Updated version of publish1r, now with no id +publish1ru_packet = mosq_test.gen_publish("subpub/id1", qos=0, payload="message1", proto_ver=5) + +# Updated verison of publish2r, with updated id +props = mqtt5_props.gen_varint_prop(mqtt5_props.PROP_SUBSCRIPTION_IDENTIFIER, 19) +publish2ru_packet = mosq_test.gen_publish("subpub/test/id2", qos=0, payload="message2", proto_ver=5, properties=props) + +# Updated version of publish3r, now with an id +props = mqtt5_props.gen_varint_prop(mqtt5_props.PROP_SUBSCRIPTION_IDENTIFIER, 21) +publish3ru_packet = mosq_test.gen_publish("subpub/noid", qos=0, payload="message3", proto_ver=5, properties=props) + + port = mosq_test.get_port() broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port) @@ -50,6 +80,15 @@ mosq_test.do_send_receive(sock, publish2_packet, publish2r_packet, "publish2") mosq_test.do_send_receive(sock, publish1_packet, publish1r_packet, "publish1") + # Now update the subscription identifiers + mosq_test.do_send_receive(sock, subscribe1u_packet, suback1u_packet, "suback1u") + mosq_test.do_send_receive(sock, subscribe2u_packet, suback2u_packet, "suback2u") + mosq_test.do_send_receive(sock, subscribe3u_packet, suback3u_packet, "suback3u") + + mosq_test.do_send_receive(sock, publish2_packet, publish2ru_packet, "publish2u") + mosq_test.do_send_receive(sock, publish3_packet, publish3ru_packet, "publish3u") + mosq_test.do_send_receive(sock, publish1_packet, publish1ru_packet, "publish1u") + rc = 0 sock.close() From 1877f8a3268e4103b7a5827a4edab736502b79cc Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Mon, 18 Feb 2019 19:46:39 +0000 Subject: [PATCH 250/254] Tests and implementation for maximum packet size. This is for broker outgoing connack and publish packets only. --- lib/mosquitto.h | 1 + lib/mosquitto_internal.h | 1 + lib/packet_mosq.c | 15 +++++++ lib/packet_mosq.h | 2 + lib/send_publish.c | 9 ++++ src/database.c | 10 +++-- src/property_broker.c | 5 +++ src/send_connack.c | 25 ++++++++--- .../12-prop-maximum-packet-size-connect.py | 30 +++++++++++++ .../12-prop-maximum-packet-size-publish.py | 45 +++++++++++++++++++ test/broker/Makefile | 2 + test/broker/test.py | 2 + 12 files changed, 137 insertions(+), 10 deletions(-) create mode 100755 test/broker/12-prop-maximum-packet-size-connect.py create mode 100755 test/broker/12-prop-maximum-packet-size-publish.py diff --git a/lib/mosquitto.h b/lib/mosquitto.h index f4770bc592..a11aa5dc90 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -93,6 +93,7 @@ enum mosq_err_t { MOSQ_ERR_DUPLICATE_PROPERTY = 22, MOSQ_ERR_TLS_HANDSHAKE = 23, MOSQ_ERR_QOS_NOT_SUPPORTED = 24, + MOSQ_ERR_OVERSIZE_PACKET = 25, }; /* Error values */ diff --git a/lib/mosquitto_internal.h b/lib/mosquitto_internal.h index a72fc72230..001b99aabf 100644 --- a/lib/mosquitto_internal.h +++ b/lib/mosquitto_internal.h @@ -186,6 +186,7 @@ struct mosquitto { struct mosquitto__packet *out_packet; struct mosquitto_message_all *will; struct mosquitto__alias *aliases; + uint32_t maximum_packet_size; int alias_count; #ifdef WITH_TLS SSL *ssl; diff --git a/lib/packet_mosq.c b/lib/packet_mosq.c index 509cd7d02c..2dac17dc51 100644 --- a/lib/packet_mosq.c +++ b/lib/packet_mosq.c @@ -150,6 +150,21 @@ int packet__queue(struct mosquitto *mosq, struct mosquitto__packet *packet) } +int packet__check_oversize(struct mosquitto *mosq, uint32_t remaining_length) +{ + int len; + + if(mosq->maximum_packet_size == 0) return MOSQ_ERR_SUCCESS; + + len = remaining_length + packet__varint_bytes(remaining_length); + if(len > mosq->maximum_packet_size){ + return MOSQ_ERR_OVERSIZE_PACKET; + }else{ + return MOSQ_ERR_SUCCESS; + } +} + + int packet__write(struct mosquitto *mosq) { ssize_t write_length; diff --git a/lib/packet_mosq.h b/lib/packet_mosq.h index 22728cd79d..503fb523e3 100644 --- a/lib/packet_mosq.h +++ b/lib/packet_mosq.h @@ -27,6 +27,8 @@ int packet__alloc(struct mosquitto__packet *packet); void packet__cleanup(struct mosquitto__packet *packet); int packet__queue(struct mosquitto *mosq, struct mosquitto__packet *packet); +int packet__check_oversize(struct mosquitto *mosq, uint32_t remaining_length); + int packet__read_byte(struct mosquitto__packet *packet, uint8_t *byte); int packet__read_bytes(struct mosquitto__packet *packet, void *bytes, uint32_t count); int packet__read_binary(struct mosquitto__packet *packet, uint8_t **data, int *length); diff --git a/lib/send_publish.c b/lib/send_publish.c index 41b5e9cebd..e72572c6cb 100644 --- a/lib/send_publish.c +++ b/lib/send_publish.c @@ -167,6 +167,15 @@ int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, packetlen += proplen + varbytes; } } + if(packet__check_oversize(mosq, packetlen)){ +#ifdef WITH_BROKER + log__printf(NULL, MOSQ_LOG_NOTICE, "Dropping too large outgoing PUBLISH for %s (%d bytes)", mosq->id, packetlen); +#else + log__printf(NULL, MOSQ_LOG_NOTICE, "Dropping too large outgoing PUBLISH (%d bytes)", packetlen); +#endif + return MOSQ_ERR_OVERSIZE_PACKET; + } + packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet)); if(!packet) return MOSQ_ERR_NOMEM; diff --git a/src/database.c b/src/database.c index 750c6b4b60..591684da12 100644 --- a/src/database.c +++ b/src/database.c @@ -946,7 +946,7 @@ int db__message_write(struct mosquitto_db *db, struct mosquitto *context) switch(tail->state){ case mosq_ms_publish_qos0: rc = send__publish(context, mid, topic, payloadlen, payload, qos, retain, retries, cmsg_props, store_props, expiry_interval); - if(!rc){ + if(rc == MOSQ_ERR_SUCCESS || rc == MOSQ_ERR_OVERSIZE_PACKET){ db__message_remove(db, context, &tail, last); }else{ return rc; @@ -955,10 +955,12 @@ int db__message_write(struct mosquitto_db *db, struct mosquitto *context) case mosq_ms_publish_qos1: rc = send__publish(context, mid, topic, payloadlen, payload, qos, retain, retries, cmsg_props, store_props, expiry_interval); - if(!rc){ + if(rc == MOSQ_ERR_SUCCESS){ tail->timestamp = mosquitto_time(); tail->dup = 1; /* Any retry attempts are a duplicate. */ tail->state = mosq_ms_wait_for_puback; + }else if(rc == MOSQ_ERR_OVERSIZE_PACKET){ + db__message_remove(db, context, &tail, last); }else{ return rc; } @@ -968,10 +970,12 @@ int db__message_write(struct mosquitto_db *db, struct mosquitto *context) case mosq_ms_publish_qos2: rc = send__publish(context, mid, topic, payloadlen, payload, qos, retain, retries, cmsg_props, store_props, expiry_interval); - if(!rc){ + if(rc == MOSQ_ERR_SUCCESS){ tail->timestamp = mosquitto_time(); tail->dup = 1; /* Any retry attempts are a duplicate. */ tail->state = mosq_ms_wait_for_pubrec; + }else if(rc == MOSQ_ERR_OVERSIZE_PACKET){ + db__message_remove(db, context, &tail, last); }else{ return rc; } diff --git a/src/property_broker.c b/src/property_broker.c index ee76b2c418..654c802b1d 100644 --- a/src/property_broker.c +++ b/src/property_broker.c @@ -42,6 +42,11 @@ int property__process_connect(struct mosquitto *context, mosquitto_property *pro context->send_maximum = p->value.i16; context->send_quota = context->send_maximum; + }else if(p->identifier == MQTT_PROP_MAXIMUM_PACKET_SIZE){ + if(p->value.i32 == 0){ + return MOSQ_ERR_PROTOCOL; + } + context->maximum_packet_size = p->value.i32; } p = p->next; } diff --git a/src/send_connack.c b/src/send_connack.c index d51179b0ee..927d4d1e3b 100644 --- a/src/send_connack.c +++ b/src/send_connack.c @@ -29,6 +29,7 @@ int send__connack(struct mosquitto_db *db, struct mosquitto *context, int ack, i int rc; mosquitto_property *connack_props = NULL; int proplen, varbytes; + uint32_t remaining_length; rc = mosquitto_property_copy_all(&connack_props, properties); if(rc){ @@ -43,30 +44,40 @@ int send__connack(struct mosquitto_db *db, struct mosquitto *context, int ack, i } } - packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet)); - if(!packet) return MOSQ_ERR_NOMEM; + remaining_length = 2; - packet->command = CMD_CONNACK; - packet->remaining_length = 2; if(context->protocol == mosq_p_mqtt5){ if(reason_code < 128 && db->config->retain_available == false){ rc = mosquitto_property_add_byte(&connack_props, MQTT_PROP_RETAIN_AVAILABLE, 0); if(rc){ - mosquitto__free(packet); + mosquitto_property_free_all(&connack_props); return rc; } } /* FIXME - disable support until available */ rc = mosquitto_property_add_byte(&connack_props, MQTT_PROP_SHARED_SUB_AVAILABLE, 0); if(rc){ - mosquitto__free(packet); + mosquitto_property_free_all(&connack_props); return rc; } proplen = property__get_length_all(connack_props); varbytes = packet__varint_bytes(proplen); - packet->remaining_length += proplen + varbytes; + remaining_length += proplen + varbytes; + } + + if(packet__check_oversize(context, remaining_length)){ + mosquitto_property_free_all(&connack_props); + mosquitto__free(packet); + return MOSQ_ERR_OVERSIZE_PACKET; } + + packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet)); + if(!packet) return MOSQ_ERR_NOMEM; + + packet->command = CMD_CONNACK; + packet->remaining_length = remaining_length; + rc = packet__alloc(packet); if(rc){ mosquitto__free(packet); diff --git a/test/broker/12-prop-maximum-packet-size-connect.py b/test/broker/12-prop-maximum-packet-size-connect.py new file mode 100755 index 0000000000..11936088c4 --- /dev/null +++ b/test/broker/12-prop-maximum-packet-size-connect.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python + +# Test whether setting maximum packet size to smaller than a CONNACK packet +# results in the CONNECT being rejected. +# MQTTv5 + +from mosq_test_helper import * + +rc = 1 + +keepalive = 10 +props = mqtt5_props.gen_uint32_prop(mqtt5_props.PROP_MAXIMUM_PACKET_SIZE, 2) +connect_packet = mosq_test.gen_connect("test", proto_ver=5, keepalive=keepalive, properties=props) + +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, "", port=port) + # Exception occurs if connack packet returned + rc = 0 +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/12-prop-maximum-packet-size-publish.py b/test/broker/12-prop-maximum-packet-size-publish.py new file mode 100755 index 0000000000..9db5ad394f --- /dev/null +++ b/test/broker/12-prop-maximum-packet-size-publish.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +# Test whether maximum packet size is honoured on a PUBLISH to a client +# MQTTv5 + +from mosq_test_helper import * + +rc = 1 + +keepalive = 10 +props = mqtt5_props.gen_uint32_prop(mqtt5_props.PROP_MAXIMUM_PACKET_SIZE, 20) +connect_packet = mosq_test.gen_connect("test", proto_ver=5, keepalive=keepalive, properties=props) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +mid = 1 +subscribe_packet = mosq_test.gen_subscribe(mid, "test/topic", 0, proto_ver=5) +suback_packet = mosq_test.gen_suback(mid, 0, proto_ver=5) + +publish1_packet = mosq_test.gen_publish(topic="test/topic", qos=0, payload="12345678901234567890", proto_ver=5) +publish2_packet = mosq_test.gen_publish(topic="test/topic", qos=0, payload="67890", proto_ver=5) + +pingreq_packet = mosq_test.gen_pingreq() +pingresp_packet = mosq_test.gen_pingresp() + +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, port=port) + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet) + sock.send(publish1_packet) + # We shouldn't receive the publish here because it is > MAXIMUM_PACKET_SIZE + mosq_test.do_send_receive(sock, pingreq_packet, pingresp_packet) + mosq_test.do_send_receive(sock, publish2_packet, publish2_packet) + mosq_test.do_send_receive(sock, pingreq_packet, pingresp_packet) + rc = 0 +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index 3b5b6fe18d..95c0458f94 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -175,3 +175,5 @@ endif ./12-prop-server-keepalive.py ./12-prop-response-topic.py ./12-prop-response-topic-correlation-data.py + ./12-prop-maximum-packet-size-connect.py + ./12-prop-maximum-packet-size-publish.py diff --git a/test/broker/test.py b/test/broker/test.py index 526f58600c..e35627d68a 100755 --- a/test/broker/test.py +++ b/test/broker/test.py @@ -142,6 +142,8 @@ (1, './12-prop-server-keepalive.py'), (1, './12-prop-response-topic.py'), (1, './12-prop-response-topic-correlation-data.py'), + (1, './12-prop-maximum-packet-size-connect.py'), + (1, './12-prop-maximum-packet-size-publish.py'), ] ptest.run_tests(tests) From b9b8e0ff2a8ae4240a82629a7bb9df8b2834d8dd Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 19 Feb 2019 14:57:31 +0000 Subject: [PATCH 251/254] Add client support for outgoing maximum packet size. --- lib/actions.c | 42 ++++++++++++++-- lib/handle_connack.c | 1 + lib/mosquitto.h | 16 +++++++ test/lib/11-prop-oversize-packet.py | 59 +++++++++++++++++++++++ test/lib/Makefile | 1 + test/lib/c/11-prop-oversize-packet.c | 72 ++++++++++++++++++++++++++++ test/lib/c/Makefile | 1 + test/lib/test.py | 1 + test/unit/publish_test.c | 43 +++++++++++++++++ 9 files changed, 233 insertions(+), 3 deletions(-) create mode 100755 test/lib/11-prop-oversize-packet.py create mode 100644 test/lib/c/11-prop-oversize-packet.c create mode 100644 test/unit/publish_test.c diff --git a/lib/actions.c b/lib/actions.c index 3779318e68..cc3c422223 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -24,6 +24,7 @@ and the Eclipse Distribution License is available at #include "messages_mosq.h" #include "mqtt_protocol.h" #include "net_mosq.h" +#include "packet_mosq.h" #include "send_mosq.h" #include "util_mosq.h" @@ -43,6 +44,8 @@ int mosquitto_publish_v5(struct mosquitto *mosq, int *mid, const char *topic, in mosquitto_property local_property; bool have_topic_alias; int rc; + int tlen = 0; + uint32_t remaining_length; if(!mosq || qos<0 || qos>2) return MOSQ_ERR_INVAL; if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED; @@ -81,13 +84,24 @@ int mosquitto_publish_v5(struct mosquitto *mosq, int *mid, const char *topic, in return MOSQ_ERR_INVAL; } }else{ - if(mosquitto_validate_utf8(topic, strlen(topic))) return MOSQ_ERR_MALFORMED_UTF8; + tlen = strlen(topic); + if(mosquitto_validate_utf8(topic, tlen)) return MOSQ_ERR_MALFORMED_UTF8; if(payloadlen < 0 || payloadlen > MQTT_MAX_PAYLOAD) return MOSQ_ERR_PAYLOAD_SIZE; if(mosquitto_pub_topic_check(topic) != MOSQ_ERR_SUCCESS){ return MOSQ_ERR_INVAL; } } + if(mosq->maximum_packet_size > 0){ + remaining_length = 1 + 2+tlen + payloadlen + property__get_length_all(outgoing_properties); + if(qos > 0){ + remaining_length++; + } + if(packet__check_oversize(mosq, remaining_length)){ + return MOSQ_ERR_OVERSIZE_PACKET; + } + } + local_mid = mosquitto__mid_generate(mosq); if(mid){ *mid = local_mid; @@ -161,6 +175,8 @@ int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count mosquitto_property local_property; int i; int rc; + uint32_t remaining_length = 0; + int slen; if(!mosq || !sub_count || !sub) return MOSQ_ERR_INVAL; if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED; @@ -183,7 +199,16 @@ int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count for(i=0; imaximum_packet_size > 0){ + remaining_length += 2 + property__get_length_all(outgoing_properties); + if(packet__check_oversize(mosq, remaining_length)){ + return MOSQ_ERR_OVERSIZE_PACKET; + } } return send__subscribe(mosq, mid, sub_count, sub, qos|options, outgoing_properties); @@ -206,6 +231,8 @@ int mosquitto_unsubscribe_multiple(struct mosquitto *mosq, int *mid, int sub_cou mosquitto_property local_property; int rc; int i; + uint32_t remaining_length = 0; + int slen; if(!mosq) return MOSQ_ERR_INVAL; if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED; @@ -226,7 +253,16 @@ int mosquitto_unsubscribe_multiple(struct mosquitto *mosq, int *mid, int sub_cou for(i=0; imaximum_packet_size > 0){ + remaining_length += 2 + property__get_length_all(outgoing_properties); + if(packet__check_oversize(mosq, remaining_length)){ + return MOSQ_ERR_OVERSIZE_PACKET; + } } return send__unsubscribe(mosq, mid, sub_count, sub, outgoing_properties); diff --git a/lib/handle_connack.c b/lib/handle_connack.c index 1b13e28a31..1f8a940018 100644 --- a/lib/handle_connack.c +++ b/lib/handle_connack.c @@ -64,6 +64,7 @@ int handle__connack(struct mosquitto *mosq) mosquitto_property_read_byte(properties, MQTT_PROP_MAXIMUM_QOS, &mosq->maximum_qos, false); mosquitto_property_read_int16(properties, MQTT_PROP_RECEIVE_MAXIMUM, &mosq->send_maximum, false); mosquitto_property_read_int16(properties, MQTT_PROP_SERVER_KEEP_ALIVE, &mosq->keepalive, false); + mosquitto_property_read_int32(properties, MQTT_PROP_MAXIMUM_PACKET_SIZE, &mosq->maximum_packet_size, false); mosq->send_quota = mosq->send_maximum; diff --git a/lib/mosquitto.h b/lib/mosquitto.h index a11aa5dc90..7a5e41d3e8 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -743,6 +743,8 @@ libmosq_EXPORT int mosquitto_disconnect_v5(struct mosquitto *mosq, int reason_co * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8 * MOSQ_ERR_QOS_NOT_SUPPORTED - if the QoS is greater than that supported by * the broker. + * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than + * supported by the broker. * * See Also: * @@ -793,6 +795,8 @@ libmosq_EXPORT int mosquitto_publish(struct mosquitto *mosq, int *mid, const cha * MOSQ_ERR_PROTOCOL - if any property is invalid for use with PUBLISH. * MOSQ_ERR_QOS_NOT_SUPPORTED - if the QoS is greater than that supported by * the broker. + * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than + * supported by the broker. */ libmosq_EXPORT int mosquitto_publish_v5( struct mosquitto *mosq, @@ -825,6 +829,8 @@ libmosq_EXPORT int mosquitto_publish_v5( * 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_MALFORMED_UTF8 - if the topic is not valid UTF-8 + * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than + * supported by the broker. */ libmosq_EXPORT int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const char *sub, int qos); @@ -882,6 +888,8 @@ libmosq_EXPORT int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const c * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8 * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. * MOSQ_ERR_PROTOCOL - if any property is invalid for use with SUBSCRIBE. + * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than + * supported by the broker. */ libmosq_EXPORT int mosquitto_subscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, int qos, int options, const mosquitto_property *properties); @@ -936,6 +944,8 @@ libmosq_EXPORT int mosquitto_subscribe_v5(struct mosquitto *mosq, int *mid, cons * 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_MALFORMED_UTF8 - if a topic is not valid UTF-8 + * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than + * supported by the broker. */ int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, int qos, int options, const mosquitto_property *properties); @@ -958,6 +968,8 @@ int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count * 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_MALFORMED_UTF8 - if the topic is not valid UTF-8 + * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than + * supported by the broker. */ libmosq_EXPORT int mosquitto_unsubscribe(struct mosquitto *mosq, int *mid, const char *sub); @@ -984,6 +996,8 @@ libmosq_EXPORT int mosquitto_unsubscribe(struct mosquitto *mosq, int *mid, const * MOSQ_ERR_MALFORMED_UTF8 - if the topic is not valid UTF-8 * MOSQ_ERR_DUPLICATE_PROPERTY - if a property is duplicated where it is forbidden. * MOSQ_ERR_PROTOCOL - if any property is invalid for use with UNSUBSCRIBE. + * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than + * supported by the broker. */ libmosq_EXPORT int mosquitto_unsubscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, const mosquitto_property *properties); @@ -1013,6 +1027,8 @@ libmosq_EXPORT int mosquitto_unsubscribe_v5(struct mosquitto *mosq, int *mid, co * 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_MALFORMED_UTF8 - if a topic is not valid UTF-8 + * MOSQ_ERR_OVERSIZE_PACKET - if the resulting packet would be larger than + * supported by the broker. */ int mosquitto_unsubscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, const mosquitto_property *properties); diff --git a/test/lib/11-prop-oversize-packet.py b/test/lib/11-prop-oversize-packet.py new file mode 100755 index 0000000000..946b7139e0 --- /dev/null +++ b/test/lib/11-prop-oversize-packet.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python + +# Test whether a client publishing an oversize packet correctly. +# The client should try to publish a message that is too big, then the one below which is ok. +# It should also try to subscribe with a too large topic + +from mosq_test_helper import * + +port = mosq_test.get_lib_port() + +rc = 1 +keepalive = 60 +connect_packet = mosq_test.gen_connect("publish-qos0-test", keepalive=keepalive, proto_ver=5) +props = mqtt5_props.gen_uint32_prop(mqtt5_props.PROP_MAXIMUM_PACKET_SIZE, 30) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5, properties=props) + +bad_publish_packet = mosq_test.gen_publish("pub/test", qos=0, payload="0123456789012345678", proto_ver=5) +publish_packet = mosq_test.gen_publish("pub/test", qos=0, payload="012345678901234567", proto_ver=5) + +disconnect_packet = mosq_test.gen_disconnect() + + +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) + + if mosq_test.expect_packet(conn, "publish", publish_packet): + if mosq_test.expect_packet(conn, "disconnect", disconnect_packet): + rc = 0 + + conn.close() +finally: + client.terminate() + client.wait() + if rc: + (stdo, stde) = client.communicate() + print(stde) + sock.close() + +exit(rc) diff --git a/test/lib/Makefile b/test/lib/Makefile index 9e55b52afc..b9d9b96be9 100644 --- a/test/lib/Makefile +++ b/test/lib/Makefile @@ -61,6 +61,7 @@ ifeq ($(WITH_TLS),yes) #./08-ssl-fake-cacert.py $@/08-ssl-fake-cacert.test endif ./09-util-topic-tokenise.py $@/09-util-topic-tokenise.test + ./11-prop-oversize-packet.py $@/11-prop-oversize-packet.test ./11-prop-send-payload-format.py $@/11-prop-send-payload-format.test ./11-prop-send-content-type.py $@/11-prop-send-content-type.test diff --git a/test/lib/c/11-prop-oversize-packet.c b/test/lib/c/11-prop-oversize-packet.c new file mode 100644 index 0000000000..c96526f51a --- /dev/null +++ b/test/lib/c/11-prop-oversize-packet.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include +#include + +static int run = -1; +static int sent_mid = -1; + +void on_connect(struct mosquitto *mosq, void *obj, int rc) +{ + if(rc){ + exit(1); + }else{ + rc = mosquitto_subscribe(mosq, NULL, "0123456789012345678901234567890", 0); + if(rc != MOSQ_ERR_OVERSIZE_PACKET){ + printf("Fail on subscribe\n"); + exit(1); + } + + rc = mosquitto_unsubscribe(mosq, NULL, "0123456789012345678901234567890"); + if(rc != MOSQ_ERR_OVERSIZE_PACKET){ + printf("Fail on unsubscribe\n"); + exit(1); + } + + rc = mosquitto_publish(mosq, &sent_mid, "pub/test", strlen("0123456789012345678"), "0123456789012345678", 0, false); + if(rc != MOSQ_ERR_OVERSIZE_PACKET){ + printf("Fail on publish 1\n"); + exit(1); + } + rc = mosquitto_publish(mosq, &sent_mid, "pub/test", strlen("012345678901234567"), "012345678901234567", 0, false); + if(rc != MOSQ_ERR_SUCCESS){ + printf("Fail on publish 2\n"); + exit(1); + } + } +} + +void on_publish(struct mosquitto *mosq, void *obj, int mid) +{ + if(mid == sent_mid){ + mosquitto_disconnect(mosq); + run = 0; + }else{ + exit(1); + } +} + +int main(int argc, char *argv[]) +{ + int rc; + struct mosquitto *mosq; + + int port = atoi(argv[1]); + + mosquitto_lib_init(); + + mosq = mosquitto_new("publish-qos0-test", true, NULL); + mosquitto_int_option(mosq, MOSQ_OPT_PROTOCOL_VERSION, MQTT_PROTOCOL_V5); + mosquitto_connect_callback_set(mosq, on_connect); + mosquitto_publish_callback_set(mosq, on_publish); + + rc = mosquitto_connect(mosq, "localhost", port, 60); + + while(run == -1){ + rc = mosquitto_loop(mosq, -1, 1); + } + + mosquitto_lib_cleanup(); + return run; +} diff --git a/test/lib/c/Makefile b/test/lib/c/Makefile index d89ab9ab16..4eed7da0f8 100644 --- a/test/lib/c/Makefile +++ b/test/lib/c/Makefile @@ -43,6 +43,7 @@ SRC = \ 08-ssl-bad-cacert.c \ 08-ssl-fake-cacert.c \ 09-util-topic-tokenise.c \ + 11-prop-oversize-packet.c \ 11-prop-send-payload-format.c \ 11-prop-send-content-type.c diff --git a/test/lib/test.py b/test/lib/test.py index 68df885507..b6520ef590 100755 --- a/test/lib/test.py +++ b/test/lib/test.py @@ -41,6 +41,7 @@ (1, ['./08-ssl-connect-cert-auth.py', 'c/08-ssl-connect-cert-auth.test']), (1, ['./08-ssl-connect-no-auth.py', 'c/08-ssl-connect-no-auth.test']), (1, ['./09-util-topic-tokenise.py', 'c/09-util-topic-tokenise.test']), + (1, ['./11-prop-oversize-packet.py', 'c/11-prop-oversize-packet.test']), (1, ['./11-prop-send-payload-format.py', 'c/11-prop-send-payload-format.test']), (1, ['./11-prop-send-content-type.py', 'c/11-prop-send-content-type.test']), diff --git a/test/unit/publish_test.c b/test/unit/publish_test.c new file mode 100644 index 0000000000..6371db3ca9 --- /dev/null +++ b/test/unit/publish_test.c @@ -0,0 +1,43 @@ +#include +#include + +#include +#include + + +static void TEST_maximum_packet_size(void) +{ + struct mosquitto mosq; + int rc; + + memset(&mosq, 0, sizeof(struct mosquitto)); + + mosq.maximum_packet_size = 5; + rc = mosquitto_publish(&mosq, NULL, "topic/oversize", strlen("payload"), "payload", 0, 0); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_OVERSIZE_PACKET); +} + +/* ======================================================================== + * TEST SUITE SETUP + * ======================================================================== */ + +int init_publish_tests(void) +{ + CU_pSuite test_suite = NULL; + + test_suite = CU_add_suite("Publish", NULL, NULL); + if(!test_suite){ + printf("Error adding CUnit Publish test suite.\n"); + return 1; + } + + if(0 + || !CU_add_test(test_suite, "v5: Maximum packet size", TEST_maximum_packet_size) + ){ + + printf("Error adding Publish CUnit tests.\n"); + return 1; + } + + return 0; +} From 8fb4ad48b5fd871dad29bfce1b5209f58659f1a5 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 19 Feb 2019 15:53:15 +0000 Subject: [PATCH 252/254] Strings for new error codes. --- lib/mosquitto.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/mosquitto.c b/lib/mosquitto.c index 65b2152916..45690d65fd 100644 --- a/lib/mosquitto.c +++ b/lib/mosquitto.c @@ -361,6 +361,12 @@ const char *mosquitto_strerror(int mosq_errno) return "Malformed UTF-8"; case MOSQ_ERR_DUPLICATE_PROPERTY: return "Duplicate property in property list"; + case MOSQ_ERR_TLS_HANDSHAKE: + return "TLS handshake failed."; + case MOSQ_ERR_QOS_NOT_SUPPORTED: + return "Requested QoS not supported on server."; + case MOSQ_ERR_OVERSIZE_PACKET: + return "Packet larger than supported by the server."; default: return "Unknown error."; } From 1d17ced4494a514e55bcb571c97766b76cd81751 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 19 Feb 2019 15:57:20 +0000 Subject: [PATCH 253/254] Broker configurable max_packet_size Plus tests. --- lib/packet_mosq.c | 12 ++++++ man/mosquitto.conf.5.xml | 22 ++++++++++ mosquitto.conf | 15 +++++++ src/conf.c | 8 ++++ src/mosquitto_broker_internal.h | 1 + src/send_connack.c | 8 ++++ .../12-prop-maximum-packet-size-broker.py | 41 +++++++++++++++++++ test/broker/Makefile | 1 + test/broker/test.py | 1 + 9 files changed, 109 insertions(+) create mode 100755 test/broker/12-prop-maximum-packet-size-broker.py diff --git a/lib/packet_mosq.c b/lib/packet_mosq.c index 2dac17dc51..abc03922f1 100644 --- a/lib/packet_mosq.c +++ b/lib/packet_mosq.c @@ -36,6 +36,7 @@ and the Eclipse Distribution License is available at #include "read_handle.h" #ifdef WITH_BROKER # include "sys_tree.h" +# include "send_mosq.h" #else # define G_BYTES_RECEIVED_INC(A) # define G_BYTES_SENT_INC(A) @@ -381,6 +382,17 @@ int packet__read(struct mosquitto *mosq) * positive. */ mosq->in_packet.remaining_count *= -1; +#ifdef WITH_BROKER + if(db->config->max_packet_size > 0 && mosq->in_packet.remaining_length+1 > db->config->max_packet_size){ + log__printf(NULL, MOSQ_LOG_INFO, "Client %s sent too large packet %d, disconnecting.", mosq->id, mosq->in_packet.remaining_length+1); + if(mosq->protocol == mosq_p_mqtt5){ + send__disconnect(mosq, MQTT_RC_PACKET_TOO_LARGE, NULL); + } + return MOSQ_ERR_OVERSIZE_PACKET; + } +#else + // FIXME - client case for incoming message received from broker too large +#endif if(mosq->in_packet.remaining_length > 0){ mosq->in_packet.payload = mosquitto__malloc(mosq->in_packet.remaining_length*sizeof(uint8_t)); if(!mosq->in_packet.payload){ diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml index 30395759df..5b70e11352 100644 --- a/man/mosquitto.conf.5.xml +++ b/man/mosquitto.conf.5.xml @@ -474,6 +474,28 @@ Reloaded on reload signal. + + value + + For MQTT v5 clients, it is possible to have the + server send a "maximum packet size" value that will + instruct the client it will not accept MQTT packets + with size greater than bytes. + This applies to the full MQTT packet, not just the + payload. Setting this option to a positive value will + set the maximum packet size to that number of bytes. If + a client sends a packet which is larger than this + value, it will be disconnected. This applies to all + clients regardless of the protocol version they are + using, but v3.1.1 and earlier clients will of course + not have received the maximum packet size information. + Defaults to no limit. + Setting below 20 bytes is forbidden because it is + likely to interfere with normal client operation even + with small payloads. + Reloaded on reload signal. + + count diff --git a/mosquitto.conf b/mosquitto.conf index 550a3dd2ce..248417b79c 100644 --- a/mosquitto.conf +++ b/mosquitto.conf @@ -179,6 +179,21 @@ # allowable is 65535. Do not set below 10. #max_keepalive 65535 + +# For MQTT v5 clients, it is possible to have the server send a "maximum packet +# size" value that will instruct the client it will not accept MQTT packets +# with size greater than max_packet_size bytes. This applies to the full MQTT +# packet, not just the payload. Setting this option to a positive value will +# set the maximum packet size to that number of bytes. If a client sends a +# packet which is larger than this value, it will be disconnected. This applies +# to all clients regardless of the protocol version they are using, but v3.1.1 +# and earlier clients will of course not have received the maximum packet size +# information. Defaults to no limit. Setting below 20 bytes is forbidden +# because it is likely to interfere with ordinary client operation, even with +# very small payloads. +#max_packet_size 0 + + # ================================================================= # Default listener # ================================================================= diff --git a/src/conf.c b/src/conf.c index c8d22c07fb..9f061cf19f 100644 --- a/src/conf.c +++ b/src/conf.c @@ -214,6 +214,7 @@ static void config__init_reload(struct mosquitto_db *db, struct mosquitto__confi #endif config->log_timestamp = true; config->max_keepalive = 65535; + config->max_packet_size = 0; config->max_inflight_messages = 20; config->persistence = false; mosquitto__free(config->persistence_location); @@ -1503,6 +1504,13 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct return MOSQ_ERR_INVAL; } config->max_keepalive = tmp_int; + }else if(!strcmp(token, "max_packet_size")){ + if(conf__parse_int(&token, "max_packet_size", &tmp_int, saveptr)) return MOSQ_ERR_INVAL; + if(tmp_int < 20){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid max_packet_size value (%d).", tmp_int); + return MOSQ_ERR_INVAL; + } + config->max_packet_size = tmp_int; }else if(!strcmp(token, "max_queued_bytes")){ token = strtok_r(NULL, " ", &saveptr); if(token){ diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index 7d02f4327f..58e7d44afd 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -264,6 +264,7 @@ struct mosquitto__config { FILE *log_fptr; uint16_t max_inflight_messages; uint16_t max_keepalive; + uint32_t max_packet_size; uint32_t message_size_limit; bool persistence; char *persistence_location; diff --git a/src/send_connack.c b/src/send_connack.c index 927d4d1e3b..5b12bbc89d 100644 --- a/src/send_connack.c +++ b/src/send_connack.c @@ -54,6 +54,14 @@ int send__connack(struct mosquitto_db *db, struct mosquitto *context, int ack, i return rc; } } + if(db->config->max_packet_size > 0){ + rc = mosquitto_property_add_int32(&connack_props, MQTT_PROP_MAXIMUM_PACKET_SIZE, db->config->max_packet_size); + if(rc){ + mosquitto_property_free_all(&connack_props); + return rc; + } + } + /* FIXME - disable support until available */ rc = mosquitto_property_add_byte(&connack_props, MQTT_PROP_SHARED_SUB_AVAILABLE, 0); if(rc){ diff --git a/test/broker/12-prop-maximum-packet-size-broker.py b/test/broker/12-prop-maximum-packet-size-broker.py new file mode 100755 index 0000000000..7d76d8683c --- /dev/null +++ b/test/broker/12-prop-maximum-packet-size-broker.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +# Check whether the broker disconnects a client nicely when they send a too large packet. + +from mosq_test_helper import * + +def write_config(filename, port): + with open(filename, 'w') as f: + f.write("port %d\n" % (port)) + f.write("max_packet_size 30\n") + +port = mosq_test.get_port() +conf_file = os.path.basename(__file__).replace('.py', '.conf') +write_config(conf_file, port) + +rc = 1 + +keepalive = 10 +connect_packet = mosq_test.gen_connect("test", proto_ver=5, keepalive=keepalive) +props = mqtt5_props.gen_uint32_prop(mqtt5_props.PROP_MAXIMUM_PACKET_SIZE, 30) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5, properties=props) + +publish_packet = mosq_test.gen_publish("test/topic", qos=0, payload="0123456789012345678901234567890", proto_ver=5) +disconnect_packet = mosq_test.gen_disconnect(reason_code=149, proto_ver=5) + +broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port, use_conf=True) + +try: + sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port) + mosq_test.do_send_receive(sock, publish_packet, disconnect_packet, "disconnect") + rc = 0 +finally: + broker.terminate() + broker.wait() + os.remove(conf_file) + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index 95c0458f94..6901f11be6 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -175,5 +175,6 @@ endif ./12-prop-server-keepalive.py ./12-prop-response-topic.py ./12-prop-response-topic-correlation-data.py + ./12-prop-maximum-packet-size-broker.py ./12-prop-maximum-packet-size-connect.py ./12-prop-maximum-packet-size-publish.py diff --git a/test/broker/test.py b/test/broker/test.py index e35627d68a..fdef41d731 100755 --- a/test/broker/test.py +++ b/test/broker/test.py @@ -142,6 +142,7 @@ (1, './12-prop-server-keepalive.py'), (1, './12-prop-response-topic.py'), (1, './12-prop-response-topic-correlation-data.py'), + (1, './12-prop-maximum-packet-size-broker.py'), (1, './12-prop-maximum-packet-size-connect.py'), (1, './12-prop-maximum-packet-size-publish.py'), ] From c3c8c99f5d4ef57f8cb82895b163ee98fb17f18c Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 21 Feb 2019 08:31:54 +0000 Subject: [PATCH 254/254] Fix dropping oversize messages for QoS>0. --- src/database.c | 16 +++-- ...2-prop-maximum-packet-size-publish-qos1.py | 54 +++++++++++++++++ ...2-prop-maximum-packet-size-publish-qos2.py | 60 +++++++++++++++++++ test/broker/Makefile | 2 + test/broker/test.py | 2 + 5 files changed, 129 insertions(+), 5 deletions(-) create mode 100755 test/broker/12-prop-maximum-packet-size-publish-qos1.py create mode 100755 test/broker/12-prop-maximum-packet-size-publish-qos2.py diff --git a/src/database.c b/src/database.c index 591684da12..0755b174e8 100644 --- a/src/database.c +++ b/src/database.c @@ -898,7 +898,7 @@ int db__message_release(struct mosquitto_db *db, struct mosquitto *context, uint int db__message_write(struct mosquitto_db *db, struct mosquitto *context) { int rc; - struct mosquitto_client_msg *tail, *last = NULL; + struct mosquitto_client_msg *tail, *last = NULL, *tmp; uint16_t mid; int retries; int retain; @@ -959,13 +959,16 @@ int db__message_write(struct mosquitto_db *db, struct mosquitto *context) tail->timestamp = mosquitto_time(); tail->dup = 1; /* Any retry attempts are a duplicate. */ tail->state = mosq_ms_wait_for_puback; + + last = tail; + tail = tail->next; }else if(rc == MOSQ_ERR_OVERSIZE_PACKET){ + tmp = tail->next; db__message_remove(db, context, &tail, last); + tail = tmp; }else{ return rc; } - last = tail; - tail = tail->next; break; case mosq_ms_publish_qos2: @@ -974,13 +977,16 @@ int db__message_write(struct mosquitto_db *db, struct mosquitto *context) tail->timestamp = mosquitto_time(); tail->dup = 1; /* Any retry attempts are a duplicate. */ tail->state = mosq_ms_wait_for_pubrec; + + last = tail; + tail = tail->next; }else if(rc == MOSQ_ERR_OVERSIZE_PACKET){ + tmp = tail->next; db__message_remove(db, context, &tail, last); + tail = tmp; }else{ return rc; } - last = tail; - tail = tail->next; break; case mosq_ms_send_pubrec: diff --git a/test/broker/12-prop-maximum-packet-size-publish-qos1.py b/test/broker/12-prop-maximum-packet-size-publish-qos1.py new file mode 100755 index 0000000000..87388bdba1 --- /dev/null +++ b/test/broker/12-prop-maximum-packet-size-publish-qos1.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python + +# Test whether maximum packet size is honoured on a PUBLISH to a client +# MQTTv5 + +from mosq_test_helper import * + +rc = 1 + +keepalive = 10 +props = mqtt5_props.gen_uint32_prop(mqtt5_props.PROP_MAXIMUM_PACKET_SIZE, 20) +connect_packet = mosq_test.gen_connect("test", proto_ver=5, keepalive=keepalive, properties=props) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +mid = 1 +subscribe_packet = mosq_test.gen_subscribe(mid, "test/topic", 1, proto_ver=5) +suback_packet = mosq_test.gen_suback(mid, 1, proto_ver=5) + +mid=1 +publish1_packet = mosq_test.gen_publish(topic="test/topic", mid=mid, qos=1, payload="12345678901234567890", proto_ver=5) +puback1_packet = mosq_test.gen_puback(mid, proto_ver=5) + +mid=2 +publish2_packet = mosq_test.gen_publish(topic="test/topic", mid=mid, qos=1, payload="7890", proto_ver=5) +puback2_packet = mosq_test.gen_puback(mid, proto_ver=5) + +pingreq_packet = mosq_test.gen_pingreq() +pingresp_packet = mosq_test.gen_pingresp() + +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, port=port) + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet) + + mosq_test.do_send_receive(sock, publish1_packet, puback1_packet, "puback 1") + + # We shouldn't receive the publish here because it is > MAXIMUM_PACKET_SIZE + mosq_test.do_send_receive(sock, pingreq_packet, pingresp_packet) + + mosq_test.do_send_receive(sock, publish2_packet, puback2_packet, "puback 2") + + if mosq_test.expect_packet(sock, "publish2", publish2_packet): + rc = 0 +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/12-prop-maximum-packet-size-publish-qos2.py b/test/broker/12-prop-maximum-packet-size-publish-qos2.py new file mode 100755 index 0000000000..05e38e8d04 --- /dev/null +++ b/test/broker/12-prop-maximum-packet-size-publish-qos2.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python + +# Test whether maximum packet size is honoured on a PUBLISH to a client +# MQTTv5 + +from mosq_test_helper import * + +rc = 1 + +keepalive = 10 +props = mqtt5_props.gen_uint32_prop(mqtt5_props.PROP_MAXIMUM_PACKET_SIZE, 20) +connect_packet = mosq_test.gen_connect("test", proto_ver=5, keepalive=keepalive, properties=props) +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + +mid = 1 +subscribe_packet = mosq_test.gen_subscribe(mid, "test/topic", 2, proto_ver=5) +suback_packet = mosq_test.gen_suback(mid, 2, proto_ver=5) + +mid=1 +publish1_packet = mosq_test.gen_publish(topic="test/topic", mid=mid, qos=2, payload="12345678901234567890", proto_ver=5) +pubrec1_packet = mosq_test.gen_pubrec(mid, proto_ver=5) +pubrel1_packet = mosq_test.gen_pubrel(mid, proto_ver=5) +pubcomp1_packet = mosq_test.gen_pubcomp(mid, proto_ver=5) + +mid=2 +publish2_packet = mosq_test.gen_publish(topic="test/topic", mid=mid, qos=2, payload="7890", proto_ver=5) +pubrec2_packet = mosq_test.gen_pubrec(mid, proto_ver=5) +pubrel2_packet = mosq_test.gen_pubrel(mid, proto_ver=5) +pubcomp2_packet = mosq_test.gen_pubcomp(mid, proto_ver=5) + +pingreq_packet = mosq_test.gen_pingreq() +pingresp_packet = mosq_test.gen_pingresp() + +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, port=port) + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet) + + mosq_test.do_send_receive(sock, publish1_packet, pubrec1_packet, "pubrec 1") + mosq_test.do_send_receive(sock, pubrel1_packet, pubcomp1_packet, "pubcomp 1") + + # We shouldn't receive the publish here because it is > MAXIMUM_PACKET_SIZE + mosq_test.do_send_receive(sock, pingreq_packet, pingresp_packet) + + mosq_test.do_send_receive(sock, publish2_packet, pubrec2_packet, "pubrec 2") + mosq_test.do_send_receive(sock, pubrel2_packet, pubcomp2_packet, "pubcomp 2") + + if mosq_test.expect_packet(sock, "publish2", publish2_packet): + rc = 0 +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde) + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index 6901f11be6..440c38f24f 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -178,3 +178,5 @@ endif ./12-prop-maximum-packet-size-broker.py ./12-prop-maximum-packet-size-connect.py ./12-prop-maximum-packet-size-publish.py + ./12-prop-maximum-packet-size-publish-qos1.py + ./12-prop-maximum-packet-size-publish-qos2.py diff --git a/test/broker/test.py b/test/broker/test.py index fdef41d731..f93d9c31c3 100755 --- a/test/broker/test.py +++ b/test/broker/test.py @@ -145,6 +145,8 @@ (1, './12-prop-maximum-packet-size-broker.py'), (1, './12-prop-maximum-packet-size-connect.py'), (1, './12-prop-maximum-packet-size-publish.py'), + (1, './12-prop-maximum-packet-size-publish-qos1.py'), + (1, './12-prop-maximum-packet-size-publish-qos2.py'), ] ptest.run_tests(tests)