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 686006fc..bb2077c7 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 bc6eebfe..915605d5 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 d537e776..48f0c89c 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 5e50dbe5..9fb36d61 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -22,7 +22,7 @@ Contributors: #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 17b53be0..ad56dda0 100644 --- a/lib/handle_ping.c +++ b/lib/handle_ping.c @@ -28,7 +28,7 @@ Contributors: #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 37788456..a6586f8f 100644 --- a/lib/handle_pubackcomp.c +++ b/lib/handle_pubackcomp.c @@ -28,7 +28,7 @@ Contributors: #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 59eea1b7..3f79d506 100644 --- a/lib/handle_pubrec.c +++ b/lib/handle_pubrec.c @@ -28,7 +28,7 @@ Contributors: #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 56660987..7c1f137c 100644 --- a/lib/handle_pubrel.c +++ b/lib/handle_pubrel.c @@ -28,7 +28,7 @@ Contributors: #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 6297bb10..357ef5c9 100644 --- a/lib/handle_unsuback.c +++ b/lib/handle_unsuback.c @@ -28,7 +28,7 @@ Contributors: #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 4884bacb..e148e1ed 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 d593c7b2..a84d10c5 100644 --- a/lib/net_mosq.c +++ b/lib/net_mosq.c @@ -64,7 +64,7 @@ Contributors: #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 bb2077c7..ddfaef49 100644 --- a/lib/packet_mosq.c +++ b/lib/packet_mosq.c @@ -30,7 +30,7 @@ Contributors: #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 274a4da5..fab8b7dd 100644 --- a/lib/read_handle.c +++ b/lib/read_handle.c @@ -24,7 +24,7 @@ Contributors: #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 458f522f..59802c9b 100644 --- a/lib/send_connect.c +++ b/lib/send_connect.c @@ -27,7 +27,7 @@ Contributors: #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 0cfea276..e5009d69 100644 --- a/lib/send_disconnect.c +++ b/lib/send_disconnect.c @@ -25,7 +25,7 @@ Contributors: #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 ee544e3e..3c58d724 100644 --- a/lib/send_mosq.c +++ b/lib/send_mosq.c @@ -30,7 +30,7 @@ Contributors: #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 e9aeeef8..124fc85f 100644 --- a/lib/send_publish.c +++ b/lib/send_publish.c @@ -29,7 +29,7 @@ Contributors: #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 c60ca0f2..6fa4720d 100644 --- a/lib/send_subscribe.c +++ b/lib/send_subscribe.c @@ -27,7 +27,7 @@ Contributors: #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 fb66e88c..18317a1d 100644 --- a/lib/send_unsubscribe.c +++ b/lib/send_unsubscribe.c @@ -26,7 +26,7 @@ Contributors: #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 3e9495ff..fe5a0443 100644 --- a/lib/will_mosq.c +++ b/lib/will_mosq.c @@ -28,7 +28,7 @@ Contributors: #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 f5e989ff..e32ba839 100644 --- a/src/conf.c +++ b/src/conf.c @@ -44,7 +44,7 @@ Contributors: #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 43da9a16..4fc04a28 100644 --- a/src/conf_includedir.c +++ b/src/conf_includedir.c @@ -44,7 +44,7 @@ Contributors: #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 52e78e4f..9451de85 100644 --- a/src/handle_connack.c +++ b/src/handle_connack.c @@ -21,7 +21,7 @@ Contributors: #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 87964456..c3e747b3 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -20,7 +20,7 @@ Contributors: #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 54976afc..a6e990ef 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -21,7 +21,7 @@ Contributors: #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 a0f00046..76b263ff 100644 --- a/src/handle_unsubscribe.c +++ b/src/handle_unsubscribe.c @@ -21,7 +21,7 @@ Contributors: #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 64f8bdc5..ca3e2d64 100644 --- a/src/net.c +++ b/src/net.c @@ -45,7 +45,7 @@ Contributors: #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 ac448aab..9d032ed2 100644 --- a/src/read_handle.c +++ b/src/read_handle.c @@ -21,7 +21,7 @@ Contributors: #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 12b20724..2a15ae3d 100644 --- a/src/send_connack.c +++ b/src/send_connack.c @@ -17,7 +17,7 @@ Contributors: #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 adaeb16b..7bbe72fa 100644 --- a/src/send_suback.c +++ b/src/send_suback.c @@ -17,7 +17,7 @@ Contributors: #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 1ab02a9b..7c0dca32 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 e148e1ed..74cfe915 100644 --- a/lib/mqtt_protocol.h +++ b/lib/mqtt_protocol.h @@ -25,6 +25,10 @@ Contributors: #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 @@ Contributors: #define PINGREQ 0xC0 #define PINGRESP 0xD0 #define DISCONNECT 0xE0 +#define AUTH 0xF0 -#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 +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 */ + + 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 74cfe915..93c7b3e1 100644 --- a/lib/mqtt_protocol.h +++ b/lib/mqtt_protocol.h @@ -22,10 +22,9 @@ Contributors: #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 59802c9b..ef83a143 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 c3e747b3..55310459 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 93c7b3e1..bf8912e1 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 d5d37256..8622cbca 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 8c729b87..9fb38889 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 3d91ed0f..e1180447 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 7c1f137c..4e4bf048 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 5baa2f15..938382c3 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 de82ec3d..d416eccb 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 ab221c7d..0d6fc314 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 01f9c979..1b83ac81 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 3b2e2591..6f3286e1 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 76b263ff..4a5bf680 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 ddfaef49..78916568 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 915605d5..56e27e2d 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 dd9f7180..5ec32302 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 ef83a143..2295e9b0 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 55310459..d03d1473 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 0716fe19..83eeeafd 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 d416eccb..b49bcff7 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 2a15ae3d..3bb6ea7c 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 78916568..f2d2a242 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 f2d2a242..dd29968a 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 56e27e2d..f7bcdeb1 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 00000000..73450d58 --- /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 00000000..7fea9a76 --- /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 dab82a48..c4d53786 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 227f6623..dd6a68a4 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 d03d1473..2384baab 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -23,6 +23,7 @@ Contributors: #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 a6e990ef..a6a10d4f 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -24,6 +24,7 @@ Contributors: #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 48f0c89c..603e9f15 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 b768c81b..4d0f2833 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 00000000..7acb7151 --- /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 dd29968a..e7ffe0b4 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 c4d53786..d14ac494 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 dd6a68a4..f981e2e2 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 | 18 ++- 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, 342 insertions(+), 14 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 1ae86973..0bf99128 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,15 @@ -*.o -*.so -*.exe *.db +*.gcda +*.gcno +*.exe +*.o +*.old +*.pyc +*.so +*.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 7acb7151..3065f124 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 f7bcdeb1..5b5b5c69 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 cf94ea73..e3f6cdf6 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 00000000..4d8d7388 --- /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 00000000..60a0d215 --- /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 00000000..3071fead --- /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 60a0d215..2a224f5e 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 2a224f5e..cb29befd 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 cb29befd..25b3e0d7 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 3065f124..9e31974f 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 2384baab..e2780daf 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 a6a10d4f..e9aa7016 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 6f3286e1..e2f49e37 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 4a5bf680..3bb8bd4a 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 4d8d7388..e6e679c0 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 25b3e0d7..05439e25 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 7ee60559..d188d3db 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 e6e679c0..226d6caf 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 3071fead..9c23ee08 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 00000000..532df519 --- /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 226d6caf..3ae0c526 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 05439e25..c8ebe032 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 9c23ee08..22a00459 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 c8ebe032..07a1128b 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 9e31974f..1fce5950 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 5b5b5c69..567ffcec 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 3ae0c526..d67b36db 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 07a1128b..95654e3f 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 00000000..a9986d46 --- /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 d67b36db..038c5a23 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 95654e3f..cf2b92ca 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 a9986d46..bf53499b 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 22a00459..cb25e3e3 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 bf53499b..24d5056e 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 24d5056e..ddb8d3c5 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 d188d3db..b08c9a43 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 cb25e3e3..e89fa4d2 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 532df519..a96ebaea 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 cf2b92ca..76978050 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 9512d2eb..4495849d 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 317333bf..c8f966a6 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 ff99e4a3..d1a5f207 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 c04f3c3f..35645952 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 48195b98..3070e7ca 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 73450d58..e8d10a42 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -26,12 +26,14 @@ Contributors: #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 e8d10a42..a8dda778 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -29,6 +29,7 @@ Contributors: 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 a96ebaea..09f1a1a4 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 eab1d99a..9c3261de 100644 --- a/lib/mosquitto.c +++ b/lib/mosquitto.c @@ -27,6 +27,7 @@ Contributors: #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 bf8912e1..b5807f47 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 99e2543b..00000000 --- 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 229eb641..f448d7e4 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 8a8e85b4..00000000 --- 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 323d23ed..0484fedd 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 2decafcb..00000000 --- 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 e5a85e5f..4d9e86f0 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 | 363 ++++++++++++++++++---------------- 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, 650 insertions(+), 175 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 4d0f2833..b4b4e4d5 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 d1a5f207..45e3b825 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 1fce5950..dd15d673 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 567ffcec..8c44d6ab 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 a8dda778..76b6a50e 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -26,7 +26,7 @@ Contributors: #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); - break; - - case PROP_CONTENT_TYPE: - rc = packet__read_string(packet, &str, &slen); - if(rc) return rc; - *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; /* 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; /* uint16, string len */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Correlation data: %s", str); + property->value.i32 = uint32; break; case PROP_SUBSCRIPTION_IDENTIFIER: rc = packet__read_varint(packet, &varint, &byte_count); if(rc) return rc; *len -= byte_count; - log__printf(NULL, MOSQ_LOG_DEBUG, "Subscription identifier: %d", varint); - 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); + property->value.varint = varint; break; + case PROP_CONTENT_TYPE: + case PROP_RESPONSE_TOPIC: 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; - - 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; - 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; - - 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, &uint32); - if(rc) return rc; - *len -= 4; /* uint32 */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Will delay interval: %d", uint32); - 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; /* 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; /* 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); + rc = packet__read_string(packet, &str1, &slen1); if(rc) return rc; - *len -= 2 - slen; /* uint16, string len */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Reason string: %s", str); + *len -= 2 - slen1; /* uint16, string len */ + property->value.s.v = str1; + property->value.s.len = slen1; break; - case PROP_RECEIVE_MAXIMUM: - rc = packet__read_uint16(packet, &uint16); + case PROP_CORRELATION_DATA: + rc = packet__read_binary(packet, (uint8_t **)&str1, &slen1); if(rc) return rc; - *len -= 2; /* uint16 */ - log__printf(NULL, MOSQ_LOG_DEBUG, "Receive maximum: %d", uint16); - break; - - 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); + *len -= 2 - slen1; /* uint16, binary len */ + property->value.bin.v = str1; + property->value.bin.len = slen1; break; case PROP_USER_PROPERTY: - rc = packet__read_string(packet, &str, &slen); + rc = packet__read_string(packet, &str1, &slen1); if(rc) return rc; - *len -= 2 - slen; /* uint16, string len */ - log__printf(NULL, MOSQ_LOG_DEBUG, "User property name: %s", str); + *len -= 2 - slen1; /* uint16, string len */ - 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; + rc = packet__read_string(packet, &str2, &slen2); + if(rc){ + mosquitto__free(str1); + return rc; + } + *len -= 2 - slen2; /* uint16, string len */ - 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); + property->name.v = str1; + property->name.len = slen1; + property->value.s.v = str2; + property->value.s.len = slen2; break; default: log__printf(NULL, MOSQ_LOG_DEBUG, "Unsupported property type: %d", byte); - return 1; + return MOSQ_ERR_MALFORMED_PACKET; } return MOSQ_ERR_SUCCESS; } -int property__read_all(struct mosquitto__packet *packet) +int property__read_all(struct mosquitto__packet *packet, struct mqtt5__property **properties) { 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; rc = packet__read_varint(packet, &proplen, NULL); if(rc) return rc; + *properties = NULL; + + /* The order of properties must be preserved for some types, so keep the + * same order for all */ while(proplen > 0){ - rc = property__read(packet, &proplen); - if(rc) return rc; + 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; + } } return MOSQ_ERR_SUCCESS; } + + +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: + mosquitto__free((*property)->value.s.v); + break; + + 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: + 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: + /* Nothing to free */ + break; + } + + free(*property); + *property = NULL; +} + + +void property__free_all(struct mqtt5__property **property) +{ + struct mqtt5__property *p, *next; + + p = *property; + while(p){ + next = p->next; + property__free(&p); + p = next; + } + *property = NULL; +} diff --git a/lib/property_mosq.h b/lib/property_mosq.h index 7fea9a76..6ce67d83 100644 --- a/lib/property_mosq.h +++ b/lib/property_mosq.h @@ -19,6 +19,28 @@ Contributors: #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 e2780daf..5b3e0b47 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 e9aa7016..2b03ef68 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 038c5a23..95249076 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 76978050..f0234bf4 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 7287168e..9fb9a5b0 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 00000000..bad77857 --- /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 00000000..f4b7c97a --- /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 e89fa4d2..dea045a4 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 76b6a50e..6ae32c93 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 bad77857..f5c2fc9d 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 6ae32c93..505048b9 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 f5c2fc9d..2a6ae7c0 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 505048b9..c6a50ae0 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 2a6ae7c0..fca34206 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 | 153 ++++++++++---------------------------------- 1 file changed, 33 insertions(+), 120 deletions(-) diff --git a/lib/property_mosq.c b/lib/property_mosq.c index c6a50ae0..26baa4b1 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,122 +165,53 @@ 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){ + if( 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){ + }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_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; - }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; } } + 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; + } + 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 fca34206..1d803e4b 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 1d803e4b..0cfbceb3 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 c2c2bcf8..9a9f5562 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 844bc6e0..02ac6087 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 b4b4e4d5..d9304c32 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 f981e2e2..e9bf16a1 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 0cfbceb3..9022e734 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 5b3e0b47..d9b489a8 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 26baa4b1..f41fb3da 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 6ce67d83..27301eac 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 2295e9b0..5f6b3806 100644 --- a/lib/send_connect.c +++ b/lib/send_connect.c @@ -29,6 +29,7 @@ Contributors: #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 e5009d69..18c5b924 100644 --- a/lib/send_disconnect.c +++ b/lib/send_disconnect.c @@ -25,12 +25,18 @@ Contributors: #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 3c58d724..ca01c010 100644 --- a/lib/send_mosq.c +++ b/lib/send_mosq.c @@ -34,6 +34,7 @@ Contributors: #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 35645952..1bac1d30 100644 --- a/lib/send_mosq.h +++ b/lib/send_mosq.h @@ -17,9 +17,10 @@ Contributors: #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 124fc85f..3df0909b 100644 --- a/lib/send_publish.c +++ b/lib/send_publish.c @@ -33,6 +33,7 @@ Contributors: #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 ec0eacab..8e6e5eb6 100644 --- a/lib/send_subscribe.c +++ b/lib/send_subscribe.c @@ -29,6 +29,7 @@ Contributors: #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 d9b489a8..18fd59f0 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 3bb8bd4a..03848d8d 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 3bb6ea7c..00a39471 100644 --- a/src/send_connack.c +++ b/src/send_connack.c @@ -20,6 +20,7 @@ Contributors: #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 7bbe72fa..b1718872 100644 --- a/src/send_suback.c +++ b/src/send_suback.c @@ -20,6 +20,7 @@ Contributors: #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 f41fb3da..d5ce5631 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 27301eac..7f7ea548 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 9022e734..4a8fa75d 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 603e9f15..cae15b03 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 d9304c32..52d04714 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 56d8cb05..4909862c 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 00000000..dccec306 --- /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 3dc19e0b..00000000 --- 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 f448d7e4..bf5a931f 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 12c512fd..00000000 --- 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 0484fedd..9678766a 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 4b1776aa..00000000 --- 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 4d9e86f0..5761d9d4 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 95249076..fba2ce32 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 dea045a4..1b920ed6 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 00000000..9b614fdf --- /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 d5ce5631..74fbd662 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 | 98 ++++++++++++++++++++++++++++--------- 3 files changed, 79 insertions(+), 25 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d14ac494..ba503f60 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 e9bf16a1..07d8f113 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 9b614fdf..c843f861 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) { - 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"); + /* 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("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(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("#", "$SYS/bar"); - no_match_helper("$BOB/bar", "$SYS/bar"); +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_INVAL, "test/6/#", "test/3"); + + 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_INVAL, "foo/+/#", "fo2/bar/baz"); + + no_match_helper(MOSQ_ERR_INVAL, "/#", "foo/bar"); + no_match_helper(MOSQ_ERR_INVAL, "/#a", "foo/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 46ffb6db..6f3f3ac5 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 07d8f113..16191e20 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 dd15d673..a07a9f54 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 8c44d6ab..04855327 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 74fbd662..5bb7331a 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 7f7ea548..9e913f99 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 a07a9f54..1b0abeeb 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 fba2ce32..611e2098 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 4a8fa75d..97a8182c 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 00000000..4fca1d5c --- /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 1b920ed6..9e29f391 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 | 51 ++++++++++++++++++++++------------- 2 files changed, 60 insertions(+), 44 deletions(-) diff --git a/lib/util_topic.c b/lib/util_topic.c index dccec306..45a2d311 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 c843f861..6e5934a7 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_SUCCESS, "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_SUCCESS, "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_SUCCESS, "#", "$SYS/bar"); + no_match_helper(MOSQ_ERR_SUCCESS, "$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"); - no_match_helper(MOSQ_ERR_INVAL, "foo+", "fooa"); - - no_match_helper(MOSQ_ERR_INVAL, "test/6/#", "test/3"); - - 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_INVAL, "foo/+/#", "fo2/bar/baz"); - - no_match_helper(MOSQ_ERR_INVAL, "/#", "foo/bar"); - no_match_helper(MOSQ_ERR_INVAL, "/#a", "foo/bar"); - - - no_match_helper(MOSQ_ERR_INVAL, "#", "$SYS/bar"); - no_match_helper(MOSQ_ERR_INVAL, "$BOB/bar", "$SYS/bar"); } /* ======================================================================== @@ -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 4fca1d5c..dae52829 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 6e5934a7..39900826 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 9ca1aa23..2fac25ba 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 5f6b3806..5231de78 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 fe5a0443..7062b512 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 1d3ae163..549c05fb 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 18fd59f0..2dfbd0ad 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 c8f966a6..7a48f3cc 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 f6c50b8b..2a737d9b 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 1b0abeeb..9297afe6 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 04855327..22728cd7 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 1bac1d30..7ea0b12b 100644 --- a/lib/send_mosq.h +++ b/lib/send_mosq.h @@ -21,7 +21,7 @@ Contributors: 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 3df0909b..2cd703c7 100644 --- a/lib/send_publish.c +++ b/lib/send_publish.c @@ -37,7 +37,7 @@ Contributors: #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 a3f2ed7d..77ccf341 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 549c05fb..f4fe9a43 100644 --- a/src/context.c +++ b/src/context.c @@ -22,6 +22,7 @@ Contributors: #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 d2f482d1..1595be21 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 @@ error: 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 3070e7ca..0124ce60 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 2dfbd0ad..df4b3074 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 @@ handle_connect_error: 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 2b03ef68..0aa780b3 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 @@ process_bad_message: 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 e2f49e37..7585c225 100644 --- a/src/handle_subscribe.c +++ b/src/handle_subscribe.c @@ -22,6 +22,7 @@ Contributors: #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 0b7b792a..ccb53651 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 67a2924c..de4cb121 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 7a93f984..cccd04ad 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 ebece86b..582e8f54 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 b5807f47..62befba6 100644 --- a/lib/mqtt_protocol.h +++ b/lib/mqtt_protocol.h @@ -45,6 +45,9 @@ Contributors: #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 5bb7331a..b4f44c84 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -26,6 +26,9 @@ Contributors: #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 9e913f99..1253063a 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 df4b3074..c0e42489 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 0aa780b3..f5850a32 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 7585c225..a134bf55 100644 --- a/src/handle_subscribe.c +++ b/src/handle_subscribe.c @@ -21,6 +21,7 @@ Contributors: #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 97a8182c..86fb5ad6 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 dae52829..5eb9caee 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 9d0a01cd..b3125017 100644 --- a/lib/handle_connack.c +++ b/lib/handle_connack.c @@ -22,35 +22,46 @@ Contributors: #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 a6586f8f..8f5f0a30 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 f8092f89..5a253aa0 100644 --- a/lib/handle_publish.c +++ b/lib/handle_publish.c @@ -23,8 +23,10 @@ Contributors: #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 3f79d506..227d27be 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 4e4bf048..2630f1f2 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 d6e3d19c..512415f2 100644 --- a/lib/handle_suback.c +++ b/lib/handle_suback.c @@ -26,7 +26,9 @@ Contributors: #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 357ef5c9..0c403175 100644 --- a/lib/handle_unsuback.c +++ b/lib/handle_unsuback.c @@ -31,6 +31,7 @@ Contributors: #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 0124ce60..fd289b5f 100644 --- a/src/handle_connack.c +++ b/src/handle_connack.c @@ -28,20 +28,30 @@ Contributors: 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 c0e42489..6a4680ae 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 @@ handle_connect_error: 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 a134bf55..e592ec83 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 03848d8d..5a130684 100644 --- a/src/handle_unsubscribe.c +++ b/src/handle_unsubscribe.c @@ -24,18 +24,14 @@ Contributors: #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 8f5f0a30..e9f0d4f4 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 5a253aa0..44257c69 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 227d27be..1d6401b0 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 2630f1f2..7ed08010 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 512415f2..2b23e134 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 0c403175..1e7fae8d 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 f5850a32..b51949f5 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 e592ec83..ebab3156 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 5a130684..1838427d 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 cae15b03..dbbf2ca6 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 52d04714..9dc330c4 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 00000000..ef2b1f83 --- /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 fab8b7dd..011c083c 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 887746de..8bf20b5f 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 ba503f60..97f1d3b4 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 16191e20..93b2ea4a 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 00000000..1941fb95 --- /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 de4cb121..f9970a78 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 9d032ed2..a283ca0e 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 5231de78..4bc75989 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 18c5b924..61c979a9 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 ca01c010..f944c6a9 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 2cd703c7..4f54acba 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 8e6e5eb6..c950b12a 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 e1dcbfe2..db59fc98 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 1838427d..56da9957 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 00a39471..ba19b305 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 b1718872..a276f81c 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 00000000..4d5201a1 --- /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 0b4fee08..0bed1290 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 27b0df6d..dad3b42d 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -8,6 +8,7 @@ max_running = 10 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 a28f2eb1..43d26369 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 00000000..ef3c9009 --- /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 00000000..2d08f43d --- /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 00000000..796ed821 --- /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 00000000..64d71963 --- /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 0bed1290..7466f052 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 dad3b42d..71ffdf75 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -29,9 +29,13 @@ tests = [ (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 43d26369..972a81c8 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 b51949f5..20c51659 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 00000000..5c9670a7 --- /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 7466f052..be9cb84b 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 71ffdf75..920dee7b 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -32,6 +32,7 @@ tests = [ (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 972a81c8..18cdec87 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 00000000..bdd5b1b3 --- /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 4bc75989..841bf936 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 | 297 ++++++++++++++++++++++++++++++------------------ 1 file changed, 188 insertions(+), 109 deletions(-) diff --git a/lib/mosquitto.h b/lib/mosquitto.h index 45e3b825..374c67e6 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. - * - * Returns: - * The socket for the mosquitto client or -1 on failure. - */ -libmosq_EXPORT int mosquitto_socket(struct mosquitto *mosq); +/* ====================================================================== + * + * Section: Network loop (for use in other event loops) + * + * ====================================================================== */ /* * 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 ef2b1f83..670c8f07 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 b3125017..f8155fd1 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 e9f0d4f4..fb649ff8 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 44257c69..a3fb99dc 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 1d6401b0..a0cdaf1b 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 7ed08010..b3f426dc 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 2b23e134..0da03758 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 1e7fae8d..0b1232d3 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 fb18c049..727f85b0 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 374c67e6..668de814 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 b4f44c84..3c932cea 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 1253063a..5fbd311f 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 f4fe9a43..a78ea1e1 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 1595be21..236d5bf0 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 @@ error: 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 1941fb95..083e6406 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 fd289b5f..4fb76c4c 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 6a4680ae..a60e1f9b 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 @@ handle_connect_error: 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 20c51659..a071481d 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 ebab3156..0bd7b702 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 56da9957..c64ae66c 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 86fb5ad6..2b347735 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 5eb9caee..95003412 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 | 184 ++++++++------- 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, 625 insertions(+), 627 deletions(-) diff --git a/lib/handle_auth.c b/lib/handle_auth.c index 670c8f07..fa798ee3 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 f8155fd1..0c96fdf9 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 fb649ff8..3f8ae22f 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 a3fb99dc..3bfd19fb 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 a0cdaf1b..778db6aa 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 b3f426dc..440791e8 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 0da03758..c41297b8 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 0b1232d3..83050f65 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 9c3261de..e5bd3292 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 62befba6..4b132018 100644 --- a/lib/mqtt_protocol.h +++ b/lib/mqtt_protocol.h @@ -14,10 +14,8 @@ Contributors: 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 @@ Contributors: /* 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 +#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 -/* For distinguishing CONNECT and WILL properties */ -#define CMD_WILL 0 +/* 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 */ + 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 */ - 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_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 e7ffe0b4..1994df25 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 3c932cea..a970ef9f 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 011c083c..1da41aa7 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 4bc75989..ee59fc02 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 61c979a9..1258f5c0 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 f944c6a9..a29d0919 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 4f54acba..9ac9d8d2 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 c950b12a..498919ff 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 db59fc98..105a7d79 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 083e6406..529f4e65 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 4fb76c4c..ca332169 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 a60e1f9b..b617211f 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 a071481d..e190f928 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 0bd7b702..b96ad255 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 c64ae66c..296fef11 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 a283ca0e..72144ce8 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 ba19b305..7414298a 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 a276f81c..20eeb270 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 2b347735..f124ae21 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 95003412..00533539 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 727f85b0..c047e87c 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 668de814..129560c0 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 a970ef9f..a3c5d209 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 c047e87c..9502cc15 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 e5bd3292..ebecbdc9 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 129560c0..9ff9f787 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 9502cc15..347beecc 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 9ff9f787..338baa88 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 4b132018..2d53f6f8 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 a3c5d209..b5556d7d 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 a29d0919..9bf441a1 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 7ea0b12b..34b1b878 100644 --- a/lib/send_mosq.h +++ b/lib/send_mosq.h @@ -20,7 +20,7 @@ Contributors: #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 a6b2c018..39a12d1d 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 02ac6087..4ffc46b1 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 00000000..908fbb0f --- /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 253ef161..aa2529aa 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 06762293..18adcf3f 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 9fb38889..ffeb2ec1 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 4495849d..5e9a972d 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 7a48f3cc..c6bdef5c 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -29,6 +29,11 @@ Contributors: 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 fe084e31..88eecca3 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -26,7 +26,7 @@ Contributors: #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 347beecc..9ec233cc 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 338baa88..c7ba275d 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 b5556d7d..be8ef05e 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 5fbd311f..dd2ecf95 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 f8859ef0..1c703fd7 100644 --- a/lib/send_connect.c +++ b/lib/send_connect.c @@ -31,7 +31,7 @@ Contributors: #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 1258f5c0..9593ea2e 100644 --- a/lib/send_disconnect.c +++ b/lib/send_disconnect.c @@ -32,11 +32,10 @@ Contributors: #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 9bf441a1..eb0d6561 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 34b1b878..68d11899 100644 --- a/lib/send_mosq.h +++ b/lib/send_mosq.h @@ -20,19 +20,19 @@ Contributors: #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 9ac9d8d2..ef71ab71 100644 --- a/lib/send_publish.c +++ b/lib/send_publish.c @@ -37,7 +37,7 @@ Contributors: #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 498919ff..7feeb3a9 100644 --- a/lib/send_subscribe.c +++ b/lib/send_subscribe.c @@ -33,14 +33,13 @@ Contributors: #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 f8f006a4..a3cfc015 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 0d6fc314..e3b43df8 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 44e93cb1..696c6c51 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 97f1d3b4..3d93b2c5 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 93b2ea4a..dcb92da4 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 77ccf341..cbff3a9a 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 ca332169..c04625ae 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 296fef11..d760a5d7 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 f9970a78..7a199b11 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 00000000..e48b6547 --- /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 18cdec87..85447d06 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_pubrel(mid, dup=False, proto_ver=4): +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, 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 aa2529aa..df70a108 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 9ec233cc..c12be67e 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 c7ba275d..fd658e4d 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 5ec32302..12a19d8b 100644 --- a/lib/options.c +++ b/lib/options.c @@ -30,9 +30,15 @@ Contributors: 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 7062b512..b9a13b9d 100644 --- a/lib/will_mosq.c +++ b/lib/will_mosq.c @@ -33,10 +33,12 @@ Contributors: #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 7afb4089..e46d1bd9 100644 --- a/lib/will_mosq.h +++ b/lib/will_mosq.h @@ -20,7 +20,7 @@ Contributors: #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 cbff3a9a..2446184d 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 ffeb2ec1..cd950d92 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 5e9a972d..355d2bb1 100644 --- a/client/sub_client.c +++ b/client/sub_client.c @@ -34,6 +34,7 @@ Contributors: #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 c12be67e..83476ccc 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 9593ea2e..d998c3f6 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 908fbb0f..de9db8e3 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 de9db8e3..93ce27f8 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 355d2bb1..d86f7e01 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 83476ccc..499aa303 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 fd658e4d..b5eba8af 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 68d11899..094c782c 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 105a7d79..a3e75251 100644 --- a/lib/send_unsubscribe.c +++ b/lib/send_unsubscribe.c @@ -29,17 +29,17 @@ Contributors: #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 c04625ae..038dab0e 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 df70a108..1e2240b5 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 cd950d92..acec809e 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 d86f7e01..ce6d4171 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 e3b43df8..c95c0cba 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 696c6c51..bffcd6e0 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 | 43 ++++++++++++++++++++++++++++++++---------- lib/send_publish.c | 14 ++++++++++---- 5 files changed, 62 insertions(+), 17 deletions(-) diff --git a/client/client_props.c b/client/client_props.c index 93ce27f8..1e641514 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 18adcf3f..ade5b274 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 acec809e..ff38e8ee 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 25c5009e..35826971 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; + const mosquitto_property *p; + bool have_topic_alias; - 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(!mosq || qos<0 || qos>2) return MOSQ_ERR_INVAL; + if(!topic || STREMPTY(topic)){ + if(topic) topic = NULL; - if(mosquitto_pub_topic_check(topic) != MOSQ_ERR_SUCCESS){ - return MOSQ_ERR_INVAL; + 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 ef71ab71..39878f8d 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 1e2240b5..41fefa90 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 ff38e8ee..9b5291db 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 ce6d4171..8a9cf3a9 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 e190f928..fe47c855 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 1e641514..71dcc2d4 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 41fefa90..fb1ba310 100644 --- a/client/client_shared.c +++ b/client/client_shared.c @@ -32,6 +32,7 @@ Contributors: #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 35826971..e0ccf0f3 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 88eecca3..100d7e9f 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -22,6 +22,7 @@ Contributors: #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 499aa303..ccebe673 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 ebecbdc9..be449fbe 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 b5eba8af..9dccb3df 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 12a19d8b..4a66f309 100644 --- a/lib/options.c +++ b/lib/options.c @@ -25,6 +25,7 @@ Contributors: #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 be8ef05e..e932d960 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -26,8 +26,6 @@ Contributors: #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 b9a13b9d..154badbc 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 236d5bf0..5cf640fc 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 fe47c855..8862394e 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 @@ process_bad_message: 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 7a199b11..8140bb17 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 cccd04ad..c434a41e 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 100d7e9f..f0f36914 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -27,7 +27,7 @@ Contributors: #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 fa798ee3..5b84d3de 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 0c96fdf9..ba110883 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 3f8ae22f..2169df70 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 3bfd19fb..c3c53b58 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 778db6aa..4bd58029 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 440791e8..d9d5dda5 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 c41297b8..65b71e52 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 83050f65..72ca3d58 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 2fac25ba..e8fc1b7e 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 e932d960..4dd5c22e 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -27,7 +27,7 @@ Contributors: #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 dd2ecf95..97c11564 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 1c703fd7..a052a398 100644 --- a/lib/send_connect.c +++ b/lib/send_connect.c @@ -31,7 +31,7 @@ Contributors: #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 d998c3f6..d29a153e 100644 --- a/lib/send_disconnect.c +++ b/lib/send_disconnect.c @@ -32,7 +32,7 @@ Contributors: #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 eb0d6561..3899589c 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 094c782c..fdf3b7ea 100644 --- a/lib/send_mosq.h +++ b/lib/send_mosq.h @@ -20,19 +20,19 @@ Contributors: #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 39878f8d..ee25d3b4 100644 --- a/lib/send_publish.c +++ b/lib/send_publish.c @@ -37,7 +37,7 @@ Contributors: #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 7feeb3a9..1fb02b14 100644 --- a/lib/send_subscribe.c +++ b/lib/send_subscribe.c @@ -33,7 +33,7 @@ Contributors: #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 5cf640fc..3de57289 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 529f4e65..dd5b2d73 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 038dab0e..20ac526a 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 b617211f..a6f1ae78 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 @@ handle_connect_error: 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 8862394e..31b1df5b 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 b96ad255..0715b475 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 d760a5d7..6fb24e2d 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 8140bb17..06f3d2f6 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 7414298a..ac39b636 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 20eeb270..49daeebc 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 e48b6547..59fc50a3 100644 --- a/src/send_unsuback.c +++ b/src/send_unsuback.c @@ -25,7 +25,7 @@ Contributors: #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 f124ae21..8d9c4433 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 00533539..6cc341ce 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 ba034832..f1f31dd1 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 b83327c3..3299356d 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 037ee82b..0d6747b9 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 ba110883..75a5db87 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 2169df70..0ed07ff1 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 c3c53b58..659260a1 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 d9d5dda5..8c606459 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 65b71e52..5f142ac5 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 72ca3d58..bce4d369 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 ccebe673..490b4a23 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 0725d227..628d7d12 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 9dccb3df..0f586fb2 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 e8fc1b7e..acc1d21e 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 1994df25..ce61cb50 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 0219dd8a..53e7881d 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 4909862c..e67eaa15 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 490b4a23..06f6e40a 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 0f586fb2..ec392a04 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 4dd5c22e..46ab2d8a 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 659260a1..ed93703e 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 00000000..43b055a1 --- /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 00000000..6ff04861 --- /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 bf5a931f..c1107921 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 00000000..5c7b5bf5 --- /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 00000000..8763496f --- /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 00000000..77245256 --- /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 9678766a..7d936ff3 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 42821379..c16079f9 100755 --- a/test/lib/ptest.py +++ b/test/lib/ptest.py @@ -23,14 +23,14 @@ tests = [ ('./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 @@ tests = [ ('./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 00000000..7e536990 --- /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 c1107921..b1ef54f4 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 00000000..198ef72f --- /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 7d936ff3..45a6c7e7 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 c16079f9..82cf15d3 100755 --- a/test/lib/ptest.py +++ b/test/lib/ptest.py @@ -31,6 +31,8 @@ tests = [ ('./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 85447d06..26fea528 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 82cf15d3..d3981a7c 100755 --- a/test/lib/ptest.py +++ b/test/lib/ptest.py @@ -31,8 +31,7 @@ tests = [ ('./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 39a12d1d..d53772ed 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 4ffc46b1..39310b97 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 9b5291db..3f95b742 100644 --- a/client/pub_client.c +++ b/client/pub_client.c @@ -31,29 +31,10 @@ Contributors: #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); - } + rc = pub_shared_loop(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); - } - - 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 00000000..26fcab91 --- /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 00000000..f91a55fc --- /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 06f6e40a..5d7c943b 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 ec392a04..13af7e7a 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 3f95b742..722308b6 100644 --- a/client/pub_client.c +++ b/client/pub_client.c @@ -35,7 +35,6 @@ Contributors: /* Global variables for use in callbacks. See sub_client.c for an example of * using a struct to hold variables for use in callbacks. */ -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 26fcab91..08f941bb 100644 --- a/client/pub_shared.c +++ b/client/pub_shared.c @@ -37,12 +37,13 @@ Contributors: * 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 f91a55fc..64c02d2b 100644 --- a/client/pub_shared.h +++ b/client/pub_shared.h @@ -23,6 +23,7 @@ Contributors: 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 f0f36914..69e98216 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 d29a153e..120ef82f 100644 --- a/lib/send_disconnect.c +++ b/lib/send_disconnect.c @@ -32,7 +32,7 @@ Contributors: #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 fdf3b7ea..c26615be 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 722308b6..7211b4f0 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 08f941bb..83a1ffee 100644 --- a/client/pub_shared.c +++ b/client/pub_shared.c @@ -30,6 +30,7 @@ Contributors: #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 8a9cf3a9..473c58c3 100644 --- a/client/sub_client.c +++ b/client/sub_client.c @@ -32,6 +32,7 @@ Contributors: #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 69e98216..016bc73d 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 13af7e7a..7ffbc16c 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 016bc73d..6035f582 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 acc1d21e..f1a64e2d 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 ce61cb50..c7a332f0 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 a6f1ae78..a109187e 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 06f3d2f6..7351e0d8 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 ac39b636..c674548e 100644 --- a/src/send_connack.c +++ b/src/send_connack.c @@ -23,7 +23,7 @@ Contributors: #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 7211b4f0..bc44af41 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 83a1ffee..98b54942 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 64c02d2b..feaa22eb 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 dbbf2ca6..da516480 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 6035f582..2bb1f6f9 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 f1a64e2d..fe0a6e24 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 c7a332f0..b22fdc8a 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 9dc330c4..8e310e61 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 00000000..2f3bb58a --- /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 1da41aa7..991a7dbc 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 8bf20b5f..e0e17c94 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 98b54942..bcfc2b53 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 a6bf0c99..fa9d1e86 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 96450050..fa332a24 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 6b6f2434..20609e07 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 3de57289..eb5547f7 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 a109187e..0e87303b 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 31b1df5b..8cb11449 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 7351e0d8..694bd649 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 c674548e..629dca64 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 bc44af41..80609f84 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 473c58c3..36ec4a0c 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 629dca64..0891af60 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 26fea528..a975d833 100644 --- a/test/mosq_test.py +++ b/test/mosq_test.py @@ -6,6 +6,8 @@ import struct 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 fb1ba310..13972770 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 80609f84..139bb3aa 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 bcfc2b53..9f10d5ec 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 36ec4a0c..cd297b0b 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 4a66f309..7f18993e 100644 --- a/lib/options.c +++ b/lib/options.c @@ -32,11 +32,11 @@ Contributors: 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 5c7b5bf5..1cdd4079 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 8763496f..0f16f1ef 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 77245256..35190af5 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 198ef72f..516d86d4 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 00000000..58ebf10e --- /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 be9cb84b..2d523790 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 920dee7b..7dfbaed5 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -51,6 +51,7 @@ tests = [ #(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 a975d833..c263cc31 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 7c0dca32..4815fbd5 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 c263cc31..f2c7d3b7 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 f0b78753..6fbc776e 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 be449fbe..688312d3 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 fe0a6e24..1ca5f3c3 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 a3cfc015..5f43d16a 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 2446184d..59e7b516 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 20609e07..00d30b2e 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 a78ea1e1..164969db 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 0e87303b..e0b50f7d 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 97147209..dd6b2139 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 694bd649..9c4439d3 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 c434a41e..d105c413 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 3365bfbf..fd387869 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 b2c761f5..8df8518d 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 4730c3b1..41a87701 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 bed2d241..fff5d7af 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 279b9f50..32188a12 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 adb5a304..99ba1494 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 58ca6311..72b2ae90 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 1245805e..c98869bf 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 4d5201a1..6533ce65 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 45b39d9d..4d3959e1 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 0ddb44ea..21313789 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 8eb626a4..a5467927 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 9951f488..46885910 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 1c9236f6..4ee76652 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 2f168e70..93de845e 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 2f168e70..93de845e 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 5ece7beb..f09f690e 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 b72605c0..b6cd0f9a 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 5c9670a7..8fa7aae2 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 ef3c9009..debb06f6 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 00cdb176..803dcb90 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 2d08f43d..cf87a989 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 c4a86599..ca78af11 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 796ed821..32feaed7 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 610e7c57..f9f941be 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 00bed94b..f9ae5b39 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 36b91099..26a627ce 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 a3ec5803..434a8704 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 03b326f3..a15290ee 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 c3e34256..9931583c 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 b5a34152..3cc1f401 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 99b85a94..0d824bd3 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 45dfdf5f..4fd25d69 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 64d71963..a05a1539 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 e4767518..2262c195 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 c7dc0561..6a1f4168 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 02754fa4..31d43edd 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 f6c9766f..f86ed175 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 14e1ed17..d171346b 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 aa99fd4d..f0c0dcce 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 8d40f5ae..dda48cc2 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 5ed91aba..a1d4c829 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 a08dd44b..f5aae3bb 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 a6e3f789..66d5384f 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 aceef579..295b1e20 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 057690fc..02dc238b 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 2c7f6f79..c5e3e8df 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 4b2d3787..35b716cf 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 811b356a..fb3788b1 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 e2f4c32d..f57e381f 100755 --- a/test/broker/03-publish-qos1-queued-bytes.py +++ b/test/broker/03-publish-qos1-queued-bytes.py @@ -17,13 +17,7 @@ except ImportError: 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 58ebf10e..bb86fe61 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 5bcebd47..dabf3358 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 c6ae3c69..2a8ebd47 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 90cdf6c3..ea6d122c 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 c2445b82..41f21a26 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 7276248a..54fc0e9e 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 2d698671..d6b21902 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 dd452652..3fa96a08 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 597e9828..bccff1d7 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 c1e62444..28abd803 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 7ae6cdc8..22f5603e 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 91c7fe6c..e742bd73 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 11f19700..38c86c23 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 4c344354..3d81e0c2 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 f010cd33..0e50f9ef 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 ae43970a..00fdba0f 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 80b12e17..bcb28d43 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 24610aba..d7469288 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 51ddf2bb..716b2e5a 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 f288561d..ece86f99 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 1d1aad1d..7c2df3e2 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 06758a75..4e6e90ad 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 cf46147b..66eb425d 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 9edde871..0b043e52 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 b3059e6c..c4c1f1a2 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 e2333231..0b4960e5 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 9ea56e59..2500185e 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 69c5dcbc..b9c15943 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 0a76fdca..50c00d4e 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 e6c46eb7..f9d42c64 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 4c7ef7d4..990e40b4 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 e67c398b..9ca462f4 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 d84bc5b6..cb997371 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 492b7d8d..b68bee05 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 4de59705..bfa5bc11 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 76b6bfbe..60d08305 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 2f7dbf83..7df9a3b2 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 04ca171c..1f0872d3 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 b73c2d12..4b7dd280 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 9f84a28c..f8cb88e9 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 67c3a877..ee0acb0a 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 70a0a27c..6f65fd0c 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 b0d2cfb9..8a184a27 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 34994416..383014a6 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 838705bb..111d5477 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 bedbec39..bb780d64 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 0cc78aa4..07521a87 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 3aa90468..77bf0d72 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 5aa008e1..38a4ecc6 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 a9b32a83..8e50fca3 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 cff805f5..27908509 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 a24bb8a7..65837917 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 7133a691..3cc6d7b9 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 602bc4a5..a6a91259 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 47fd0766..f190770b 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 492dcfcc..ff1328fc 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 00000000..0e861dba --- /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 bb5f4ce2..6838c587 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 8e95b5db..59129cfe 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 d5f46eb3..481b1190 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 454e417a..6dd0d4d5 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 63a8e2ea..c43f1f08 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 2a64bef7..e9132376 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 f5f60d2f..737efa77 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 68ffa39d..5201bf0e 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 9a2864a5..180c3b9d 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 8d9560cf..abffc00a 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 4d6c475a..942ca4f7 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 a970ed55..8600c187 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 2111ae7c..87aa79ba 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 7cea7005..104961aa 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 c9a5d526..dbd843db 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 37031a9a..68313423 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 b27b6a06..3a52b767 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 b2185639..4a851d62 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 3f7adc9b..dff2cb81 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 43b055a1..b1ed9ccd 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 6ff04861..229bc8f9 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 cb495df1..485d7712 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 20dc6fed..025f66b9 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 d49540fa..2d321fc4 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 f1485bb9..8f5f31d5 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 55c81962..2499c31c 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 48967fd2..367cb479 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 6f8dc122..88974c2e 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 7e536990..da6a61f0 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 00000000..0e861dba --- /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 1ca5f3c3..55a537a7 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 3d93b2c5..e1eb6f46 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 dcb92da4..07b917dd 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 e0b50f7d..088ea051 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 @@ handle_connect_error: 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 9c4439d3..3cfe0738 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 00000000..e2f9d466 --- /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 00000000..de31d0e6 --- /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 2d523790..0a90db09 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 7dfbaed5..ffb7b3ed 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -105,6 +105,7 @@ tests = [ (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 82eff277..c31535de 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 f2c7d3b7..cc3e9264 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 46fe350e..e641a8d1 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 46ab2d8a..40fc3909 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 75a5db87..530e8bf6 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 088ea051..ad737b8f 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 @@ handle_connect_error: 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 3cfe0738..7a1b6bd7 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 0891af60..1c20820c 100644 --- a/src/send_connack.c +++ b/src/send_connack.c @@ -23,13 +23,18 @@ Contributors: #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 00000000..923f54bf --- /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 b4145237..7b5f4ded 100644 --- a/www/conf.py +++ b/www/conf.py @@ -87,6 +87,7 @@ NAVIGATION_LINKS = { #("/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 00000000..7e607cf7 --- /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 00000000..2b27e821 --- /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 cc35d767..d6942a0d 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 ab3f5e96..4aeb8c39 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 34143f85..d7db79b8 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 097f4521..7ae8dccd 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 0f480eff..5661fb35 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 6a8c1794..27b05904 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 d6942a0d..cfe54fc2 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 a6bf0c99..d5dcc50b 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 0b1d79cf..c6bd897c 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 67a2924c..bd6ad136 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 08f2b824..21f5ec68 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 bf2804b8..a57330aa 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 cfe54fc2..953a2b3c 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 4efda3d2..f2bb628b 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 1d3ae163..e8cbfdfc 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 953a2b3c..969c6c2a 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 23e60825..349ee5dc 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 dd9f7180..00951a68 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 969c6c2a..f79c5277 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 a3f2ed7d..e35cacce 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 52e78e4f..9e16e4d4 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 f79c5277..e80a1d40 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 c6bd897c..67e172b0 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 fa1127ed..0b31af92 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 e80a1d40..ec082855 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 11b4b018..c0fdc68a 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 349ee5dc..b8fd2c57 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 c049c8ef..6773185a 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 8fa7aae2..00000000 --- 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 00000000..43ec811d --- /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 00000000..96d63afe --- /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 0a90db09..f19566ea 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 00000000..212e4d7e --- /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 ffb7b3ed..5d9fb0a3 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -32,7 +32,6 @@ tests = [ (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 @@ tests = [ (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 00000000..f78bb3a6 --- /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 b1ef54f4..e9b0c54c 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 00000000..d60c8b5a --- /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 45a6c7e7..4727680f 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 d3981a7c..64990e5e 100755 --- a/test/lib/ptest.py +++ b/test/lib/ptest.py @@ -32,6 +32,7 @@ tests = [ ('./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 | 137 +++++++++++------------------------------ 2 files changed, 54 insertions(+), 121 deletions(-) diff --git a/test/broker/c/Makefile b/test/broker/c/Makefile index f60f9d5f..2005270d 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 4727680f..0986b528 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 +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 -01-con-discon-success.test : 01-con-discon-success.c +TESTS = ${SRC:.c=.test} + +all : ${TESTS} + +${TESTS} : %.test: %.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 - $(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 8ebaa2a9..bb3fc58f 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 99ddc56e..8d44b449 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 6f3f3ac5..f7a030db 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 32726894..ee038fbc 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 c7569010..7ce01902 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 e1eb6f46..960b263a 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 ad737b8f..0c92d6d3 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -30,28 +30,75 @@ Contributors: #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 int random_16_bytes(uint8_t *bytes) +{ + 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; -#ifdef WITH_UUID - uuid_t uuid; -#else + uint8_t rnd[16]; int i; -#endif + 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 f1f31dd1..4c8fbb89 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 bb3fc58f..e2dd2e3a 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 fa9d1e86..ee240762 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 fa332a24..d9456a68 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 00d30b2e..68da9929 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 6fbc776e..0de00322 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 688312d3..92c4e9ea 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 a052a398..5b50e2c7 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 32188a12..63273e93 100755 --- a/test/broker/01-connect-invalid-id-missing.py +++ b/test/broker/01-connect-invalid-id-missing.py @@ -6,13 +6,14 @@ from mosq_test_helper import * 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 00000000..fac50d11 --- /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 f19566ea..db0b971a 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 5d9fb0a3..ff2984fd 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -108,6 +108,7 @@ tests = [ (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 cc3e9264..8d29d1a5 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 13972770..88112201 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 139bb3aa..bede0032 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 feaa22eb..22f88e62 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 cd297b0b..1a26bcb0 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 530e8bf6..98adae1d 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 e2dd2e3a..27be9d46 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 98adae1d..7cd65d4e 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 ee240762..dbfce513 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 d9456a68..cf24e2ed 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 68da9929..9053f228 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 0c92d6d3..c1634eb7 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 7a1b6bd7..cc0a5edd 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 00000000..5073f28c --- /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 db0b971a..0b9bf169 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 ff2984fd..a9772aa5 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -109,6 +109,7 @@ tests = [ (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 | 12 ++-- ...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, 129 insertions(+), 8 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 8cb11449..f328a77e 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_CORRELATION_DATA: - case MQTT_PROP_USER_PROPERTY: 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: 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 00000000..9a043825 --- /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 00000000..3b9c3e8b --- /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 0b9bf169..3105c62a 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 a9772aa5..2804dfd8 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -110,6 +110,8 @@ tests = [ (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 ec082855..c3a6c60a 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 b8fd2c57..4b277752 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 56d8cb05..405cb390 100644 --- a/lib/util_mosq.c +++ b/lib/util_mosq.c @@ -46,9 +46,9 @@ Contributors: #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 0e65dd98..8e601a0f 100644 --- a/lib/util_mosq.h +++ b/lib/util_mosq.h @@ -26,9 +26,9 @@ Contributors: #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 776e3045..00000000 --- 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 | 169 +++++++++++------ lib/property_mosq.c | 191 ++++++++++++-------- 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, 342 insertions(+), 172 deletions(-) diff --git a/lib/actions.c b/lib/actions.c index 38074b1b..65388195 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 0de00322..791aadd5 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 7cd65d4e..5e5fa86d 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 b1be3a11..e9ee68ca 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 e641a8d1..f8ca0794 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 * - * 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. + * 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. + * + * 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 + * 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_pair(const mosquitto_property *property, char **name, char **value); +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 40fc3909..ae2d02bb 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){ + 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_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, property->value.s.v, property->value.s.len); + memcpy(*value, p->value.s.v, p->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 97c11564..d31ce85e 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 b1ed9ccd..a2ab54be 100755 --- a/test/lib/03-request-response-correlation.py +++ b/test/lib/03-request-response-correlation.py @@ -23,7 +23,13 @@ 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) +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 @@ try: 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 0f16f1ef..3419f395 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 f8ca0794..c5624c78 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 59e7b516..80bed550 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 0715b475..ab2de078 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 d105c413..b9e48ba3 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 715b043f..901cb72b 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 fd60addf..2d300fc0 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 c3a6c60a..6287bce2 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 67e172b0..87294680 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 6287bce2..b36c1d96 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 2788b7ce..8f993dc9 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 f1ce6f31..aee823a6 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 8c729b87..49ca48c2 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 3d91ed0f..607f258c 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 97ac6be9..3c777059 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 f2bb628b..09a26042 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 00951a68..b4b8ac84 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 405cb390..d98bbde4 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 8e601a0f..d94661e7 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 e35cacce..6e4b94fa 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 87294680..0968d326 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 2d300fc0..b9b0fefd 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 bd6ad136..bf13eebb 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 21f5ec68..10f88dbe 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 b36c1d96..e7cb7886 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 6773185a..8d084749 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 10f88dbe..937f6ce1 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 a57330aa..6ac446f6 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 4b277752..e4a985eb 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 161696da..265c106d 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 e7cb7886..d7682e40 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 d591cd49..0ee3fa44 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 d7db79b8..0574e0b1 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 7ae8dccd..5e9706c4 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 b3600b2c..57a22ec3 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 54958189..ec105f6b 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 fa1127ed..b337fe0b 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 0c0dec00..b337fe0b 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 5661fb35..2c9b15c6 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 2a9b54e0..2aceb0a5 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 7696dca9..43618a25 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 00000000..ca011715 --- /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 791aadd5..ad3bb1d0 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -16,6 +16,8 @@ Contributors: #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 88112201..b37d3067 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 ade5b274..1a8ad280 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 1a26bcb0..62d91ca7 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 c5624c78..bb1524bd 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 2d53f6f8..672d50b7 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 1fb02b14..ffe7ef7d 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 bffcd6e0..7c4861ab 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 80bed550..10c5744c 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 ab2de078..7cf62855 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 cc0a5edd..2156cc4e 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 b9e48ba3..8cc2de5f 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 901cb72b..d608f36e 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 7cf62855..aac6ad6d 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 2156cc4e..d80accce 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 d608f36e..0899383c 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 8d9c4433..5982ae32 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 611e2098..ddc52375 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 00000000..341c0080 --- /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 9e29f391..6ae5cad3 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 ddc52375..b627cbde 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 00000000..065237b2 --- /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 6ae5cad3..17a37023 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 6cc341ce..c689ba75 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 ae2d02bb..c8dde7f1 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 065237b2..42a8c08d 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 b08c9a43..1edaceb2 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 09f1a1a4..52c33998 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 10c5744c..8006c2d9 100644 --- a/src/bridge.c +++ b/src/bridge.c @@ -29,6 +29,7 @@ Contributors: #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 aac6ad6d..4d59da6f 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 0899383c..3e3bf3be 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 00000000..d6436eef --- /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 00000000..ed9ba735 --- /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 00000000..d66be515 --- /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 3105c62a..1d80d79d 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 0e861dba..9b8f2113 100644 --- a/test/broker/mosq_test_helper.py +++ b/test/broker/mosq_test_helper.py @@ -6,6 +6,7 @@ if cmd_subfolder not in sys.path: 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 2804dfd8..68f1ed25 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -32,6 +32,9 @@ tests = [ (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 00000000..55675a73 --- /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 3e3bf3be..acc8714a 100644 --- a/src/subs.c +++ b/src/subs.c @@ -53,6 +53,7 @@ Contributors: #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 342cac56..aac409be 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 00000000..a7640e7c --- /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 00000000..d99297b6 --- /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 681387e6..102a7474 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 42ca336f..41f690b2 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -7,6 +7,8 @@ import sys 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 00000000..723e07e5 --- /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 102a7474..4336e50b 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 41f690b2..4ae7cdca 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -7,6 +7,7 @@ import sys 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 71dcc2d4..7415bc06 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 57a48d54..7c0e8c27 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 ad3bb1d0..5beed13a 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 2a737d9b..9d494788 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 c8dde7f1..e9399fd5 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 d31ce85e..d965d8a3 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 5b50e2c7..99778634 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 120ef82f..c0959fbb 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 3899589c..8b54b996 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 c26615be..897f2eb8 100644 --- a/lib/send_mosq.h +++ b/lib/send_mosq.h @@ -21,7 +21,7 @@ Contributors: 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 ee25d3b4..c1d81e0e 100644 --- a/lib/send_publish.c +++ b/lib/send_publish.c @@ -37,7 +37,7 @@ Contributors: #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 ffe7ef7d..4095e4af 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 a3e75251..6e0623df 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 365658e6..46dbf51c 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 eb5547f7..666c58ef 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 bc6e37a8..9ef56812 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 f328a77e..3b02c1af 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 @@ process_bad_message: 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 4d59da6f..1f8412f7 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 9cf0246e..cd5eddb8 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 b8b3e4b8..a48028a7 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 1c20820c..d51179b0 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 49daeebc..98c13bc7 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 59fc50a3..ee0c8333 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 acc8714a..04bb2231 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 8d29d1a5..a2db51fd 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 d7682e40..ba8864db 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 43618a25..b8abf73d 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 ca011715..b2d5f96e 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 00000000..4841af75 --- /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 4336e50b..fa77f88e 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 4ae7cdca..494eda39 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -38,6 +38,7 @@ tests = [ (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 a2db51fd..abea7af5 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 bdd5b1b3..9f307324 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 0ed07ff1..4c4f319f 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 4bd58029..56879265 100644 --- a/lib/handle_pubrec.c +++ b/lib/handle_pubrec.c @@ -37,6 +37,7 @@ Contributors: 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 8c606459..2ec6dc8b 100644 --- a/lib/handle_pubrel.c +++ b/lib/handle_pubrel.c @@ -38,6 +38,7 @@ Contributors: 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 52c33998..1982da87 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 55a537a7..5eff5d06 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 b18af7b1..0ae70ee4 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 c7fa9da3..a93b8e30 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 666c58ef..d93d3c08 100644 --- a/src/database.c +++ b/src/database.c @@ -25,7 +25,6 @@ Contributors: #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 cd5eddb8..497167c9 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 e2f9d466..57d17c9c 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 00000000..f517a745 --- /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 00000000..4084737d --- /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 00000000..01eb91a6 --- /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 fa77f88e..8d9043d1 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 494eda39..406dfe67 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -39,6 +39,8 @@ tests = [ (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 7b83dd49..5959289d 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 9f10d5ec..9ef50084 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 | 68 +++++++++++++++++++++++++++++++++++------- 4 files changed, 114 insertions(+), 12 deletions(-) diff --git a/client/client_shared.c b/client/client_shared.c index 517a6a6f..b38306ca 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 e9ee68ca..d7eecba0 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 1c91d7fb..742ef599 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 85a9cba1..c3208050 100644 --- a/lib/options.c +++ b/lib/options.c @@ -276,16 +276,7 @@ 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){ - 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; - } - break; + return mosquitto_int_option(mosq, option, ival); case MOSQ_OPT_SSL_CTX: #ifdef WITH_TLS mosq->ssl_ctx = (SSL_CTX *)value; @@ -300,9 +291,64 @@ int mosquitto_opts_set(struct mosquitto *mosq, enum mosq_opt_t option, void *val #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(value == MQTT_PROTOCOL_V311){ + mosq->protocol = mosq_p_mqtt311; + }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 - mosq->ssl_ctx_defaults = true; + 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; + 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; 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 5beed13a..a08f7902 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 ed93703e..acebd90a 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 92c4e9ea..b07c69f8 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 742ef599..cadb2ee0 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 5eff5d06..f62cf3d3 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 c3208050..053a1e4b 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 99778634..d0bd3cd3 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 8b54b996..5366fd1e 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 07ba6afb..1683a2e9 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 d94661e7..62a14f2b 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 abea7af5..cfa182f5 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 0bf99128..d640d5b8 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 00000000..8e400589 --- /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 00000000..6d46cb77 --- /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 4841af75..4f9c1a1d 100755 --- a/test/broker/02-subpub-qos0-subscription-id.py +++ b/test/broker/02-subpub-qos0-subscription-id.py @@ -12,13 +12,11 @@ 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) @@ -29,12 +27,10 @@ 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) diff --git a/test/broker/02-subpub-qos2-receive-maximum-1.py b/test/broker/02-subpub-qos2-receive-maximum-1.py index f517a745..db291c52 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 @@ 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) diff --git a/test/broker/02-subpub-qos2-receive-maximum-2.py b/test/broker/02-subpub-qos2-receive-maximum-2.py index 4084737d..66de557d 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 @@ 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) diff --git a/test/broker/12-prop-assigned-client-identifier.py b/test/broker/12-prop-assigned-client-identifier.py index fac50d11..2e85c278 100755 --- a/test/broker/12-prop-assigned-client-identifier.py +++ b/test/broker/12-prop-assigned-client-identifier.py @@ -16,7 +16,6 @@ props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_ASSIGNED_CLIENT_IDENTIFIER, 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 9a043825..13a64760 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 @@ 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) diff --git a/test/broker/12-prop-response-topic.py b/test/broker/12-prop-response-topic.py index 3b9c3e8b..ddfbf936 100755 --- a/test/broker/12-prop-response-topic.py +++ b/test/broker/12-prop-response-topic.py @@ -21,7 +21,6 @@ subscribe_packet2 = mosq_test.gen_subscribe(mid=1, topic="response/topic", qos=0 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 de31d0e6..81cd7b5e 100755 --- a/test/broker/12-prop-session-expiry-invalid.py +++ b/test/broker/12-prop-session-expiry-invalid.py @@ -9,13 +9,11 @@ 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) diff --git a/test/broker/12-prop-subpub-content-type.py b/test/broker/12-prop-subpub-content-type.py index 43ec811d..d7106d15 100755 --- a/test/broker/12-prop-subpub-content-type.py +++ b/test/broker/12-prop-subpub-content-type.py @@ -9,9 +9,7 @@ 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 index 96d63afe..8cbd90e1 100755 --- a/test/broker/12-prop-subpub-payload-format.py +++ b/test/broker/12-prop-subpub-payload-format.py @@ -9,9 +9,7 @@ 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/lib/03-request-response-correlation.py b/test/lib/03-request-response-correlation.py index a2ab54be..689ddcfc 100755 --- a/test/lib/03-request-response-correlation.py +++ b/test/lib/03-request-response-correlation.py @@ -22,17 +22,14 @@ 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_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 229bc8f9..fe0bf456 100755 --- a/test/lib/03-request-response.py +++ b/test/lib/03-request-response.py @@ -21,7 +21,6 @@ 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) diff --git a/test/lib/11-prop-send-content-type.py b/test/lib/11-prop-send-content-type.py index f78bb3a6..9a433f1c 100755 --- a/test/lib/11-prop-send-content-type.py +++ b/test/lib/11-prop-send-content-type.py @@ -10,7 +10,6 @@ connect_packet = mosq_test.gen_connect("prop-test", keepalive=keepalive, proto_v 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 da6a61f0..701d55ba 100755 --- a/test/lib/11-prop-send-payload-format.py +++ b/test/lib/11-prop-send-payload-format.py @@ -20,7 +20,6 @@ connect_packet = mosq_test.gen_connect("prop-test", keepalive=keepalive, proto_v 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 cfa182f5..21c702bd 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 a08f7902..f2804002 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 5e5fa86d..135e9b4c 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 9d494788..51f48550 100644 --- a/lib/messages_mosq.c +++ b/lib/messages_mosq.c @@ -26,6 +26,7 @@ Contributors: #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 b07c69f8..c5bb056e 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 cadb2ee0..81fc6929 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 f62cf3d3..49a8829b 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 053a1e4b..fd31d57d 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 1683a2e9..ca2b5077 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 62a14f2b..6642a697 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 a93b8e30..a6a5f499 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 d93d3c08..6fc2dc23 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 57d17c9c..ee76b2c4 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 135e9b4c..df230419 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 00000000..b55860ea --- /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 00000000..b2335a51 --- /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 e9b0c54c..2d4cba92 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 00000000..e2d351cc --- /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 00000000..a4b8e2a2 --- /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 0986b528..69dc56a3 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 64990e5e..34b53323 100755 --- a/test/lib/ptest.py +++ b/test/lib/ptest.py @@ -21,6 +21,8 @@ tests = [ ('./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 00000000..cb27cf55 --- /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 2d4cba92..f7eb8858 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 00000000..a4b8e2a2 --- /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 69dc56a3..289d33d6 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 34b53323..56d478bc 100755 --- a/test/lib/ptest.py +++ b/test/lib/ptest.py @@ -22,7 +22,8 @@ tests = [ ('./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 56879265..589b405a 100644 --- a/lib/handle_pubrec.c +++ b/lib/handle_pubrec.c @@ -35,9 +35,9 @@ Contributors: #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 991a7dbc..28c0e66b 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 e0e17c94..d1c46cfd 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 72144ce8..f71a76f9 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 00000000..4d1bbc93 --- /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 00000000..2e3b3d34 --- /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 8d9043d1..7583026f 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 406dfe67..fbaf48f8 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -41,6 +41,7 @@ tests = [ (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 00000000..58021bd4 --- /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 f7eb8858..c91a1fa9 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 00000000..9f454c02 --- /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 289d33d6..936da2a2 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 56d478bc..9b7e4fab 100755 --- a/test/lib/ptest.py +++ b/test/lib/ptest.py @@ -24,6 +24,7 @@ tests = [ ('./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 4c9c75d5..db4deded 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 9ef50084..7f0f22ad 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 22f88e62..fd7331f7 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 6cbf76f9..2657dac7 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 0d6747b9..7b424210 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 4c4f319f..d03ea594 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 81fc6929..fffe1120 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 49a8829b..a3746fcf 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 b22fdc8a..b652656e 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 e2d351cc..563da395 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 9f454c02..f7a64b17 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 a4b8e2a2..d0f427ae 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 a4b8e2a2..d0f427ae 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 db4deded..28d5ed6b 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 7c0e8c27..b7abd592 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 df230419..1b13e28a 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 c5bb056e..65b21529 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 fffe1120..394d1a3a 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 a3746fcf..d79a464b 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 97509b05..437d2891 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 0ae70ee4..d1f8f64e 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 a6a5f499..bfe23405 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 6fc2dc23..e00c9ada 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 aac409be..cefd20d8 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 3b02c1af..6dbf4744 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 497167c9..e0e0f5a8 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 00000000..430df3a2 --- /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 00000000..ec29af36 --- /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 c91a1fa9..7fa08a0d 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 00000000..cfe7ab1d --- /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 00000000..84e56692 --- /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 936da2a2..cf05d72b 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 9b7e4fab..78ebcd0e 100755 --- a/test/lib/ptest.py +++ b/test/lib/ptest.py @@ -25,6 +25,8 @@ tests = [ ('./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 5959289d..3ff4e22d 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 b38306ca..0a0e26a4 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 c95c0cba..1054d432 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 7c4861ab..e46b5bbb 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 1f8412f7..e50075a3 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 d03ea594..b9fc2c5d 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 589b405a..feb41e92 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 2ec6dc8b..e046c40b 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 394d1a3a..8174eca0 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 5366fd1e..6f39b36d 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 00000000..3c491c4e --- /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 00000000..4eb82ae5 --- /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 00000000..e2a9c456 --- /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 00000000..b3f0e765 --- /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 00000000..753c571d --- /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 7583026f..6295d729 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 fbaf48f8..3f96794c 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -56,6 +56,9 @@ tests = [ (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 00000000..775669cc --- /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 00000000..30e65337 --- /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 00000000..fc444167 --- /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 7fa08a0d..cb71a4e7 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 00000000..3975d914 --- /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 00000000..66fe76e6 --- /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 00000000..ab59adb7 --- /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 cf05d72b..2df4221c 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 78ebcd0e..b94e6b40 100755 --- a/test/lib/ptest.py +++ b/test/lib/ptest.py @@ -18,6 +18,9 @@ tests = [ ('./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 21c702bd..a09367cc 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 2f3bb58a..0ec1c8b3 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 c0959fbb..3615a001 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 cefd20d8..739cd4d6 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 00000000..96dd4d89 --- /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 6295d729..74b7f434 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 3f96794c..cffe6cb0 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -12,6 +12,7 @@ tests = [ (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 a09367cc..b4a4b125 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 d1f8f64e..cabfd601 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 00000000..2d6fa9c2 --- /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 cb71a4e7..49f3088b 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 00000000..99da6f69 --- /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 2df4221c..f02beb90 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 b94e6b40..c12142a1 100755 --- a/test/lib/ptest.py +++ b/test/lib/ptest.py @@ -8,6 +8,7 @@ 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'), 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 | 151 ++++++++++++---------- test/broker/02-subpub-qos0-topic-alias.py | 54 ++++++++ test/broker/Makefile | 1 + test/broker/ptest.py | 1 + 10 files changed, 273 insertions(+), 73 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 00000000..8057bb99 --- /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 00000000..f892dbf8 --- /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 d79a464b..a3eac687 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 9297afe6..41dd9d94 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 07b917dd..bf7775ef 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 bfe23405..74a5a8d6 100644 --- a/src/context.c +++ b/src/context.c @@ -20,6 +20,7 @@ Contributors: #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 6dbf4744..148e7174 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -21,6 +21,7 @@ Contributors: #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,12 +83,91 @@ 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; } + if(qos > 0){ + if(packet__read_uint16(&context->in_packet, &mid)){ + mosquitto__free(topic); + return 1; + } + if(mid == 0){ + mosquitto__free(topic); + return MOSQ_ERR_PROTOCOL; + } + } + + /* Handle properties */ + if(context->protocol == mosq_p_mqtt5){ + rc = property__read_all(CMD_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 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: + 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; + p = p_prev->next; + }else{ + properties = p->next; + p = properties; + } + msg_properties_last->next = NULL; + break; + + case MQTT_PROP_TOPIC_ALIAS: + topic_alias = p->value.i16; + p_prev = p; + p = p->next; + break; + + case MQTT_PROP_MESSAGE_EXPIRY_INTERVAL: + message_expiry_interval = p->value.i32; + p_prev = p; + p = p->next; + break; + + case MQTT_PROP_SUBSCRIPTION_IDENTIFIER: + p_prev = p; + p = p->next; + break; + + default: + p = p->next; + break; + } + } + } + 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++){ @@ -141,74 +222,6 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) return 1; } - if(qos > 0){ - if(packet__read_uint16(&context->in_packet, &mid)){ - mosquitto__free(topic); - return 1; - } - if(mid == 0){ - mosquitto__free(topic); - return MOSQ_ERR_PROTOCOL; - } - } - - /* Handle properties */ - if(context->protocol == mosq_p_mqtt5){ - rc = property__read_all(CMD_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 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: - 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; - p = p_prev->next; - }else{ - properties = p->next; - p = properties; - } - msg_properties_last->next = NULL; - break; - - case MQTT_PROP_TOPIC_ALIAS: - p_prev = p; - p = p->next; - break; - - case MQTT_PROP_MESSAGE_EXPIRY_INTERVAL: - message_expiry_interval = p->value.i32; - p_prev = p; - p = p->next; - break; - - case MQTT_PROP_SUBSCRIPTION_IDENTIFIER: - p_prev = p; - p = p->next; - break; - - default: - p = p->next; - break; - } - } - } - mosquitto_property_free_all(&properties); - 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 00000000..89b86fbf --- /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 74b7f434..f6434d75 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 cffe6cb0..277b972e 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -43,6 +43,7 @@ tests = [ (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 dd5b2d73..1520f22d 100644 --- a/src/handle_auth.c +++ b/src/handle_auth.c @@ -28,7 +28,7 @@ Contributors: 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 d171346b..b95cd576 100755 --- a/test/broker/03-publish-b2c-disconnect-qos1.py +++ b/test/broker/03-publish-b2c-disconnect-qos1.py @@ -8,8 +8,8 @@ rc = 1 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 dda48cc2..30227655 100755 --- a/test/broker/03-publish-b2c-disconnect-qos2.py +++ b/test/broker/03-publish-b2c-disconnect-qos2.py @@ -6,8 +6,8 @@ rc = 1 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 4eb82ae5..7be55611 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 b3f0e765..28623a02 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 02dc238b..d45ffadc 100755 --- a/test/broker/03-publish-c2b-disconnect-qos2.py +++ b/test/broker/03-publish-c2b-disconnect-qos2.py @@ -6,7 +6,7 @@ rc = 1 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 753c571d..5f9957fe 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 22f5603e..17265460 100755 --- a/test/broker/05-clean-session-qos1.py +++ b/test/broker/05-clean-session-qos1.py @@ -8,8 +8,8 @@ rc = 1 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 ff1328fc..e64cf2f8 100755 --- a/test/broker/11-persistent-subscription.py +++ b/test/broker/11-persistent-subscription.py @@ -21,7 +21,7 @@ connect_packet = mosq_test.gen_connect( "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 b4a4b125..891ce73e 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 b7abd592..bc6e2e1a 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 51f48550..75e4c9d9 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 897f2eb8..9e2853b3 100644 --- a/lib/send_mosq.h +++ b/lib/send_mosq.h @@ -21,7 +21,7 @@ Contributors: 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 c1d81e0e..41b5e9ce 100644 --- a/lib/send_publish.c +++ b/lib/send_publish.c @@ -37,7 +37,7 @@ Contributors: #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 e00c9ada..56f4eb91 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 1520f22d..a4953e47 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 9ef56812..d288a671 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 00000000..3ba16773 --- /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 f6434d75..4dedbc2f 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 277b972e..d9d243c8 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -36,6 +36,7 @@ tests = [ (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 a3eac687..1e057138 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 46dbf51c..86c314df 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 74a5a8d6..3133e93a 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 56f4eb91..e5ebf0e4 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 d288a671..48530100 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 739cd4d6..7a4f6198 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 ccb53651..78ba9ebe 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 e0e0f5a8..0cbcf44e 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 0baf82a5..207f44c6 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 00000000..b8b139b2 --- /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 4dedbc2f..be1f8425 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 d9d243c8..e2966d0e 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -37,6 +37,7 @@ tests = [ (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 891ce73e..95cab4a1 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 04bb2231..394eb0e8 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 00000000..8ff512ea --- /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 be1f8425..713893db 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 e2966d0e..adaf32ba 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -37,6 +37,7 @@ tests = [ (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 8174eca0..b47faff1 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 00000000..b7851f9f --- /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 713893db..ecf35df3 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 adaf32ba..441946fc 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -52,6 +52,7 @@ tests = [ (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 95cab4a1..c278cfbb 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 a4953e47..fd659fb7 100644 --- a/src/handle_auth.c +++ b/src/handle_auth.c @@ -23,6 +23,7 @@ Contributors: #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 148e7174..8defeb42 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 00000000..a79c19e2 --- /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 ecf35df3..790f2de3 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 441946fc..60fdad43 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -47,6 +47,7 @@ tests = [ (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 c278cfbb..f3a9d973 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 2aceb0a5..cfe43754 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 686006fc..b1dc84f9 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 265c106d..8439e43b 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 ba8864db..abc7430a 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 660bf1ac..56b5c73e 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 c92571aa..5abfd2e0 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 5e4f08ea..b2d86216 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 187d0aac..baf6e313 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 | 22 +++++++++++++--------- lib/util_mosq.c | 3 +++ src/mosquitto_passwd.c | 2 ++ 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index abc7430a..0d96ad9f 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 09a26042..6ff60a93 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); - ERR_free_strings(); - EVP_cleanup(); +# if OPENSSL_VERSION_NUMBER < 0x10100000L || OPENSSL_API_COMPAT < 0x10100000L CRYPTO_cleanup_all_ex_data(); + ERR_free_strings(); + ERR_remove_state(0); + EVP_cleanup(); + +# 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 d98bbde4..72666872 100644 --- a/lib/util_mosq.c +++ b/lib/util_mosq.c @@ -28,6 +28,9 @@ Contributors: # 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 5b303c1a..c9d5cbe8 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 0968d326..c995babe 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 0d96ad9f..79c6bbe4 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 79c6bbe4..48a7614b 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 6ff60a93..2473da4c 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 ea729665..702034db 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 e7d597f7..ea524c1f 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 2473da4c..c7de615a 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 48a7614b..9f7a860b 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 9f7a860b..b9faac5a 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 d5dcc50b..df7a3725 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 df7a3725..8b212e2d 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 b9faac5a..6bb4cae9 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 37788456..b86c26d7 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 59eea1b7..a610af39 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 56660987..81f33ebb 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 f6c50b8b..c7359446 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 85b82185..42385003 100644 --- a/lib/messages_mosq.h +++ b/lib/messages_mosq.h @@ -21,11 +21,11 @@ Contributors: 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 d2f482d1..2f76de12 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 bf13eebb..0b69a8cc 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 00000000..6c38d9b6 --- /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 00000000..9f926fd0 --- /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 00000000..e228c3d5 --- /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 00000000..67189990 --- /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 00000000..acaac552 --- /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 c70f1f7d..08f1b0ff 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 f39049e1..a9d9a9a0 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -28,6 +28,11 @@ tests = [ (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 6ac446f6..163c222e 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 6bb4cae9..c7146ff5 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 26d8b59e..743020c1 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 00000000..6a865234 --- /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 08f1b0ff..3299d7db 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 a9d9a9a0..eb10895d 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -100,6 +100,7 @@ tests = [ (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 a28f2eb1..10323323 100644 --- a/test/mosq_test.py +++ b/test/mosq_test.py @@ -6,7 +6,7 @@ import struct 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 c7146ff5..215ca204 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 743020c1..5a886a53 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 00000000..a6d71cf6 --- /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 3299d7db..d3b3e438 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 eb10895d..28f14f97 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -90,6 +90,7 @@ tests = [ (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 | 184 ++++++++++++------ 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, 646 insertions(+), 174 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 215ca204..6d22cf5c 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 8b212e2d..d941c985 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 96450050..e8c43397 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 c995babe..f81219f3 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 2f76de12..8253cb41 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 @@ error: 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 13ae261b..202af870 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 e009cce5..62bf24be 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 @@ error: 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 b9b0fefd..f47edb3b 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 54976afc..76b3ee89 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 @@ process_bad_message: 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 0b69a8cc..c3655981 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 3299356d..2f400869 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 @@ error: 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){ - mosquitto__free(load); - fclose(db_fptr); - log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); - return MOSQ_ERR_NOMEM; - } - read_e(db_fptr, source_id, slen); - source_id[slen] = '\0'; + 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); + 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, &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 @@ error: 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 63a1a0cd..04f26342 100644 --- a/src/persist.h +++ b/src/persist.h @@ -17,7 +17,7 @@ Contributors: #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 5a886a53..44089d9b 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 5953055c..bae4cb43 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 00000000..c26ebe5f --- /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 00000000..d383908e --- /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 00000000..4ef51275 --- /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 d3b3e438..715b97c7 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 28f14f97..f21ae8ce 100755 --- a/test/broker/ptest.py +++ b/test/broker/ptest.py @@ -57,6 +57,9 @@ tests = [ (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 d941c985..9f164f16 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 6d22cf5c..0c59e5ad 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 0ee3fa44..ce92090d 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 44f00187..3fba92a2 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 0ebd8d4a..ec4e6b70 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 0c59e5ad..f17e68a0 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 f81219f3..8479fd25 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 f17e68a0..e72b9211 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 72666872..350d1ccc 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 e72b9211..46e45e39 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 c6b3d6e5..55d38626 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 e8cbfdfc..b7e47565 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 8d084749..980de518 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 c3655981..31305841 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 46e45e39..f4a9ddcf 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 163c222e..4db2e8df 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 f4a9ddcf..7785799e 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 c7de615a..ed783cad 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 350d1ccc..4caed72b 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 9f164f16..60337bf9 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 e8c43397..d0ec0df7 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 7785799e..3764ebfd 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 76b3ee89..2402869b 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 ed783cad..3d472597 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 56b5c73e..8daeda6a 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 8f993dc9..981eea3a 100644 --- a/client/client_shared.c +++ b/client/client_shared.c @@ -34,7 +34,9 @@ Contributors: #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 @@ unknown_option: 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 8479fd25..14d35284 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 b7e47565..0a9ac175 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 980de518..7535b6d0 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 8439e43b..d37dc207 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 3764ebfd..322a23a1 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 ce92090d..98210587 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 0574e0b1..bdcff77c 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 5e9706c4..9368779d 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 57a22ec3..767b854a 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 ec105f6b..69469c88 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 b337fe0b..970ae55c 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 2c9b15c6..0681f4ed 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 322a23a1..b6dd793f 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 6e4b94fa..d9611f0d 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 b6dd793f..c5516f1a 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 14d35284..0e822c95 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 | 80 +++++++++---------------------------------- src/conf_includedir.c | 13 +++++-- 3 files changed, 28 insertions(+), 67 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index c5516f1a..e64cf37c 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 0e822c95..aea01f0d 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); - } + log__printf(NULL, MOSQ_LOG_ERR, "Error found at %s:%d.", files[i], lineno_ext); + /* Free happens below */ + break; } } - closedir(dh); -#endif + 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 e64cf37c..cbe6ae2c 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 2f400869..13b34d2c 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 cbe6ae2c..dcd4a965 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 4caed72b..ee1ddf07 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 c689ba75..7a4a3d04 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 45a2d311..18fbceb1 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 41dd9d94..335cb9f0 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 52b4bd60..b6b766fb 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 | 46 +++++++++++++++----------------------------- 1 file changed, 15 insertions(+), 31 deletions(-) diff --git a/test/broker/ptest.py b/test/broker/ptest.py index b6b766fb..df029c1e 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() + proc_ports = () - 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: + 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 31d43edd..66ff2ef2 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 bfa5bc11..836a9b82 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 @@ write_config(conf_file, 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 @@ try: 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 60d08305..97b8f432 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 @@ write_config(conf_file, 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 @@ try: 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 7df9a3b2..f31141e7 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 @@ write_config(conf_file, 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 @@ ssock = ssl.wrap_socket(sock, ca_certs="../ssl/test-root-ca.crt", cert_reqs=ssl. 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 76448dfe..28473325 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 df029c1e..200cf55b 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 @@ tests = [ (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 49f3088b..d88f58a1 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 c12142a1..00000000 --- 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 00000000..76d7dc0d --- /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 00000000..233f609e --- /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 d37dc207..ea6e0733 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 39059ed7..cf4bef62 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 bdcff77c..15c356f0 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 9368779d..2da63198 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 1b3517cb..480937b5 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 69469c88..5cb46a3c 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 6eb584a1..dced140b 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 6fb24e2d..03d4025a 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 c9981390..3a2ac517 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 ee0c8333..9a310fac 100644 --- a/src/send_unsuback.c +++ b/src/send_unsuback.c @@ -25,7 +25,7 @@ Contributors: #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 00000000..1e6c3f53 --- /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 28473325..3b5b6fe1 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 200cf55b..526f5860 100755 --- a/test/broker/test.py +++ b/test/broker/test.py @@ -57,6 +57,7 @@ tests = [ (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 e9da563f..bb5e9147 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 03d4025a..075bde44 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 3a2ac517..7d02f432 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 3a7480ee..9fe52d52 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 1e6c3f53..bbbc40cd 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 a05a1539..2936c33b 100755 --- a/test/broker/02-unsubscribe-qos2-v5.py +++ b/test/broker/02-unsubscribe-qos2-v5.py @@ -12,7 +12,7 @@ connect_packet = mosq_test.gen_connect("unsubscribe-qos2-test", keepalive=keepal 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 00000000..9b55d276 --- /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 d88f58a1..00d963a7 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 00000000..50e7377b --- /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 f02beb90..79552efc 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 76d7dc0d..29c309bc 100755 --- a/test/lib/test.py +++ b/test/lib/test.py @@ -15,6 +15,7 @@ tests = [ (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 bc6e2e1a..3779318e 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 48530100..b853a9b8 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 00000000..af564e6a --- /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 00d963a7..9e55b52a 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 00000000..7403a633 --- /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 79552efc..d89ab9ab 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 29c309bc..68df8855 100755 --- a/test/lib/test.py +++ b/test/lib/test.py @@ -16,6 +16,7 @@ tests = [ (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 9fe52d52..ad71b73f 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 4f9c1a1d..c25dda54 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 @@ 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) +# 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 @@ publish2r_packet = mosq_test.gen_publish("subpub/test/id2", qos=0, payload="mess 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 @@ try: 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 f4770bc5..a11aa5dc 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 a72fc722..001b99aa 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 509cd7d0..2dac17dc 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 22728cd7..503fb523 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 41b5e9ce..e72572c6 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 750c6b4b..591684da 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 ee76b2c4..654c802b 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 d51179b0..927d4d1e 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 00000000..11936088 --- /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 00000000..9db5ad39 --- /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 3b5b6fe1..95c0458f 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 526f5860..e35627d6 100755 --- a/test/broker/test.py +++ b/test/broker/test.py @@ -142,6 +142,8 @@ tests = [ (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 3779318e..cc3c4222 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -24,6 +24,7 @@ Contributors: #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 1b13e28a..1f8a9400 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 a11aa5dc..7a5e41d3 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 00000000..946b7139 --- /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 9e55b52a..b9d9b96b 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 00000000..c96526f5 --- /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 d89ab9ab..4eed7da0 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 68df8855..b6520ef5 100755 --- a/test/lib/test.py +++ b/test/lib/test.py @@ -41,6 +41,7 @@ tests = [ (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 00000000..6371db3c --- /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 65b21529..45690d65 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 2dac17dc..abc03922 100644 --- a/lib/packet_mosq.c +++ b/lib/packet_mosq.c @@ -36,6 +36,7 @@ Contributors: #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 30395759..5b70e113 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 550a3dd2..248417b7 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 c8d22c07..9f061cf1 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 7d02f432..58e7d44a 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 927d4d1e..5b12bbc8 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 00000000..7d76d868 --- /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 95c0458f..6901f11b 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 e35627d6..fdef41d7 100755 --- a/test/broker/test.py +++ b/test/broker/test.py @@ -142,6 +142,7 @@ tests = [ (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 591684da..0755b174 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 00000000..87388bdb --- /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 00000000..05e38e8d --- /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 6901f11b..440c38f2 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 fdef41d7..f93d9c31 100755 --- a/test/broker/test.py +++ b/test/broker/test.py @@ -145,6 +145,8 @@ tests = [ (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)