diff --git a/README.md b/README.md index 83176919..c3b5cce4 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,8 @@ 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` or at runtime + using PubSubClient::setBufferSize(). - 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 diff --git a/examples/mqtt_auth/mqtt_auth.ino b/examples/mqtt_auth/mqtt_auth.ino index e9f7b180..04bd7bb2 100755 --- a/examples/mqtt_auth/mqtt_auth.ino +++ b/examples/mqtt_auth/mqtt_auth.ino @@ -27,9 +27,9 @@ void setup() { Ethernet.begin(mac, ip); // Note - the default maximum packet size is 128 bytes. If the - // combined length of clientId, username and password exceed this, - // you will need to increase the value of MQTT_MAX_PACKET_SIZE in - // PubSubClient.h + // combined length of clientId, username and password exceed this use the + // following to increase the buffer size: + // client.setBufferSize(255); if (client.connect("arduinoClient", "testuser", "testpass")) { client.publish("outTopic","hello world"); diff --git a/src/PubSubClient.cpp b/src/PubSubClient.cpp index 5932bdbe..73714bd2 100755 --- a/src/PubSubClient.cpp +++ b/src/PubSubClient.cpp @@ -12,12 +12,16 @@ PubSubClient::PubSubClient() { this->_client = NULL; this->stream = NULL; setCallback(NULL); + this->buffer_size = MQTT_MAX_PACKET_SIZE; + this->buffer = (uint8_t*)malloc(MQTT_MAX_PACKET_SIZE); } PubSubClient::PubSubClient(Client& client) { this->_state = MQTT_DISCONNECTED; setClient(client); this->stream = NULL; + this->buffer_size = MQTT_MAX_PACKET_SIZE; + this->buffer = (uint8_t*)malloc(MQTT_MAX_PACKET_SIZE); } PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client) { @@ -25,12 +29,16 @@ PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client) { setServer(addr, port); setClient(client); this->stream = NULL; + this->buffer_size = MQTT_MAX_PACKET_SIZE; + this->buffer = (uint8_t*)malloc(MQTT_MAX_PACKET_SIZE); } PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client, Stream& stream) { this->_state = MQTT_DISCONNECTED; setServer(addr,port); setClient(client); setStream(stream); + this->buffer_size = MQTT_MAX_PACKET_SIZE; + this->buffer = (uint8_t*)malloc(MQTT_MAX_PACKET_SIZE); } PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) { this->_state = MQTT_DISCONNECTED; @@ -38,6 +46,8 @@ PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATUR setCallback(callback); setClient(client); this->stream = NULL; + this->buffer_size = MQTT_MAX_PACKET_SIZE; + this->buffer = (uint8_t*)malloc(MQTT_MAX_PACKET_SIZE); } PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) { this->_state = MQTT_DISCONNECTED; @@ -45,6 +55,8 @@ PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATUR setCallback(callback); setClient(client); setStream(stream); + this->buffer_size = MQTT_MAX_PACKET_SIZE; + this->buffer = (uint8_t*)malloc(MQTT_MAX_PACKET_SIZE); } PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client) { @@ -52,12 +64,16 @@ PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client) { setServer(ip, port); setClient(client); this->stream = NULL; + this->buffer_size = MQTT_MAX_PACKET_SIZE; + this->buffer = (uint8_t*)malloc(MQTT_MAX_PACKET_SIZE); } PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client, Stream& stream) { this->_state = MQTT_DISCONNECTED; setServer(ip,port); setClient(client); setStream(stream); + this->buffer_size = MQTT_MAX_PACKET_SIZE; + this->buffer = (uint8_t*)malloc(MQTT_MAX_PACKET_SIZE); } PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) { this->_state = MQTT_DISCONNECTED; @@ -65,6 +81,8 @@ PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, setCallback(callback); setClient(client); this->stream = NULL; + this->buffer_size = MQTT_MAX_PACKET_SIZE; + this->buffer = (uint8_t*)malloc(MQTT_MAX_PACKET_SIZE); } PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) { this->_state = MQTT_DISCONNECTED; @@ -72,6 +90,8 @@ PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, setCallback(callback); setClient(client); setStream(stream); + this->buffer_size = MQTT_MAX_PACKET_SIZE; + this->buffer = (uint8_t*)malloc(MQTT_MAX_PACKET_SIZE); } PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client) { @@ -79,12 +99,16 @@ PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client) { setServer(domain,port); setClient(client); this->stream = NULL; + this->buffer_size = MQTT_MAX_PACKET_SIZE; + this->buffer = (uint8_t*)malloc(MQTT_MAX_PACKET_SIZE); } PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client, Stream& stream) { this->_state = MQTT_DISCONNECTED; setServer(domain,port); setClient(client); setStream(stream); + this->buffer_size = MQTT_MAX_PACKET_SIZE; + this->buffer = (uint8_t*)malloc(MQTT_MAX_PACKET_SIZE); } PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) { this->_state = MQTT_DISCONNECTED; @@ -92,6 +116,8 @@ PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGN setCallback(callback); setClient(client); this->stream = NULL; + this->buffer_size = MQTT_MAX_PACKET_SIZE; + this->buffer = (uint8_t*)malloc(MQTT_MAX_PACKET_SIZE); } PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) { this->_state = MQTT_DISCONNECTED; @@ -99,6 +125,12 @@ PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGN setCallback(callback); setClient(client); setStream(stream); + this->buffer_size = MQTT_MAX_PACKET_SIZE; + this->buffer = (uint8_t*)malloc(MQTT_MAX_PACKET_SIZE); +} + +PubSubClient::~PubSubClient() { + free(this->buffer); } boolean PubSubClient::connect(const char *id) { @@ -266,13 +298,13 @@ uint16_t PubSubClient::readPacket(uint8_t* lengthLength) { this->stream->write(digit); } } - if (len < MQTT_MAX_PACKET_SIZE) { + if (len < this->buffer_size) { buffer[len] = digit; } len++; } - if (!this->stream && len > MQTT_MAX_PACKET_SIZE) { + if (!this->stream && len > this->buffer_size) { len = 0; // This will cause the packet to be ignored. } @@ -356,7 +388,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 < 5 + 2+strlen(topic) + plength) { + if (this->buffer_size < 5 + 2+strlen(topic) + plength) { // Too long return false; } @@ -471,7 +503,7 @@ boolean PubSubClient::subscribe(const char* topic, uint8_t qos) { if (qos < 0 || qos > 1) { return false; } - if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) { + if (this->buffer_size < 9 + strlen(topic)) { // Too long return false; } @@ -492,7 +524,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 (this->buffer_size < 9 + strlen(topic)) { // Too long return false; } @@ -586,3 +618,13 @@ PubSubClient& PubSubClient::setStream(Stream& stream){ int PubSubClient::state() { return this->_state; } + +boolean PubSubClient::setBufferSize(uint16_t size) { + this->buffer = (uint8_t*)realloc(this->buffer, size); + this->buffer_size = size; + return (this->buffer == NULL); +} + +uint16_t PubSubClient::getBufferSize() { + return this->buffer_size; +} diff --git a/src/PubSubClient.h b/src/PubSubClient.h index be4bd674..c8b0ff14 100755 --- a/src/PubSubClient.h +++ b/src/PubSubClient.h @@ -21,7 +21,7 @@ #define MQTT_VERSION MQTT_VERSION_3_1_1 #endif -// MQTT_MAX_PACKET_SIZE : Maximum packet size +// MQTT_MAX_PACKET_SIZE : Maximum packet size. Override with setBufferSize(). #ifndef MQTT_MAX_PACKET_SIZE #define MQTT_MAX_PACKET_SIZE 128 #endif @@ -83,7 +83,8 @@ class PubSubClient { private: Client* _client; - uint8_t buffer[MQTT_MAX_PACKET_SIZE]; + uint8_t* buffer; + uint16_t buffer_size; uint16_t nextMsgId; unsigned long lastOutActivity; unsigned long lastInActivity; @@ -115,6 +116,8 @@ class PubSubClient { PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&); + ~PubSubClient(); + PubSubClient& setServer(IPAddress ip, uint16_t port); PubSubClient& setServer(uint8_t * ip, uint16_t port); PubSubClient& setServer(const char * domain, uint16_t port); @@ -138,6 +141,8 @@ class PubSubClient { boolean loop(); boolean connected(); int state(); + boolean setBufferSize(uint16_t size); + uint16_t getBufferSize(); }; diff --git a/tests/src/receive_spec.cpp b/tests/src/receive_spec.cpp index 54a62ee5..29975190 100644 --- a/tests/src/receive_spec.cpp +++ b/tests/src/receive_spec.cpp @@ -160,6 +160,43 @@ int test_receive_oversized_message() { END_IT } +int test_resize_buffer() { + IT("receives a message larger than the default maximum"); + 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); + + int length = MQTT_MAX_PACKET_SIZE+1; + client.setBufferSize(length); + byte publish[] = {0x30,length-2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; + byte bigPublish[length]; + memset(bigPublish,'A',length); + bigPublish[length] = 'B'; + memcpy(bigPublish,publish,16); + shimClient.respond(bigPublish,length); + + rc = client.loop(); + + IS_TRUE(rc); + + IS_TRUE(callback_called); + IS_TRUE(strcmp(lastTopic,"topic")==0); + IS_TRUE(lastLength == length-9); + IS_TRUE(memcmp(lastPayload,bigPublish+9,lastLength)==0); + + IS_FALSE(shimClient.error()); + + END_IT +} + int test_receive_oversized_stream_message() { IT("drops an oversized message"); reset_callback(); @@ -242,6 +279,7 @@ int main() test_receive_stream(); test_receive_max_sized_message(); test_receive_oversized_message(); + test_resize_buffer(); test_receive_oversized_stream_message(); test_receive_qos1();