From b85f4dc35c870eb2da8887bbc56d64ce95e8abdb Mon Sep 17 00:00:00 2001 From: Kenneth Finnegan Date: Tue, 25 Apr 2017 20:39:09 -0700 Subject: [PATCH 01/46] 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/46] 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 bef58148582f956dfa772687db80c44e2279a163 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Wed, 7 Jun 2017 20:37:45 +0100 Subject: [PATCH 03/46] Add test for blank (not-null) password --- tests/src/connect_spec.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/src/connect_spec.cpp b/tests/src/connect_spec.cpp index 69f1864..3c46e0c 100644 --- a/tests/src/connect_spec.cpp +++ b/tests/src/connect_spec.cpp @@ -133,6 +133,23 @@ int test_connect_accepts_username_no_password() { END_IT } +int test_connect_accepts_username_blank_password() { + IT("accepts a username and blank password"); + ShimClient shimClient; + shimClient.setAllowConnect(true); + + byte connect[] = { 0x10,0x20,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0xc2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x4,0x75,0x73,0x65,0x72,0x0,0x0}; + byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; + shimClient.expect(connect,0x26); + shimClient.respond(connack,4); + + PubSubClient client(server, 1883, callback, shimClient); + int rc = client.connect((char*)"client_test1",(char*)"user",(char*)"pass"); + IS_TRUE(rc); + IS_FALSE(shimClient.error()); + + END_IT +} int test_connect_ignores_password_no_username() { IT("ignores a password but no username"); From dddfffbe0c497073d960f3b9f83c8400dc8cad6d Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Wed, 7 Jun 2017 21:31:48 +0100 Subject: [PATCH 04/46] Initialise buffer variables in test framework --- tests/src/lib/Buffer.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/src/lib/Buffer.cpp b/tests/src/lib/Buffer.cpp index 59a2fbb..f07759a 100644 --- a/tests/src/lib/Buffer.cpp +++ b/tests/src/lib/Buffer.cpp @@ -2,9 +2,13 @@ #include "Arduino.h" Buffer::Buffer() { + this->pos = 0; + this->length = 0; } Buffer::Buffer(uint8_t* buf, size_t size) { + this->pos = 0; + this->length = 0; this->add(buf,size); } bool Buffer::available() { From 49f307506b98f2cb4712694c34a070cdafcfda66 Mon Sep 17 00:00:00 2001 From: constantin Date: Mon, 18 Sep 2017 19:27:44 +0200 Subject: [PATCH 05/46] Add ESP32 callback signature to be functional like ESP8266 --- src/PubSubClient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PubSubClient.h b/src/PubSubClient.h index be4bd67..13ab692 100755 --- a/src/PubSubClient.h +++ b/src/PubSubClient.h @@ -73,7 +73,7 @@ #define MQTTQOS1 (1 << 1) #define MQTTQOS2 (2 << 1) -#ifdef ESP8266 +#if defined(ESP8266) || defined(ESP32) #include #define MQTT_CALLBACK_SIGNATURE std::function callback #else From 8498284792ed3a734097b650d064507ccd6efa29 Mon Sep 17 00:00:00 2001 From: constantin Date: Tue, 19 Sep 2017 18:10:09 +0200 Subject: [PATCH 06/46] Add ESP32 to documentation --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8317691..baa58d6 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ boards and shields, including: - TI CC3000 WiFi - [library](https://github.com/sparkfun/SFE_CC3000_Library) - Intel Galileo/Edison - ESP8266 + - ESP32 The library cannot currently be used with hardware based on the ENC28J60 chip – such as the Nanode or the Nuelectronics Ethernet Shield. For those, there is an 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 07/46] 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 08/46] 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 12:41:05 -0800 Subject: [PATCH 09/46] Create new signature to permit cleaner user code --- src/PubSubClient.cpp | 4 ++++ src/PubSubClient.h | 1 + 2 files changed, 5 insertions(+) diff --git a/src/PubSubClient.cpp b/src/PubSubClient.cpp index 5932bdb..473bff1 100755 --- a/src/PubSubClient.cpp +++ b/src/PubSubClient.cpp @@ -376,6 +376,10 @@ boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigne return false; } +boolean PubSubClient::publish_P(const char* topic, const char* payload, boolean retained) { + return publish_P(topic, (const uint8_t*)payload, strlen(payload), retained); +} + boolean PubSubClient::publish_P(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) { uint8_t llen = 0; uint8_t digit; diff --git a/src/PubSubClient.h b/src/PubSubClient.h index be4bd67..f5473ed 100755 --- a/src/PubSubClient.h +++ b/src/PubSubClient.h @@ -131,6 +131,7 @@ public: boolean publish(const char* topic, const char* payload, boolean retained); boolean publish(const char* topic, const uint8_t * payload, unsigned int plength); boolean publish(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained); + boolean publish_P(const char* topic, const char* payload, boolean retained); boolean publish_P(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained); boolean subscribe(const char* topic); boolean subscribe(const char* topic, uint8_t qos); From 1174d642ab0937bdd8934bfe8460f8f4d79debac Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 16 Nov 2017 16:37:41 -0800 Subject: [PATCH 10/46] 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 11/46] 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 12/46] 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 bb101c58e8c1bd970f3b6cde58e31d77a8c0d56a Mon Sep 17 00:00:00 2001 From: Rotzbua Date: Sat, 20 Jan 2018 01:13:10 +0100 Subject: [PATCH 13/46] Update link http->https (#384) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8317691..572b4a5 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ a server that supports MQTT. The library comes with a number of example sketches. See File > Examples > PubSubClient within the Arduino application. -Full API documentation is available here: http://pubsubclient.knolleary.net +Full API documentation is available here: https://pubsubclient.knolleary.net ## Limitations From f029640ee6365c58ebfe66ebf6bf1733d322f2ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trygve=20Laugst=C3=B8l?= Date: Fri, 23 Feb 2018 03:29:44 +0100 Subject: [PATCH 14/46] Fixing compiler warnings exposed with -Wall and -Wextra: qos can't be less than zero. (#274) --- src/PubSubClient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PubSubClient.cpp b/src/PubSubClient.cpp index 5932bdb..603fcc8 100755 --- a/src/PubSubClient.cpp +++ b/src/PubSubClient.cpp @@ -468,7 +468,7 @@ boolean PubSubClient::subscribe(const char* topic) { } boolean PubSubClient::subscribe(const char* topic, uint8_t qos) { - if (qos < 0 || qos > 1) { + if (qos > 1) { return false; } if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) { From 54be6e87db16d7dbc60d4c4674566ec08b0115c2 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Wed, 18 Jul 2018 11:02:08 +0100 Subject: [PATCH 15/46] Check remaining-length encoding is valid --- src/PubSubClient.cpp | 9 +++++++++ tests/src/receive_spec.cpp | 30 ++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/PubSubClient.cpp b/src/PubSubClient.cpp index 603fcc8..29fbbfa 100755 --- a/src/PubSubClient.cpp +++ b/src/PubSubClient.cpp @@ -240,6 +240,12 @@ uint16_t PubSubClient::readPacket(uint8_t* lengthLength) { uint8_t start = 0; do { + if (len == 6) { + // Invalid remaining length encoding - kill the connection + _state = MQTT_DISCONNECTED; + _client->stop(); + return 0; + } if(!readByte(&digit)) return 0; buffer[len++] = digit; length += (digit & 127) * multiplier; @@ -335,6 +341,9 @@ boolean PubSubClient::loop() { } else if (type == MQTTPINGRESP) { pingOutstanding = false; } + } else if (!connected()) { + // readPacket has closed the connection + return false; } } return true; diff --git a/tests/src/receive_spec.cpp b/tests/src/receive_spec.cpp index 54a62ee..4ecd439 100644 --- a/tests/src/receive_spec.cpp +++ b/tests/src/receive_spec.cpp @@ -160,6 +160,35 @@ int test_receive_oversized_message() { END_IT } +int test_drop_invalid_remaining_length_message() { + IT("drops invalid remaining length message"); + reset_callback(); + + ShimClient shimClient; + shimClient.setAllowConnect(true); + + byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; + shimClient.respond(connack,4); + + PubSubClient client(server, 1883, callback, shimClient); + int rc = client.connect((char*)"client_test1"); + IS_TRUE(rc); + + byte publish[] = {0x30,0x92,0x92,0x92,0x92,0x92,0x92,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; + shimClient.respond(publish,21); + + rc = client.loop(); + + IS_FALSE(rc); + + IS_FALSE(callback_called); + + IS_FALSE(shimClient.error()); + + END_IT +} + + int test_receive_oversized_stream_message() { IT("drops an oversized message"); reset_callback(); @@ -241,6 +270,7 @@ int main() test_receive_callback(); test_receive_stream(); test_receive_max_sized_message(); + test_drop_invalid_remaining_length_message(); test_receive_oversized_message(); test_receive_oversized_stream_message(); test_receive_qos1(); From 9e1a6e64799218f5eb3609f7097357c6e8314937 Mon Sep 17 00:00:00 2001 From: apicquot Date: Tue, 7 Aug 2018 17:29:29 -0400 Subject: [PATCH 16/46] Update PubSubClient.cpp added yield to resolve random connection failure --- src/PubSubClient.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PubSubClient.cpp b/src/PubSubClient.cpp index 29fbbfa..c7afc6a 100755 --- a/src/PubSubClient.cpp +++ b/src/PubSubClient.cpp @@ -209,6 +209,7 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass boolean PubSubClient::readByte(uint8_t * result) { uint32_t previousMillis = millis(); while(!_client->available()) { + yield(); uint32_t currentMillis = millis(); if(currentMillis - previousMillis >= ((int32_t) MQTT_SOCKET_TIMEOUT * 1000)){ return false; From 3b3a8da8d25f0d9c21e0699c1edf4e355d53f177 Mon Sep 17 00:00:00 2001 From: Adrian McEwen Date: Wed, 15 Aug 2018 17:15:04 +0100 Subject: [PATCH 17/46] Add large-payload API, make max header size a define, not magic number. --- keywords.txt | 3 ++ src/PubSubClient.cpp | 69 ++++++++++++++++++++++++++++++++++---------- src/PubSubClient.h | 25 ++++++++++++++++ 3 files changed, 81 insertions(+), 16 deletions(-) diff --git a/keywords.txt b/keywords.txt index b979588..1ee23d0 100755 --- a/keywords.txt +++ b/keywords.txt @@ -16,6 +16,9 @@ connect KEYWORD2 disconnect KEYWORD2 publish KEYWORD2 publish_P KEYWORD2 +beginPublish KEYWORD2 +endPublish KEYWORD2 +write KEYWORD2 subscribe KEYWORD2 unsubscribe KEYWORD2 loop KEYWORD2 diff --git a/src/PubSubClient.cpp b/src/PubSubClient.cpp index 29fbbfa..f60d6a0 100755 --- a/src/PubSubClient.cpp +++ b/src/PubSubClient.cpp @@ -125,7 +125,7 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass if (result == 1) { nextMsgId = 1; // Leave room in the buffer for header and variable length field - uint16_t length = 5; + uint16_t length = MQTT_MAX_HEADER_SIZE; unsigned int j; #if MQTT_VERSION == MQTT_VERSION_3_1 @@ -171,7 +171,7 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass } } - write(MQTTCONNECT,buffer,length-5); + write(MQTTCONNECT,buffer,length-MQTT_MAX_HEADER_SIZE); lastInActivity = lastOutActivity = millis(); @@ -365,12 +365,12 @@ boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigne boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) { if (connected()) { - if (MQTT_MAX_PACKET_SIZE < 5 + 2+strlen(topic) + plength) { + if (MQTT_MAX_PACKET_SIZE < MQTT_MAX_HEADER_SIZE + 2+strlen(topic) + plength) { // Too long return false; } // Leave room in the buffer for header and variable length field - uint16_t length = 5; + uint16_t length = MQTT_MAX_HEADER_SIZE; length = writeString(topic,buffer,length); uint16_t i; for (i=0;iwrite(buffer+(MQTT_MAX_HEADER_SIZE-hlen),length-(MQTT_MAX_HEADER_SIZE-hlen)); + lastOutActivity = millis(); + return (rc == (length-(MQTT_MAX_HEADER_SIZE-hlen))); + } + return false; +} + +int PubSubClient::endPublish() { + return 1; +} + +size_t PubSubClient::write(uint8_t data) { + lastOutActivity = millis(); + return _client->write(data); +} + +size_t PubSubClient::write(const uint8_t *buffer, size_t size) { + lastOutActivity = millis(); + return _client->write(buffer,size); +} + +size_t PubSubClient::buildHeader(uint8_t header, uint8_t* buf, uint16_t length) { uint8_t lenBuf[4]; uint8_t llen = 0; uint8_t digit; uint8_t pos = 0; - uint16_t rc; uint16_t len = length; do { digit = len % 128; @@ -449,12 +480,18 @@ boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) { buf[4-llen] = header; for (int i=0;i 0) && result) { @@ -466,9 +503,9 @@ boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) { } return result; #else - rc = _client->write(buf+(4-llen),length+1+llen); + rc = _client->write(buf+(MQTT_MAX_HEADER_SIZE-hlen),length+hlen); lastOutActivity = millis(); - return (rc == 1+llen+length); + return (rc == hlen+length); #endif } @@ -486,7 +523,7 @@ boolean PubSubClient::subscribe(const char* topic, uint8_t qos) { } if (connected()) { // Leave room in the buffer for header and variable length field - uint16_t length = 5; + uint16_t length = MQTT_MAX_HEADER_SIZE; nextMsgId++; if (nextMsgId == 0) { nextMsgId = 1; @@ -495,7 +532,7 @@ boolean PubSubClient::subscribe(const char* topic, uint8_t qos) { buffer[length++] = (nextMsgId & 0xFF); length = writeString((char*)topic, buffer,length); buffer[length++] = qos; - return write(MQTTSUBSCRIBE|MQTTQOS1,buffer,length-5); + return write(MQTTSUBSCRIBE|MQTTQOS1,buffer,length-MQTT_MAX_HEADER_SIZE); } return false; } @@ -506,7 +543,7 @@ boolean PubSubClient::unsubscribe(const char* topic) { return false; } if (connected()) { - uint16_t length = 5; + uint16_t length = MQTT_MAX_HEADER_SIZE; nextMsgId++; if (nextMsgId == 0) { nextMsgId = 1; @@ -514,7 +551,7 @@ boolean PubSubClient::unsubscribe(const char* topic) { buffer[length++] = (nextMsgId >> 8); buffer[length++] = (nextMsgId & 0xFF); length = writeString(topic, buffer,length); - return write(MQTTUNSUBSCRIBE|MQTTQOS1,buffer,length-5); + return write(MQTTUNSUBSCRIBE|MQTTQOS1,buffer,length-MQTT_MAX_HEADER_SIZE); } return false; } diff --git a/src/PubSubClient.h b/src/PubSubClient.h index be4bd67..dc81ff3 100755 --- a/src/PubSubClient.h +++ b/src/PubSubClient.h @@ -73,6 +73,9 @@ #define MQTTQOS1 (1 << 1) #define MQTTQOS2 (2 << 1) +// Maximum size of fixed header and variable length size header +#define MQTT_MAX_HEADER_SIZE 5 + #ifdef ESP8266 #include #define MQTT_CALLBACK_SIGNATURE std::function callback @@ -94,6 +97,11 @@ private: boolean readByte(uint8_t * result, uint16_t * index); boolean write(uint8_t header, uint8_t* buf, uint16_t length); uint16_t writeString(const char* string, uint8_t* buf, uint16_t pos); + // Build up the header ready to send + // Returns the size of the header + // Note: the header is built at the end of the first MQTT_MAX_HEADER_SIZE bytes, so will start + // (MQTT_MAX_HEADER_SIZE - ) bytes into the buffer + size_t buildHeader(uint8_t header, uint8_t* buf, uint16_t length); IPAddress ip; const char* domain; uint16_t port; @@ -132,6 +140,23 @@ public: boolean publish(const char* topic, const uint8_t * payload, unsigned int plength); boolean publish(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained); boolean publish_P(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained); + // Start to publish a message. + // This API: + // beginPublish(...) + // one or more calls to write(...) + // endPublish() + // Allows for arbitrarily large payloads to be sent without them having to be copied into + // a new buffer and held in memory at one time + // Returns 1 if the message was started successfully, 0 if there was an error + boolean beginPublish(const char* topic, unsigned int plength, boolean retained); + // Finish off this publish message (started with beginPublish) + // Returns 1 if the packet was sent successfully, 0 if there was an error + int endPublish(); + // Write a single byte of payload (only to be used with beginPublish/endPublish) + size_t write(uint8_t); + // Write size bytes from buffer into the payload (only to be used with beginPublish/endPublish) + // Returns the number of bytes written + size_t write(const uint8_t *buffer, size_t size); boolean subscribe(const char* topic); boolean subscribe(const char* topic, uint8_t qos); boolean unsubscribe(const char* topic); From c87c9a47b3d4222c4d853e1737c8329269bb1fc7 Mon Sep 17 00:00:00 2001 From: bwibwi13 Date: Sun, 19 Aug 2018 08:39:39 +0200 Subject: [PATCH 18/46] Correct maximum size of snprintf (use same size as the buffer ;) --- examples/mqtt_esp8266/mqtt_esp8266.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/mqtt_esp8266/mqtt_esp8266.ino b/examples/mqtt_esp8266/mqtt_esp8266.ino index 34333c9..e07c70d 100644 --- a/examples/mqtt_esp8266/mqtt_esp8266.ino +++ b/examples/mqtt_esp8266/mqtt_esp8266.ino @@ -124,7 +124,7 @@ void loop() { if (now - lastMsg > 2000) { lastMsg = now; ++value; - snprintf (msg, 75, "hello world #%ld", value); + snprintf (msg, 50, "hello world #%ld", value); Serial.print("Publish message: "); Serial.println(msg); client.publish("outTopic", msg); From 0c2d12d8b04a866cff04c94fa78929649a3c4521 Mon Sep 17 00:00:00 2001 From: Adrian McEwen Date: Tue, 4 Sep 2018 13:31:43 +0100 Subject: [PATCH 19/46] Allow the large message publishing to use all the `print` methods. --- src/PubSubClient.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PubSubClient.h b/src/PubSubClient.h index dc81ff3..4d80839 100755 --- a/src/PubSubClient.h +++ b/src/PubSubClient.h @@ -83,7 +83,7 @@ #define MQTT_CALLBACK_SIGNATURE void (*callback)(char*, uint8_t*, unsigned int) #endif -class PubSubClient { +class PubSubClient : public Print { private: Client* _client; uint8_t buffer[MQTT_MAX_PACKET_SIZE]; @@ -153,10 +153,10 @@ public: // Returns 1 if the packet was sent successfully, 0 if there was an error int endPublish(); // Write a single byte of payload (only to be used with beginPublish/endPublish) - size_t write(uint8_t); + virtual size_t write(uint8_t); // Write size bytes from buffer into the payload (only to be used with beginPublish/endPublish) // Returns the number of bytes written - size_t write(const uint8_t *buffer, size_t size); + virtual size_t write(const uint8_t *buffer, size_t size); boolean subscribe(const char* topic); boolean subscribe(const char* topic, uint8_t qos); boolean unsubscribe(const char* topic); From b2f3a6d2ec5a31c0f3036d3a94a19a6619e3401d Mon Sep 17 00:00:00 2001 From: Adrian McEwen Date: Tue, 4 Sep 2018 13:36:45 +0100 Subject: [PATCH 20/46] Add example code for using the large message API. --- .../mqtt_large_message/mqtt_large_message.ino | 179 ++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 examples/mqtt_large_message/mqtt_large_message.ino diff --git a/examples/mqtt_large_message/mqtt_large_message.ino b/examples/mqtt_large_message/mqtt_large_message.ino new file mode 100644 index 0000000..e048c3e --- /dev/null +++ b/examples/mqtt_large_message/mqtt_large_message.ino @@ -0,0 +1,179 @@ +/* + Long message ESP8266 MQTT example + + This sketch demonstrates sending arbitrarily large messages in combination + with the ESP8266 board/library. + + It connects to an MQTT server then: + - publishes "hello world" to the topic "outTopic" + - subscribes to the topic "greenBottles/#", printing out any messages + it receives. NB - it assumes the received payloads are strings not binary + - If the sub-topic is a number, it publishes a "greenBottles/lyrics" message + with a payload consisting of the lyrics to "10 green bottles", replacing + 10 with the number given in the sub-topic. + + 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 +#include + +// Update these with values suitable for your network. + +const char* ssid = "........"; +const char* password = "........"; +const char* mqtt_server = "broker.mqtt-dashboard.com"; + +WiFiClient espClient; +PubSubClient client(espClient); +long lastMsg = 0; +char msg[50]; +int value = 0; + +void setup_wifi() { + + delay(10); + // We start by connecting to a WiFi network + Serial.println(); + Serial.print("Connecting to "); + Serial.println(ssid); + + WiFi.begin(ssid, password); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + + randomSeed(micros()); + + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); +} + +void callback(char* topic, byte* payload, unsigned int length) { + Serial.print("Message arrived ["); + Serial.print(topic); + Serial.print("] "); + for (int i = 0; i < length; i++) { + Serial.print((char)payload[i]); + } + Serial.println(); + + // Find out how many bottles we should generate lyrics for + String topicStr(topic); + int bottleCount = 0; // assume no bottles unless we correctly parse a value from the topic + if (topicStr.indexOf('/') >= 0) { + // The topic includes a '/', we'll try to read the number of bottles from just after that + topicStr.remove(0, topicStr.indexOf('/')+1); + // Now see if there's a number of bottles after the '/' + bottleCount = topicStr.toInt(); + } + + if (bottleCount > 0) { + // Work out how big our resulting message will be + int msgLen = 0; + for (int i = bottleCount; i > 0; i--) { + String numBottles(i); + msgLen += 2*numBottles.length(); + if (i == 1) { + msgLen += 2*String(" green bottle, standing on the wall\n").length(); + } else { + msgLen += 2*String(" green bottles, standing on the wall\n").length(); + } + msgLen += String("And if one green bottle should accidentally fall\nThere'll be ").length(); + switch (i) { + case 1: + msgLen += String("no green bottles, standing on the wall\n\n").length(); + break; + case 2: + msgLen += String("1 green bottle, standing on the wall\n\n").length(); + break; + default: + numBottles = i-1; + msgLen += numBottles.length(); + msgLen += String(" green bottles, standing on the wall\n\n").length(); + break; + }; + } + + // Now we can start to publish the message + client.beginPublish("greenBottles/lyrics", msgLen, false); + for (int i = bottleCount; i > 0; i--) { + for (int j = 0; j < 2; j++) { + client.print(i); + if (i == 1) { + client.print(" green bottle, standing on the wall\n"); + } else { + client.print(" green bottles, standing on the wall\n"); + } + } + client.print("And if one green bottle should accidentally fall\nThere'll be "); + switch (i) { + case 1: + client.print("no green bottles, standing on the wall\n\n"); + break; + case 2: + client.print("1 green bottle, standing on the wall\n\n"); + break; + default: + client.print(i-1); + client.print(" green bottles, standing on the wall\n\n"); + break; + }; + } + // Now we're done! + client.endPublish(); + } +} + +void reconnect() { + // Loop until we're reconnected + while (!client.connected()) { + Serial.print("Attempting MQTT connection..."); + // Create a random client ID + String clientId = "ESP8266Client-"; + clientId += String(random(0xffff), HEX); + // Attempt to connect + if (client.connect(clientId.c_str())) { + Serial.println("connected"); + // Once connected, publish an announcement... + client.publish("outTopic", "hello world"); + // ... and resubscribe + client.subscribe("greenBottles/#"); + } else { + Serial.print("failed, rc="); + Serial.print(client.state()); + Serial.println(" try again in 5 seconds"); + // Wait 5 seconds before retrying + delay(5000); + } + } +} + +void setup() { + pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output + Serial.begin(115200); + setup_wifi(); + client.setServer(mqtt_server, 1883); + client.setCallback(callback); +} + +void loop() { + + if (!client.connected()) { + reconnect(); + } + client.loop(); +} From 0e2d6c322bba946ea9fc3a4e5d2d0dfe9070db3b Mon Sep 17 00:00:00 2001 From: Folkert van Heusden Date: Fri, 7 Sep 2018 21:39:45 +0200 Subject: [PATCH 21/46] Update PubSubClient.cpp Make sure all data is flushed to the other end when doing a disconnect(): that way we know for sure that it is there when we disconnect the wifi or maybe even reboot. This change was made after I noticed that I did not get any mqtt messages. I verified that it indeed solves the problem. Example code on request. --- src/PubSubClient.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PubSubClient.cpp b/src/PubSubClient.cpp index 29fbbfa..3c5c5f7 100755 --- a/src/PubSubClient.cpp +++ b/src/PubSubClient.cpp @@ -524,6 +524,7 @@ void PubSubClient::disconnect() { buffer[1] = 0; _client->write(buffer,2); _state = MQTT_DISCONNECTED; + _client->flush(); _client->stop(); lastInActivity = lastOutActivity = millis(); } From a1cfd5af5643838392fbaa3a3c2b816e5745da27 Mon Sep 17 00:00:00 2001 From: Nikhil Warke Date: Mon, 24 Sep 2018 00:29:11 +0530 Subject: [PATCH 22/46] Fix spelling in mqtt_esp8266 example --- examples/mqtt_esp8266/mqtt_esp8266.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/mqtt_esp8266/mqtt_esp8266.ino b/examples/mqtt_esp8266/mqtt_esp8266.ino index 34333c9..60ff938 100644 --- a/examples/mqtt_esp8266/mqtt_esp8266.ino +++ b/examples/mqtt_esp8266/mqtt_esp8266.ino @@ -74,7 +74,7 @@ void callback(char* topic, byte* payload, unsigned int length) { if ((char)payload[0] == '1') { digitalWrite(BUILTIN_LED, LOW); // Turn the LED on (Note that LOW is the voltage level // but actually the LED is on; this is because - // it is acive low on the ESP-01) + // it is active low on the ESP-01) } else { digitalWrite(BUILTIN_LED, HIGH); // Turn the LED off by making the voltage HIGH } From 0e8e3123cff80ce8e927adf6a45e4d868ac16a97 Mon Sep 17 00:00:00 2001 From: Maxim Kukushkin Date: Tue, 2 Oct 2018 00:02:31 +0100 Subject: [PATCH 23/46] Added support of CleanSession flag during connect --- src/PubSubClient.cpp | 13 ++++++++----- src/PubSubClient.h | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/PubSubClient.cpp b/src/PubSubClient.cpp index 29fbbfa..a8c0560 100755 --- a/src/PubSubClient.cpp +++ b/src/PubSubClient.cpp @@ -102,18 +102,18 @@ PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGN } boolean PubSubClient::connect(const char *id) { - return connect(id,NULL,NULL,0,0,0,0); + return connect(id,NULL,NULL,0,0,0,0,1); } boolean PubSubClient::connect(const char *id, const char *user, const char *pass) { - return connect(id,user,pass,0,0,0,0); + return connect(id,user,pass,0,0,0,0,1); } boolean PubSubClient::connect(const char *id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) { - return connect(id,NULL,NULL,willTopic,willQos,willRetain,willMessage); + return connect(id,NULL,NULL,willTopic,willQos,willRetain,willMessage,1); } -boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) { +boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage, boolean cleanSession) { if (!connected()) { int result = 0; @@ -143,9 +143,12 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass if (willTopic) { v = 0x06|(willQos<<3)|(willRetain<<5); } else { - v = 0x02; + v = 0; } + if (cleanSession) + v = v|0x02; + if(user != NULL) { v = v|0x80; diff --git a/src/PubSubClient.h b/src/PubSubClient.h index be4bd67..97f92ec 100755 --- a/src/PubSubClient.h +++ b/src/PubSubClient.h @@ -125,7 +125,7 @@ public: boolean connect(const char* id); boolean connect(const char* id, const char* user, const char* pass); boolean connect(const char* id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage); - boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage); + boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage, boolean cleanSession); void disconnect(); boolean publish(const char* topic, const char* payload); boolean publish(const char* topic, const char* payload, boolean retained); From 8154cbc09cdf72258d9f1783f308fca9cc876fde Mon Sep 17 00:00:00 2001 From: Maxim Kukushkin Date: Mon, 22 Oct 2018 23:35:47 +0100 Subject: [PATCH 24/46] Fixed an issue with clean session flag set when willTopic is provided --- src/PubSubClient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PubSubClient.cpp b/src/PubSubClient.cpp index a8c0560..97ae909 100755 --- a/src/PubSubClient.cpp +++ b/src/PubSubClient.cpp @@ -141,7 +141,7 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass uint8_t v; if (willTopic) { - v = 0x06|(willQos<<3)|(willRetain<<5); + v = 0x04|(willQos<<3)|(willRetain<<5); } else { v = 0; } From 4ecd32ec0898783b3392c1471287a1b7b6f9bbed Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Thu, 1 Nov 2018 23:25:04 +0000 Subject: [PATCH 25/46] Fix up CI tests --- tests/src/lib/Arduino.h | 1 + tests/src/lib/Print.h | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 tests/src/lib/Print.h diff --git a/tests/src/lib/Arduino.h b/tests/src/lib/Arduino.h index c675280..9bb814e 100644 --- a/tests/src/lib/Arduino.h +++ b/tests/src/lib/Arduino.h @@ -5,6 +5,7 @@ #include #include #include +#include "Print.h" extern "C"{ diff --git a/tests/src/lib/Print.h b/tests/src/lib/Print.h new file mode 100644 index 0000000..02ef77c --- /dev/null +++ b/tests/src/lib/Print.h @@ -0,0 +1,28 @@ +/* + Print.h - Base class that provides print() and println() + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef Print_h +#define Print_h + +class Print { + public: + virtual size_t write(uint8_t) = 0; +}; + +#endif From 3637cbec69d0d606d020c16991d3b9a6663084b7 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Thu, 1 Nov 2018 23:35:31 +0000 Subject: [PATCH 26/46] Revert "Added support of CleanSession flag during connect" --- src/PubSubClient.cpp | 15 ++++++--------- src/PubSubClient.h | 2 +- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/PubSubClient.cpp b/src/PubSubClient.cpp index 633eeec..836484c 100755 --- a/src/PubSubClient.cpp +++ b/src/PubSubClient.cpp @@ -102,18 +102,18 @@ PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGN } boolean PubSubClient::connect(const char *id) { - return connect(id,NULL,NULL,0,0,0,0,1); + return connect(id,NULL,NULL,0,0,0,0); } boolean PubSubClient::connect(const char *id, const char *user, const char *pass) { - return connect(id,user,pass,0,0,0,0,1); + return connect(id,user,pass,0,0,0,0); } boolean PubSubClient::connect(const char *id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) { - return connect(id,NULL,NULL,willTopic,willQos,willRetain,willMessage,1); + return connect(id,NULL,NULL,willTopic,willQos,willRetain,willMessage); } -boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage, boolean cleanSession) { +boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) { if (!connected()) { int result = 0; @@ -141,14 +141,11 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass uint8_t v; if (willTopic) { - v = 0x04|(willQos<<3)|(willRetain<<5); + v = 0x06|(willQos<<3)|(willRetain<<5); } else { - v = 0; + v = 0x02; } - if (cleanSession) - v = v|0x02; - if(user != NULL) { v = v|0x80; diff --git a/src/PubSubClient.h b/src/PubSubClient.h index 1057f1f..4d80839 100755 --- a/src/PubSubClient.h +++ b/src/PubSubClient.h @@ -133,7 +133,7 @@ public: boolean connect(const char* id); boolean connect(const char* id, const char* user, const char* pass); boolean connect(const char* id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage); - boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage, boolean cleanSession); + boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage); void disconnect(); boolean publish(const char* topic, const char* payload); boolean publish(const char* topic, const char* payload, boolean retained); From a0f09681f5a92189ffda995524b0f394fd11b30c Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Thu, 1 Nov 2018 23:46:09 +0000 Subject: [PATCH 27/46] Add separate connect function for clean session + test --- src/PubSubClient.cpp | 4 +++ src/PubSubClient.h | 1 + tests/src/connect_spec.cpp | 53 +++++++++++++++++++++++++++++--------- 3 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/PubSubClient.cpp b/src/PubSubClient.cpp index 97ae909..cbe09ba 100755 --- a/src/PubSubClient.cpp +++ b/src/PubSubClient.cpp @@ -113,6 +113,10 @@ boolean PubSubClient::connect(const char *id, const char* willTopic, uint8_t wil return connect(id,NULL,NULL,willTopic,willQos,willRetain,willMessage,1); } +boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) { + return connect(id,user,pass,willTopic,willQos,willRetain,willMessage,1); +} + boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage, boolean cleanSession) { if (!connected()) { int result = 0; diff --git a/src/PubSubClient.h b/src/PubSubClient.h index 97f92ec..62c915f 100755 --- a/src/PubSubClient.h +++ b/src/PubSubClient.h @@ -125,6 +125,7 @@ public: boolean connect(const char* id); boolean connect(const char* id, const char* user, const char* pass); boolean connect(const char* id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage); + boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage); boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage, boolean cleanSession); void disconnect(); boolean publish(const char* topic, const char* payload); diff --git a/tests/src/connect_spec.cpp b/tests/src/connect_spec.cpp index 3c46e0c..202b2b9 100644 --- a/tests/src/connect_spec.cpp +++ b/tests/src/connect_spec.cpp @@ -98,6 +98,33 @@ int test_connect_fails_on_bad_rc() { END_IT } +int test_connect_non_clean_session() { + IT("sends a properly formatted non-clean session connect packet and succeeds"); + ShimClient shimClient; + + shimClient.setAllowConnect(true); + byte expectServer[] = { 172, 16, 0, 2 }; + shimClient.expectConnect(expectServer,1883); + byte connect[] = {0x10,0x18,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0x0,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31}; + byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; + + shimClient.expect(connect,26); + shimClient.respond(connack,4); + + PubSubClient client(server, 1883, callback, shimClient); + int state = client.state(); + IS_TRUE(state == MQTT_DISCONNECTED); + + int rc = client.connect((char*)"client_test1",0,0,0,0,0,0,0); + IS_TRUE(rc); + IS_FALSE(shimClient.error()); + + state = client.state(); + IS_TRUE(state == MQTT_CONNECTED); + + END_IT +} + int test_connect_accepts_username_password() { IT("accepts a username and password"); ShimClient shimClient; @@ -256,18 +283,20 @@ int test_connect_disconnect_connect() { int main() { SUITE("Connect"); - test_connect_fails_no_network(); - test_connect_fails_on_no_response(); + test_connect_non_clean_session(); - test_connect_properly_formatted(); - test_connect_accepts_username_password(); - test_connect_fails_on_bad_rc(); - test_connect_properly_formatted_hostname(); - - test_connect_accepts_username_no_password(); - test_connect_ignores_password_no_username(); - test_connect_with_will(); - test_connect_with_will_username_password(); - test_connect_disconnect_connect(); + // test_connect_fails_no_network(); + // test_connect_fails_on_no_response(); + // + // test_connect_properly_formatted(); + // test_connect_accepts_username_password(); + // test_connect_fails_on_bad_rc(); + // test_connect_properly_formatted_hostname(); + // + // test_connect_accepts_username_no_password(); + // test_connect_ignores_password_no_username(); + // test_connect_with_will(); + // test_connect_with_will_username_password(); + // test_connect_disconnect_connect(); FINISH } From 4daba0ae5c11cca4da2fd98a1ba4fe0b490a4a86 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Fri, 2 Nov 2018 00:06:32 +0000 Subject: [PATCH 28/46] Fix remaining length protection --- src/PubSubClient.cpp | 2 +- tests/src/receive_spec.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PubSubClient.cpp b/src/PubSubClient.cpp index bd2514f..997bfb4 100755 --- a/src/PubSubClient.cpp +++ b/src/PubSubClient.cpp @@ -244,7 +244,7 @@ uint16_t PubSubClient::readPacket(uint8_t* lengthLength) { uint8_t start = 0; do { - if (len == 6) { + if (len == 5) { // Invalid remaining length encoding - kill the connection _state = MQTT_DISCONNECTED; _client->stop(); diff --git a/tests/src/receive_spec.cpp b/tests/src/receive_spec.cpp index 4ecd439..9a18af0 100644 --- a/tests/src/receive_spec.cpp +++ b/tests/src/receive_spec.cpp @@ -174,8 +174,8 @@ int test_drop_invalid_remaining_length_message() { int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); - byte publish[] = {0x30,0x92,0x92,0x92,0x92,0x92,0x92,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; - shimClient.respond(publish,21); + byte publish[] = {0x30,0x92,0x92,0x92,0x92,0x01,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; + shimClient.respond(publish,20); rc = client.loop(); From ee30733e247676ce7424938db79d6a91ff4d2750 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Fri, 2 Nov 2018 00:12:44 +0000 Subject: [PATCH 29/46] Fixup bad revert of 500 --- src/PubSubClient.cpp | 13 ++++++++----- tests/src/connect_spec.cpp | 28 ++++++++++++++-------------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/PubSubClient.cpp b/src/PubSubClient.cpp index 997bfb4..022f90e 100755 --- a/src/PubSubClient.cpp +++ b/src/PubSubClient.cpp @@ -102,15 +102,15 @@ PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGN } boolean PubSubClient::connect(const char *id) { - return connect(id,NULL,NULL,0,0,0,0); + return connect(id,NULL,NULL,0,0,0,0,1); } boolean PubSubClient::connect(const char *id, const char *user, const char *pass) { - return connect(id,user,pass,0,0,0,0); + return connect(id,user,pass,0,0,0,0,1); } boolean PubSubClient::connect(const char *id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) { - return connect(id,NULL,NULL,willTopic,willQos,willRetain,willMessage); + return connect(id,NULL,NULL,willTopic,willQos,willRetain,willMessage,1); } boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) { @@ -145,9 +145,12 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass uint8_t v; if (willTopic) { - v = 0x06|(willQos<<3)|(willRetain<<5); + v = 0x04|(willQos<<3)|(willRetain<<5); } else { - v = 0x02; + v = 0x00; + } + if (cleanSession) { + v = v|0x02; } if(user != NULL) { diff --git a/tests/src/connect_spec.cpp b/tests/src/connect_spec.cpp index 202b2b9..e27a1f5 100644 --- a/tests/src/connect_spec.cpp +++ b/tests/src/connect_spec.cpp @@ -283,20 +283,20 @@ int test_connect_disconnect_connect() { int main() { SUITE("Connect"); - test_connect_non_clean_session(); - // test_connect_fails_no_network(); - // test_connect_fails_on_no_response(); - // - // test_connect_properly_formatted(); - // test_connect_accepts_username_password(); - // test_connect_fails_on_bad_rc(); - // test_connect_properly_formatted_hostname(); - // - // test_connect_accepts_username_no_password(); - // test_connect_ignores_password_no_username(); - // test_connect_with_will(); - // test_connect_with_will_username_password(); - // test_connect_disconnect_connect(); + test_connect_fails_no_network(); + test_connect_fails_on_no_response(); + + test_connect_properly_formatted(); + test_connect_non_clean_session(); + test_connect_accepts_username_password(); + test_connect_fails_on_bad_rc(); + test_connect_properly_formatted_hostname(); + + test_connect_accepts_username_no_password(); + test_connect_ignores_password_no_username(); + test_connect_with_will(); + test_connect_with_will_username_password(); + test_connect_disconnect_connect(); FINISH } From 2d053d2df06f9bb864dc462d92453d3c1292796d Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Fri, 2 Nov 2018 00:50:52 +0000 Subject: [PATCH 30/46] Add buffer overflow protection to connect Closes #492 --- src/PubSubClient.cpp | 6 ++++++ src/PubSubClient.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/PubSubClient.cpp b/src/PubSubClient.cpp index 022f90e..48ec1ce 100755 --- a/src/PubSubClient.cpp +++ b/src/PubSubClient.cpp @@ -165,15 +165,21 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass buffer[length++] = ((MQTT_KEEPALIVE) >> 8); buffer[length++] = ((MQTT_KEEPALIVE) & 0xFF); + + CHECK_STRING_LENGTH(length,id) length = writeString(id,buffer,length); if (willTopic) { + CHECK_STRING_LENGTH(length,willTopic) length = writeString(willTopic,buffer,length); + CHECK_STRING_LENGTH(length,willMessage) length = writeString(willMessage,buffer,length); } if(user != NULL) { + CHECK_STRING_LENGTH(length,user) length = writeString(user,buffer,length); if(pass != NULL) { + CHECK_STRING_LENGTH(length,pass) length = writeString(pass,buffer,length); } } diff --git a/src/PubSubClient.h b/src/PubSubClient.h index 8fd8707..b476b63 100755 --- a/src/PubSubClient.h +++ b/src/PubSubClient.h @@ -83,6 +83,8 @@ #define MQTT_CALLBACK_SIGNATURE void (*callback)(char*, uint8_t*, unsigned int) #endif +#define CHECK_STRING_LENGTH(l,s) if (l+2+strlen(s) > MQTT_MAX_PACKET_SIZE) {_client->stop();return false;} + class PubSubClient : public Print { private: Client* _client; From b3817289988abbef58336955487987c712f20618 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Fri, 2 Nov 2018 01:05:02 +0000 Subject: [PATCH 31/46] Add yield to mock test framework --- tests/src/lib/Arduino.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/src/lib/Arduino.h b/tests/src/lib/Arduino.h index 9bb814e..2a00f24 100644 --- a/tests/src/lib/Arduino.h +++ b/tests/src/lib/Arduino.h @@ -21,4 +21,6 @@ extern "C"{ #define PROGMEM #define pgm_read_byte_near(x) *(x) +#define yield(x) {} + #endif // Arduino_h From 26ce89fa476da85399b736f885274d67676dacb8 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Fri, 2 Nov 2018 11:42:44 +0000 Subject: [PATCH 32/46] Update for 2.7 --- CHANGES.txt | 10 +++++++++- library.json | 2 +- library.properties | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 8c8bef6..ff4da62 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,8 +1,16 @@ +2.7 + * Fix remaining-length handling to prevent buffer overrun + * Add large-payload API - beginPublish/write/publish/endPublish + * Add yield call to improve reliability on ESP + * Add Clean Session flag to connect options + * Add ESP32 support for functional callback signature + * Various other fixes + 2.4 * Add MQTT_SOCKET_TIMEOUT to prevent it blocking indefinitely whilst waiting for inbound data * Fixed return code when publishing >256 bytes - + 2.3 * Add publish(topic,payload,retained) function diff --git a/library.json b/library.json index b967390..8a36a1c 100644 --- a/library.json +++ b/library.json @@ -6,7 +6,7 @@ "type": "git", "url": "https://github.com/knolleary/pubsubclient.git" }, - "version": "2.6", + "version": "2.7", "exclude": "tests", "examples": "examples/*/*.ino", "frameworks": "arduino", diff --git a/library.properties b/library.properties index 3ceeda8..1ae9788 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=PubSubClient -version=2.6 +version=2.7 author=Nick O'Leary maintainer=Nick O'Leary sentence=A client library for MQTT messaging. From 2dca84a77682f2a4e845dac20c4f5ae6b1fd349a Mon Sep 17 00:00:00 2001 From: Alex Ignatov Date: Wed, 21 Nov 2018 03:09:08 +0200 Subject: [PATCH 33/46] 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 34/46] 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 35/46] 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 36/46] 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 37/46] 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 38/46] 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 39/46] 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 40/46] 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 bc65fe5244cb4292dba2eeb4dd743af2c378d1f7 Mon Sep 17 00:00:00 2001 From: Brandon Piner Date: Thu, 9 May 2019 22:10:56 +0200 Subject: [PATCH 41/46] Removed an unused variable --- src/PubSubClient.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/PubSubClient.cpp b/src/PubSubClient.cpp index 0fa420d..12d1ad3 100755 --- a/src/PubSubClient.cpp +++ b/src/PubSubClient.cpp @@ -453,7 +453,6 @@ boolean PubSubClient::beginPublish(const char* topic, unsigned int plength, bool // Send the header and variable length field uint16_t length = MQTT_MAX_HEADER_SIZE; length = writeString(topic,buffer,length); - uint16_t i; uint8_t header = MQTTPUBLISH; if (retained) { header |= 1; From 719b90eafd46b2f97067730dacbab7c49e7fd5e9 Mon Sep 17 00:00:00 2001 From: Abderraouf Adjal Date: Thu, 22 Aug 2019 17:14:02 +0100 Subject: [PATCH 42/46] PubSubClient.h: Using strnlen() --- src/PubSubClient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PubSubClient.h b/src/PubSubClient.h index 2fd6f1d..9a4b72f 100755 --- a/src/PubSubClient.h +++ b/src/PubSubClient.h @@ -83,7 +83,7 @@ #define MQTT_CALLBACK_SIGNATURE void (*callback)(char*, uint8_t*, unsigned int) #endif -#define CHECK_STRING_LENGTH(l,s) if (l+2+strlen(s) > MQTT_MAX_PACKET_SIZE) {_client->stop();return false;} +#define CHECK_STRING_LENGTH(l,s) if (l+2+strnlen(s, MQTT_MAX_PACKET_SIZE) > MQTT_MAX_PACKET_SIZE) {_client->stop();return false;} class PubSubClient : public Print { private: From f13ad2af3beb2c863a9dc5e8ebd0ffb13860db25 Mon Sep 17 00:00:00 2001 From: Abderraouf Adjal Date: Thu, 22 Aug 2019 17:19:38 +0100 Subject: [PATCH 43/46] PubSubClient.cpp: Using strnlen() --- src/PubSubClient.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/PubSubClient.cpp b/src/PubSubClient.cpp index 12d1ad3..b850c94 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,strnlen(payload, MQTT_MAX_PACKET_SIZE),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,strnlen(payload, MQTT_MAX_PACKET_SIZE),retained); } boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength) { @@ -379,7 +379,7 @@ boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigne boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) { if (connected()) { - if (MQTT_MAX_PACKET_SIZE < MQTT_MAX_HEADER_SIZE + 2+strlen(topic) + plength) { + if (MQTT_MAX_PACKET_SIZE < MQTT_MAX_HEADER_SIZE + 2+strnlen(topic, MQTT_MAX_PACKET_SIZE) + plength) { // Too long return false; } @@ -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, strnlen(payload, MQTT_MAX_PACKET_SIZE), retained); } boolean PubSubClient::publish_P(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) { @@ -417,7 +417,7 @@ boolean PubSubClient::publish_P(const char* topic, const uint8_t* payload, unsig return false; } - tlen = strlen(topic); + tlen = strnlen(topic, MQTT_MAX_PACKET_SIZE); header = MQTTPUBLISH; if (retained) { @@ -534,7 +534,7 @@ boolean PubSubClient::subscribe(const char* topic, uint8_t qos) { if (qos > 1) { return false; } - if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) { + if (MQTT_MAX_PACKET_SIZE < 9 + strnlen(topic, MQTT_MAX_PACKET_SIZE)) { // Too long return false; } @@ -555,7 +555,7 @@ boolean PubSubClient::subscribe(const char* topic, uint8_t qos) { } boolean PubSubClient::unsubscribe(const char* topic) { - if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) { + if (MQTT_MAX_PACKET_SIZE < 9 + strnlen(topic, MQTT_MAX_PACKET_SIZE)) { // Too long return false; } From d88909db3e0330be8323a8a8910c62d987b5ab9f Mon Sep 17 00:00:00 2001 From: Leo Zimmermann Date: Tue, 24 Dec 2019 11:08:59 +0100 Subject: [PATCH 44/46] 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 45/46] 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; } From baad92dd0c86b22b758f9d279267e037cfe06f4a Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Sat, 9 May 2020 23:20:44 +0100 Subject: [PATCH 46/46] Fix merge error with strnlen --- src/PubSubClient.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/PubSubClient.cpp b/src/PubSubClient.cpp index 14d661e..cda2cde 100755 --- a/src/PubSubClient.cpp +++ b/src/PubSubClient.cpp @@ -132,7 +132,7 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass result = _client->connect(this->ip, this->port); } } - + if (result == 1) { nextMsgId = 1; // Leave room in the buffer for header and variable length field @@ -375,11 +375,11 @@ boolean PubSubClient::loop() { } boolean PubSubClient::publish(const char* topic, const char* payload) { - return publish(topic,(const uint8_t*)payload, payload ? strnlen(payload, MQTT_MAX_PACKET_SIZE)) : 0,false); + return publish(topic,(const uint8_t*)payload, payload ? strnlen(payload, MQTT_MAX_PACKET_SIZE) : 0,false); } boolean PubSubClient::publish(const char* topic, const char* payload, boolean retained) { - return publish(topic,(const uint8_t*)payload, payload ? strnlen(payload, MQTT_MAX_PACKET_SIZE)) : 0,retained); + return publish(topic,(const uint8_t*)payload, payload ? strnlen(payload, MQTT_MAX_PACKET_SIZE) : 0,retained); } boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength) { @@ -402,7 +402,7 @@ boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigne buffer[length++] = payload[i]; } - // Write the header + // Write the header uint8_t header = MQTTPUBLISH; if (retained) { header |= 1;