From b85f4dc35c870eb2da8887bbc56d64ce95e8abdb Mon Sep 17 00:00:00 2001 From: Kenneth Finnegan Date: Tue, 25 Apr 2017 20:39:09 -0700 Subject: [PATCH 01/17] Corrected time data types in esp8266 example The millis() function returns unsigned longs, not longs. --- examples/mqtt_esp8266/mqtt_esp8266.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/mqtt_esp8266/mqtt_esp8266.ino b/examples/mqtt_esp8266/mqtt_esp8266.ino index 34333c9..b45147b 100644 --- a/examples/mqtt_esp8266/mqtt_esp8266.ino +++ b/examples/mqtt_esp8266/mqtt_esp8266.ino @@ -34,7 +34,7 @@ const char* mqtt_server = "broker.mqtt-dashboard.com"; WiFiClient espClient; PubSubClient client(espClient); -long lastMsg = 0; +unsigned long lastMsg = 0; char msg[50]; int value = 0; @@ -120,7 +120,7 @@ void loop() { } client.loop(); - long now = millis(); + unsigned long now = millis(); if (now - lastMsg > 2000) { lastMsg = now; ++value; From 98ad16eff8848bffeb812c4d347dfdb5ddef5a31 Mon Sep 17 00:00:00 2001 From: Kenneth Finnegan Date: Tue, 25 Apr 2017 20:43:54 -0700 Subject: [PATCH 02/17] Correct buffer overflow and remove magic constants from esp8266 example The msg[] array is defined as 50 bytes long, but then the snprintf is protected at 75 bytes long, which is incorrectly 25 bytes longer than the underlying array. To correct this, define a new macro MSG_BUFFER_SIZE and use it in both places: * defining msg[] * writing to msg[] with snprintf() --- examples/mqtt_esp8266/mqtt_esp8266.ino | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/mqtt_esp8266/mqtt_esp8266.ino b/examples/mqtt_esp8266/mqtt_esp8266.ino index b45147b..79d2c14 100644 --- a/examples/mqtt_esp8266/mqtt_esp8266.ino +++ b/examples/mqtt_esp8266/mqtt_esp8266.ino @@ -35,7 +35,8 @@ const char* mqtt_server = "broker.mqtt-dashboard.com"; WiFiClient espClient; PubSubClient client(espClient); unsigned long lastMsg = 0; -char msg[50]; +#define MSG_BUFFER_SIZE (50) +char msg[MSG_BUFFER_SIZE]; int value = 0; void setup_wifi() { @@ -124,7 +125,7 @@ void loop() { if (now - lastMsg > 2000) { lastMsg = now; ++value; - snprintf (msg, 75, "hello world #%ld", value); + snprintf (msg, MSG_BUFFER_SIZE, "hello world #%ld", value); Serial.print("Publish message: "); Serial.println(msg); client.publish("outTopic", msg); From 54043f5469a307157d990b64454f5e8b30365a81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Augusto?= Date: Tue, 14 Nov 2017 22:34:33 -0300 Subject: [PATCH 03/17] Start --- nada.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 nada.txt diff --git a/nada.txt b/nada.txt new file mode 100644 index 0000000..1fa1684 --- /dev/null +++ b/nada.txt @@ -0,0 +1 @@ +nada From 4fa0226cce08ea56e41e0b5d702ff56f119db374 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 16 Nov 2017 11:45:33 -0800 Subject: [PATCH 04/17] Add some comments --- src/PubSubClient.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/PubSubClient.cpp b/src/PubSubClient.cpp index 5932bdb..9d50e8a 100755 --- a/src/PubSubClient.cpp +++ b/src/PubSubClient.cpp @@ -363,10 +363,14 @@ boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigne // Leave room in the buffer for header and variable length field uint16_t length = 5; length = writeString(topic,buffer,length); + + // Add payload uint16_t i; for (i=0;i Date: Thu, 16 Nov 2017 16:37:41 -0800 Subject: [PATCH 05/17] Updated documentation. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8317691..f429443 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Full API documentation is available here: http://pubsubclient.knolleary.net - It can only publish QoS 0 messages. It can subscribe at QoS 0 or QoS 1. - The maximum message size, including header, is **128 bytes** by default. This - is configurable via `MQTT_MAX_PACKET_SIZE` in `PubSubClient.h`. + is configurable via `MQTT_MAX_PACKET_SIZE` in `PubSubClient.h`. Longer messages can also be sent with the `publish_P()` method. - The keepalive interval is set to 15 seconds by default. This is configurable via `MQTT_KEEPALIVE` in `PubSubClient.h`. - The client uses MQTT 3.1.1 by default. It can be changed to use MQTT 3.1 by From 6bc3b76a9b3a8a79e3dfc1af78ccacf29d549fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Augusto?= Date: Thu, 7 Dec 2017 12:20:23 -0300 Subject: [PATCH 06/17] Adding improvments --- .gitignore | 4 ++++ examples/mqtt_esp8266/mqtt_esp8266.ino | 5 ----- src/PubSubClient.cpp | 18 +++++++++++++----- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 1c3ba18..a42cc40 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,5 @@ tests/bin +.pioenvs +.piolibdeps +.clang_complete +.gcc-flags.json diff --git a/examples/mqtt_esp8266/mqtt_esp8266.ino b/examples/mqtt_esp8266/mqtt_esp8266.ino index 34333c9..ef4ab28 100644 --- a/examples/mqtt_esp8266/mqtt_esp8266.ino +++ b/examples/mqtt_esp8266/mqtt_esp8266.ino @@ -1,26 +1,21 @@ /* Basic ESP8266 MQTT example - This sketch demonstrates the capabilities of the pubsub library in combination with the ESP8266 board/library. - It connects to an MQTT server then: - publishes "hello world" to the topic "outTopic" every two seconds - subscribes to the topic "inTopic", printing out any messages it receives. NB - it assumes the received payloads are strings not binary - If the first character of the topic "inTopic" is an 1, switch ON the ESP Led, else switch it off - It will reconnect to the server if the connection is lost using a blocking reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to achieve the same result without blocking the main loop. - To install the ESP8266 board, (using Arduino 1.6.4+): - Add the following 3rd party board manager under "File -> Preferences -> Additional Boards Manager URLs": http://arduino.esp8266.com/stable/package_esp8266com_index.json - Open the "Tools -> Board -> Board Manager" and click install for the ESP8266" - Select your ESP8266 in "Tools -> Board" - */ #include diff --git a/src/PubSubClient.cpp b/src/PubSubClient.cpp index 5932bdb..1e12375 100755 --- a/src/PubSubClient.cpp +++ b/src/PubSubClient.cpp @@ -1,4 +1,5 @@ /* + PubSubClient.cpp - A simple client for MQTT. Nick O'Leary http://knolleary.net @@ -243,7 +244,8 @@ uint16_t PubSubClient::readPacket(uint8_t* lengthLength) { if(!readByte(&digit)) return 0; buffer[len++] = digit; length += (digit & 127) * multiplier; - multiplier *= 128; + //multiplier *= 128; replace by multiplier <<=7; + multiplier <<=7; } while ((digit & 128) != 0); *lengthLength = len-1; @@ -399,8 +401,11 @@ boolean PubSubClient::publish_P(const char* topic, const uint8_t* payload, unsig buffer[pos++] = header; len = plength + 2 + tlen; do { - digit = len % 128; - len = len / 128; + //digit = len %128; replace by digit = len & 127; + digit = len & 127; + + //len = len / 128; replace by len >>= 7; + len >>= 7; if (len > 0) { digit |= 0x80; } @@ -429,8 +434,11 @@ boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) { uint16_t rc; uint16_t len = length; do { - digit = len % 128; - len = len / 128; + //digit = len %128; replace by digit = len & 127; + digit = len & 127; + + //len = len / 128; replace by len >>= 7; + len >>= 7; if (len > 0) { digit |= 0x80; } From 3b0775a91d2168000f370d89628ecb818de4a7e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Augusto?= Date: Thu, 7 Dec 2017 15:31:24 -0300 Subject: [PATCH 07/17] Excluding nada.txt which was empty and improving indentation --- nada.txt | 1 - src/PubSubClient.cpp | 16 +++++----------- 2 files changed, 5 insertions(+), 12 deletions(-) delete mode 100644 nada.txt diff --git a/nada.txt b/nada.txt deleted file mode 100644 index 1fa1684..0000000 --- a/nada.txt +++ /dev/null @@ -1 +0,0 @@ -nada diff --git a/src/PubSubClient.cpp b/src/PubSubClient.cpp index 1e12375..7686c8b 100755 --- a/src/PubSubClient.cpp +++ b/src/PubSubClient.cpp @@ -244,8 +244,7 @@ uint16_t PubSubClient::readPacket(uint8_t* lengthLength) { if(!readByte(&digit)) return 0; buffer[len++] = digit; length += (digit & 127) * multiplier; - //multiplier *= 128; replace by multiplier <<=7; - multiplier <<=7; + multiplier <<=7; //multiplier *= 128 } while ((digit & 128) != 0); *lengthLength = len-1; @@ -401,11 +400,8 @@ boolean PubSubClient::publish_P(const char* topic, const uint8_t* payload, unsig buffer[pos++] = header; len = plength + 2 + tlen; do { - //digit = len %128; replace by digit = len & 127; - digit = len & 127; - - //len = len / 128; replace by len >>= 7; - len >>= 7; + digit = len & 127; //digit = len %128 + len >>= 7; //len = len / 128 if (len > 0) { digit |= 0x80; } @@ -434,11 +430,9 @@ boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) { uint16_t rc; uint16_t len = length; do { - //digit = len %128; replace by digit = len & 127; - digit = len & 127; - //len = len / 128; replace by len >>= 7; - len >>= 7; + digit = len & 127; //digit = len %128 + len >>= 7; //len = len / 128 if (len > 0) { digit |= 0x80; } From 2dca84a77682f2a4e845dac20c4f5ae6b1fd349a Mon Sep 17 00:00:00 2001 From: Alex Ignatov Date: Wed, 21 Nov 2018 03:09:08 +0200 Subject: [PATCH 08/17] Fix publish() when payload == NULL Messages with empty payload are completely valid and are actually useful (e.g., to delete retained value). This adds a check before calling `strlen()` to prevent crash when using shortcut methods taking `const char*` --- src/PubSubClient.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PubSubClient.cpp b/src/PubSubClient.cpp index 0fa420d..aca2181 100755 --- a/src/PubSubClient.cpp +++ b/src/PubSubClient.cpp @@ -366,11 +366,11 @@ boolean PubSubClient::loop() { } boolean PubSubClient::publish(const char* topic, const char* payload) { - return publish(topic,(const uint8_t*)payload,strlen(payload),false); + return publish(topic,(const uint8_t*)payload, payload ? strlen(payload) : 0,false); } boolean PubSubClient::publish(const char* topic, const char* payload, boolean retained) { - return publish(topic,(const uint8_t*)payload,strlen(payload),retained); + return publish(topic,(const uint8_t*)payload, payload ? strlen(payload) : 0,retained); } boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength) { @@ -400,7 +400,7 @@ boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigne } boolean PubSubClient::publish_P(const char* topic, const char* payload, boolean retained) { - return publish_P(topic, (const uint8_t*)payload, strlen(payload), retained); + return publish_P(topic, (const uint8_t*)payload, payload ? strlen(payload) : 0, retained); } boolean PubSubClient::publish_P(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) { From b6239823fba189e7c1bd518dd8121a934c240a61 Mon Sep 17 00:00:00 2001 From: Guy Turcotte Date: Mon, 28 Jan 2019 18:02:37 -0500 Subject: [PATCH 09/17] Allow streaming of large messages These changes are required to allow for the transmission of large messages through a connected stream. The changes do not have an impact on the class interface and habitual behavior. In particular, it will enable the use of OTA through a stream hooked through the setStream() class method. I've designed such a stream to demonstrate the functionality: https://github.com/turgu1/mqtt_ota_example.git Guy --- src/PubSubClient.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/PubSubClient.cpp b/src/PubSubClient.cpp index 0fa420d..bd934b3 100755 --- a/src/PubSubClient.cpp +++ b/src/PubSubClient.cpp @@ -197,7 +197,7 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass } } uint8_t llen; - uint16_t len = readPacket(&llen); + uint32_t len = readPacket(&llen); if (len == 4) { if (buffer[3] == 0) { @@ -243,12 +243,12 @@ boolean PubSubClient::readByte(uint8_t * result, uint16_t * index){ return false; } -uint16_t PubSubClient::readPacket(uint8_t* lengthLength) { +uint32_t PubSubClient::readPacket(uint8_t* lengthLength) { uint16_t len = 0; if(!readByte(buffer, &len)) return 0; bool isPublish = (buffer[0]&0xF0) == MQTTPUBLISH; uint32_t multiplier = 1; - uint16_t length = 0; + uint32_t length = 0; uint8_t digit = 0; uint16_t skip = 0; uint8_t start = 0; @@ -279,20 +279,22 @@ uint16_t PubSubClient::readPacket(uint8_t* lengthLength) { } } - for (uint16_t i = start;istream) { - if (isPublish && len-*lengthLength-2>skip) { + if (isPublish && idx-*lengthLength-2>skip) { this->stream->write(digit); } } if (len < MQTT_MAX_PACKET_SIZE) { buffer[len] = digit; + len++; } - len++; + idx++; } - if (!this->stream && len > MQTT_MAX_PACKET_SIZE) { + if (!this->stream && idx > MQTT_MAX_PACKET_SIZE) { len = 0; // This will cause the packet to be ignored. } From 373c7d3569061af1ff6cc04564656a531ae21329 Mon Sep 17 00:00:00 2001 From: Guy Turcotte Date: Mon, 28 Jan 2019 18:47:18 -0500 Subject: [PATCH 10/17] Update PubSubClient.h --- src/PubSubClient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PubSubClient.h b/src/PubSubClient.h index 2fd6f1d..9fb8bcc 100755 --- a/src/PubSubClient.h +++ b/src/PubSubClient.h @@ -94,7 +94,7 @@ private: unsigned long lastInActivity; bool pingOutstanding; MQTT_CALLBACK_SIGNATURE; - uint16_t readPacket(uint8_t*); + uint32_t readPacket(uint8_t*); boolean readByte(uint8_t * result); boolean readByte(uint8_t * result, uint16_t * index); boolean write(uint8_t header, uint8_t* buf, uint16_t length); From e7d9688ca53361d4125ba5983844624b3d11f8e4 Mon Sep 17 00:00:00 2001 From: Guy Turcotte Date: Tue, 29 Jan 2019 08:43:30 -0500 Subject: [PATCH 11/17] Update receive_spec.cpp --- tests/src/receive_spec.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/src/receive_spec.cpp b/tests/src/receive_spec.cpp index 9a18af0..923ce25 100644 --- a/tests/src/receive_spec.cpp +++ b/tests/src/receive_spec.cpp @@ -190,7 +190,7 @@ int test_drop_invalid_remaining_length_message() { int test_receive_oversized_stream_message() { - IT("drops an oversized message"); + IT("receive an oversized streamed message"); reset_callback(); Stream stream; @@ -222,7 +222,7 @@ int test_receive_oversized_stream_message() { IS_TRUE(callback_called); IS_TRUE(strcmp(lastTopic,"topic")==0); - IS_TRUE(lastLength == length-9); + IS_TRUE(lastLength == 0); IS_FALSE(stream.error()); IS_FALSE(shimClient.error()); From 7d6e409b59c30f01b379313475657787692656b3 Mon Sep 17 00:00:00 2001 From: Guy Turcotte Date: Tue, 29 Jan 2019 08:59:35 -0500 Subject: [PATCH 12/17] Update receive_spec.cpp --- tests/src/receive_spec.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/src/receive_spec.cpp b/tests/src/receive_spec.cpp index 923ce25..199033a 100644 --- a/tests/src/receive_spec.cpp +++ b/tests/src/receive_spec.cpp @@ -222,7 +222,7 @@ int test_receive_oversized_stream_message() { IS_TRUE(callback_called); IS_TRUE(strcmp(lastTopic,"topic")==0); - IS_TRUE(lastLength == 0); + IS_TRUE(lastLength == MQTT_MAX_PACKET_SIZE); IS_FALSE(stream.error()); IS_FALSE(shimClient.error()); From b25040a0d7880457b370bb210496f5545e3ffbbf Mon Sep 17 00:00:00 2001 From: Guy Turcotte Date: Tue, 29 Jan 2019 09:05:26 -0500 Subject: [PATCH 13/17] Update receive_spec.cpp --- tests/src/receive_spec.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/src/receive_spec.cpp b/tests/src/receive_spec.cpp index 199033a..185f19b 100644 --- a/tests/src/receive_spec.cpp +++ b/tests/src/receive_spec.cpp @@ -222,7 +222,7 @@ int test_receive_oversized_stream_message() { IS_TRUE(callback_called); IS_TRUE(strcmp(lastTopic,"topic")==0); - IS_TRUE(lastLength == MQTT_MAX_PACKET_SIZE); + IS_TRUE(lastLength == MQTT_MAX_PACKET_SIZE-9); IS_FALSE(stream.error()); IS_FALSE(shimClient.error()); From a4f7821a70371fded515c82cf73f058353d907ef Mon Sep 17 00:00:00 2001 From: Kevin Leung Date: Mon, 4 Feb 2019 00:07:05 +0800 Subject: [PATCH 14/17] Support pre-connected Client --- src/PubSubClient.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/PubSubClient.cpp b/src/PubSubClient.cpp index 0fa420d..859d75c 100755 --- a/src/PubSubClient.cpp +++ b/src/PubSubClient.cpp @@ -121,11 +121,17 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass if (!connected()) { int result = 0; - if (domain != NULL) { - result = _client->connect(this->domain, this->port); + + if(_client->connected()) { + result = 1; } else { - result = _client->connect(this->ip, this->port); + if (domain != NULL) { + result = _client->connect(this->domain, this->port); + } else { + result = _client->connect(this->ip, this->port); + } } + if (result == 1) { nextMsgId = 1; // Leave room in the buffer for header and variable length field @@ -610,6 +616,8 @@ boolean PubSubClient::connected() { _client->flush(); _client->stop(); } + } else { + return this->_state == MQTT_CONNECTED; } } return rc; From 1b9f52b1fcb12f7e32fc8b4a3b22d93e1e64b479 Mon Sep 17 00:00:00 2001 From: lucian Date: Sun, 7 Apr 2019 22:19:47 +0300 Subject: [PATCH 15/17] Fix publish_P return value --- src/PubSubClient.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/PubSubClient.cpp b/src/PubSubClient.cpp index 0fa420d..b1d338e 100755 --- a/src/PubSubClient.cpp +++ b/src/PubSubClient.cpp @@ -412,6 +412,7 @@ boolean PubSubClient::publish_P(const char* topic, const uint8_t* payload, unsig unsigned int i; uint8_t header; unsigned int len; + int expectedLength; if (!connected()) { return false; @@ -445,7 +446,9 @@ boolean PubSubClient::publish_P(const char* topic, const uint8_t* payload, unsig lastOutActivity = millis(); - return rc == tlen + 4 + plength; + expectedLength = 1 + llen + 2 + tlen + plength; + + return (rc == expectedLength); } boolean PubSubClient::beginPublish(const char* topic, unsigned int plength, boolean retained) { From d88909db3e0330be8323a8a8910c62d987b5ab9f Mon Sep 17 00:00:00 2001 From: Leo Zimmermann Date: Tue, 24 Dec 2019 11:08:59 +0100 Subject: [PATCH 16/17] declare wifi mode prior to connect must have statement for current Arduino Framework, see also https://github.com/knolleary/pubsubclient/issues/138#issuecomment-326113915 --- examples/mqtt_esp8266/mqtt_esp8266.ino | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/mqtt_esp8266/mqtt_esp8266.ino b/examples/mqtt_esp8266/mqtt_esp8266.ino index 8e5f0da..7e6effd 100644 --- a/examples/mqtt_esp8266/mqtt_esp8266.ino +++ b/examples/mqtt_esp8266/mqtt_esp8266.ino @@ -42,6 +42,7 @@ void setup_wifi() { Serial.print("Connecting to "); Serial.println(ssid); + WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { From 6099ee028fbb9b98c439f82d8592aea53a37fbb2 Mon Sep 17 00:00:00 2001 From: Andrei Balasescu Date: Sun, 12 Apr 2020 01:20:08 +0300 Subject: [PATCH 17/17] Added check to prevent subscribe/unsubscribe to empty topics --- src/PubSubClient.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/PubSubClient.cpp b/src/PubSubClient.cpp index 70c3b27..a89ff8b 100755 --- a/src/PubSubClient.cpp +++ b/src/PubSubClient.cpp @@ -548,10 +548,14 @@ boolean PubSubClient::subscribe(const char* topic) { } boolean PubSubClient::subscribe(const char* topic, uint8_t qos) { + size_t topicLength = strlen(topic); + if (topic == 0) { + return false; + } if (qos > 1) { return false; } - if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) { + if (MQTT_MAX_PACKET_SIZE < 9 + topicLength) { // Too long return false; } @@ -572,7 +576,11 @@ boolean PubSubClient::subscribe(const char* topic, uint8_t qos) { } boolean PubSubClient::unsubscribe(const char* topic) { - if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) { + size_t topicLength = strlen(topic); + if (topic == 0) { + return false; + } + if (MQTT_MAX_PACKET_SIZE < 9 + topicLength) { // Too long return false; }