Merge branch 'master' into pr_282

This commit is contained in:
Nick O'Leary
2020-05-20 00:49:38 +01:00
18 changed files with 630 additions and 168 deletions

View File

@ -1,4 +1,5 @@
/*
PubSubClient.cpp - A simple client for MQTT.
Nick O'Leary
http://knolleary.net
@ -12,16 +13,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);
this->bufferSize = 0;
setBufferSize(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);
this->bufferSize = 0;
setBufferSize(MQTT_MAX_PACKET_SIZE);
}
PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client) {
@ -29,16 +30,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);
this->bufferSize = 0;
setBufferSize(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);
this->bufferSize = 0;
setBufferSize(MQTT_MAX_PACKET_SIZE);
}
PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) {
this->_state = MQTT_DISCONNECTED;
@ -46,8 +47,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);
this->bufferSize = 0;
setBufferSize(MQTT_MAX_PACKET_SIZE);
}
PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) {
this->_state = MQTT_DISCONNECTED;
@ -55,8 +56,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);
this->bufferSize = 0;
setBufferSize(MQTT_MAX_PACKET_SIZE);
}
PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client) {
@ -64,16 +65,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);
this->bufferSize = 0;
setBufferSize(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);
this->bufferSize = 0;
setBufferSize(MQTT_MAX_PACKET_SIZE);
}
PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) {
this->_state = MQTT_DISCONNECTED;
@ -81,8 +82,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);
this->bufferSize = 0;
setBufferSize(MQTT_MAX_PACKET_SIZE);
}
PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) {
this->_state = MQTT_DISCONNECTED;
@ -90,8 +91,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);
this->bufferSize = 0;
setBufferSize(MQTT_MAX_PACKET_SIZE);
}
PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client) {
@ -99,16 +100,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);
this->bufferSize = 0;
setBufferSize(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);
this->bufferSize = 0;
setBufferSize(MQTT_MAX_PACKET_SIZE);
}
PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) {
this->_state = MQTT_DISCONNECTED;
@ -116,8 +117,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);
this->bufferSize = 0;
setBufferSize(MQTT_MAX_PACKET_SIZE);
}
PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) {
this->_state = MQTT_DISCONNECTED;
@ -125,8 +126,8 @@ 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);
this->bufferSize = 0;
setBufferSize(MQTT_MAX_PACKET_SIZE);
}
PubSubClient::~PubSubClient() {
@ -134,30 +135,40 @@ PubSubClient::~PubSubClient() {
}
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) {
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;
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
uint16_t length = 5;
uint16_t length = MQTT_MAX_HEADER_SIZE;
unsigned int j;
#if MQTT_VERSION == MQTT_VERSION_3_1
@ -168,14 +179,17 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass
#define MQTT_HEADER_VERSION_LENGTH 7
#endif
for (j = 0;j<MQTT_HEADER_VERSION_LENGTH;j++) {
buffer[length++] = d[j];
this->buffer[length++] = d[j];
}
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) {
@ -185,25 +199,30 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass
v = v|(0x80>>1);
}
}
this->buffer[length++] = v;
buffer[length++] = v;
this->buffer[length++] = ((MQTT_KEEPALIVE) >> 8);
this->buffer[length++] = ((MQTT_KEEPALIVE) & 0xFF);
buffer[length++] = ((MQTT_KEEPALIVE) >> 8);
buffer[length++] = ((MQTT_KEEPALIVE) & 0xFF);
length = writeString(id,buffer,length);
CHECK_STRING_LENGTH(length,id)
length = writeString(id,this->buffer,length);
if (willTopic) {
length = writeString(willTopic,buffer,length);
length = writeString(willMessage,buffer,length);
CHECK_STRING_LENGTH(length,willTopic)
length = writeString(willTopic,this->buffer,length);
CHECK_STRING_LENGTH(length,willMessage)
length = writeString(willMessage,this->buffer,length);
}
if(user != NULL) {
length = writeString(user,buffer,length);
CHECK_STRING_LENGTH(length,user)
length = writeString(user,this->buffer,length);
if(pass != NULL) {
length = writeString(pass,buffer,length);
CHECK_STRING_LENGTH(length,pass)
length = writeString(pass,this->buffer,length);
}
}
write(MQTTCONNECT,buffer,length-5);
write(MQTTCONNECT,this->buffer,length-MQTT_MAX_HEADER_SIZE);
lastInActivity = lastOutActivity = millis();
@ -216,7 +235,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) {
@ -241,6 +260,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;
@ -261,53 +281,61 @@ 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;
if(!readByte(this->buffer, &len)) return 0;
bool isPublish = (this->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;
uint32_t start = 0;
do {
if (len == 5) {
// Invalid remaining length encoding - kill the connection
_state = MQTT_DISCONNECTED;
_client->stop();
return 0;
}
if(!readByte(&digit)) return 0;
buffer[len++] = digit;
this->buffer[len++] = digit;
length += (digit & 127) * multiplier;
multiplier *= 128;
multiplier <<=7; //multiplier *= 128
} while ((digit & 128) != 0);
*lengthLength = len-1;
if (isPublish) {
// Read in topic length to calculate bytes to skip over for Stream writing
if(!readByte(buffer, &len)) return 0;
if(!readByte(buffer, &len)) return 0;
skip = (buffer[*lengthLength+1]<<8)+buffer[*lengthLength+2];
if(!readByte(this->buffer, &len)) return 0;
if(!readByte(this->buffer, &len)) return 0;
skip = (this->buffer[*lengthLength+1]<<8)+this->buffer[*lengthLength+2];
start = 2;
if (buffer[0]&MQTTQOS1) {
if (this->buffer[0]&MQTTQOS1) {
// skip message id
skip += 2;
}
}
uint32_t idx = len;
for (uint16_t i = start;i<length;i++) {
for (uint32_t i = start;i<length;i++) {
if(!readByte(&digit)) return 0;
if (this->stream) {
if (isPublish && len-*lengthLength-2>skip) {
if (isPublish && idx-*lengthLength-2>skip) {
this->stream->write(digit);
}
}
if (len < this->buffer_size) {
buffer[len] = digit;
if (len < this->bufferSize) {
this->buffer[len] = digit;
len++;
}
len++;
idx++;
}
if (!this->stream && len > this->buffer_size) {
if (!this->stream && idx > this->bufferSize) {
len = 0; // This will cause the packet to be ignored.
}
return len;
}
@ -320,9 +348,9 @@ boolean PubSubClient::loop() {
_client->stop();
return false;
} else {
buffer[0] = MQTTPINGREQ;
buffer[1] = 0;
_client->write(buffer,2);
this->buffer[0] = MQTTPINGREQ;
this->buffer[1] = 0;
_client->write(this->buffer,2);
lastOutActivity = t;
lastInActivity = t;
pingOutstanding = true;
@ -335,38 +363,41 @@ boolean PubSubClient::loop() {
uint8_t *payload;
if (len > 0) {
lastInActivity = t;
uint8_t type = buffer[0]&0xF0;
uint8_t type = this->buffer[0]&0xF0;
if (type == MQTTPUBLISH) {
if (callback) {
uint16_t tl = (buffer[llen+1]<<8)+buffer[llen+2]; /* topic length in bytes */
memmove(buffer+llen+2,buffer+llen+3,tl); /* move topic inside buffer 1 byte to front */
buffer[llen+2+tl] = 0; /* end the topic as a 'C' string with \x00 */
char *topic = (char*) buffer+llen+2;
uint16_t tl = (this->buffer[llen+1]<<8)+this->buffer[llen+2]; /* topic length in bytes */
memmove(this->buffer+llen+2,this->buffer+llen+3,tl); /* move topic inside buffer 1 byte to front */
this->buffer[llen+2+tl] = 0; /* end the topic as a 'C' string with \x00 */
char *topic = (char*) this->buffer+llen+2;
// msgId only present for QOS>0
if ((buffer[0]&0x06) == MQTTQOS1) {
msgId = (buffer[llen+3+tl]<<8)+buffer[llen+3+tl+1];
payload = buffer+llen+3+tl+2;
if ((this->buffer[0]&0x06) == MQTTQOS1) {
msgId = (this->buffer[llen+3+tl]<<8)+this->buffer[llen+3+tl+1];
payload = this->buffer+llen+3+tl+2;
callback(topic,payload,len-llen-3-tl-2);
buffer[0] = MQTTPUBACK;
buffer[1] = 2;
buffer[2] = (msgId >> 8);
buffer[3] = (msgId & 0xFF);
_client->write(buffer,4);
this->buffer[0] = MQTTPUBACK;
this->buffer[1] = 2;
this->buffer[2] = (msgId >> 8);
this->buffer[3] = (msgId & 0xFF);
_client->write(this->buffer,4);
lastOutActivity = t;
} else {
payload = buffer+llen+3+tl;
payload = this->buffer+llen+3+tl;
callback(topic,payload,len-llen-3-tl);
}
}
} else if (type == MQTTPINGREQ) {
buffer[0] = MQTTPINGRESP;
buffer[1] = 0;
_client->write(buffer,2);
this->buffer[0] = MQTTPINGRESP;
this->buffer[1] = 0;
_client->write(this->buffer,2);
} else if (type == MQTTPINGRESP) {
pingOutstanding = false;
}
} else if (!connected()) {
// readPacket has closed the connection
return false;
}
}
return true;
@ -375,11 +406,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 ? strnlen(payload, this->bufferSize) : 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 ? strnlen(payload, this->bufferSize) : 0,retained);
}
boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength) {
@ -388,26 +419,34 @@ 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 (this->buffer_size < 5 + 2+strlen(topic) + plength) {
if (this->bufferSize < MQTT_MAX_HEADER_SIZE + 2+strnlen(topic, this->bufferSize) + plength) {
// Too long
return false;
}
// Leave room in the buffer for header and variable length field
uint16_t length = 5;
length = writeString(topic,buffer,length);
uint16_t length = MQTT_MAX_HEADER_SIZE;
length = writeString(topic,this->buffer,length);
// Add payload
uint16_t i;
for (i=0;i<plength;i++) {
buffer[length++] = payload[i];
this->buffer[length++] = payload[i];
}
// Write the header
uint8_t header = MQTTPUBLISH;
if (retained) {
header |= 1;
}
return write(header,buffer,length-5);
return write(header,this->buffer,length-MQTT_MAX_HEADER_SIZE);
}
return false;
}
boolean PubSubClient::publish_P(const char* topic, const char* payload, boolean retained) {
return publish_P(topic, (const uint8_t*)payload, payload ? strnlen(payload, this->bufferSize) : 0, retained);
}
boolean PubSubClient::publish_P(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) {
uint8_t llen = 0;
uint8_t digit;
@ -417,32 +456,33 @@ 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;
}
tlen = strlen(topic);
tlen = strnlen(topic, this->bufferSize);
header = MQTTPUBLISH;
if (retained) {
header |= 1;
}
buffer[pos++] = header;
this->buffer[pos++] = header;
len = plength + 2 + tlen;
do {
digit = len % 128;
len = len / 128;
digit = len & 127; //digit = len %128
len >>= 7; //len = len / 128
if (len > 0) {
digit |= 0x80;
}
buffer[pos++] = digit;
this->buffer[pos++] = digit;
llen++;
} while(len>0);
pos = writeString(topic,buffer,pos);
pos = writeString(topic,this->buffer,pos);
rc += _client->write(buffer,pos);
rc += _client->write(this->buffer,pos);
for (i=0;i<plength;i++) {
rc += _client->write((char)pgm_read_byte_near(payload + i));
@ -450,19 +490,52 @@ 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::write(uint8_t header, uint8_t* buf, uint16_t length) {
boolean PubSubClient::beginPublish(const char* topic, unsigned int plength, boolean retained) {
if (connected()) {
// Send the header and variable length field
uint16_t length = MQTT_MAX_HEADER_SIZE;
length = writeString(topic,this->buffer,length);
uint8_t header = MQTTPUBLISH;
if (retained) {
header |= 1;
}
size_t hlen = buildHeader(header, this->buffer, plength+length-MQTT_MAX_HEADER_SIZE);
uint16_t rc = _client->write(this->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;
len = len / 128;
digit = len & 127; //digit = len %128
len >>= 7; //len = len / 128
if (len > 0) {
digit |= 0x80;
}
@ -472,12 +545,18 @@ boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) {
buf[4-llen] = header;
for (int i=0;i<llen;i++) {
buf[5-llen+i] = lenBuf[i];
buf[MQTT_MAX_HEADER_SIZE-llen+i] = lenBuf[i];
}
return llen+1; // Full header size is variable length bit plus the 1-byte fixed header
}
boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) {
uint16_t rc;
uint8_t hlen = buildHeader(header, buf, length);
#ifdef MQTT_MAX_TRANSFER_SIZE
uint8_t* writeBuf = buf+(4-llen);
uint16_t bytesRemaining = length+1+llen; //Match the length type
uint8_t* writeBuf = buf+(MQTT_MAX_HEADER_SIZE-hlen);
uint16_t bytesRemaining = length+hlen; //Match the length type
uint8_t bytesToWrite;
boolean result = true;
while((bytesRemaining > 0) && result) {
@ -489,9 +568,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
}
@ -500,53 +579,62 @@ boolean PubSubClient::subscribe(const char* topic) {
}
boolean PubSubClient::subscribe(const char* topic, uint8_t qos) {
if (qos < 0 || qos > 1) {
size_t topicLength = strnlen(topic, this->bufferSize);
if (topic == 0) {
return false;
}
if (this->buffer_size < 9 + strlen(topic)) {
if (qos > 1) {
return false;
}
if (this->bufferSize < 9 + topicLength) {
// Too long
return false;
}
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;
}
buffer[length++] = (nextMsgId >> 8);
buffer[length++] = (nextMsgId & 0xFF);
length = writeString((char*)topic, buffer,length);
buffer[length++] = qos;
return write(MQTTSUBSCRIBE|MQTTQOS1,buffer,length-5);
this->buffer[length++] = (nextMsgId >> 8);
this->buffer[length++] = (nextMsgId & 0xFF);
length = writeString((char*)topic, this->buffer,length);
this->buffer[length++] = qos;
return write(MQTTSUBSCRIBE|MQTTQOS1,this->buffer,length-MQTT_MAX_HEADER_SIZE);
}
return false;
}
boolean PubSubClient::unsubscribe(const char* topic) {
if (this->buffer_size < 9 + strlen(topic)) {
size_t topicLength = strnlen(topic, this->bufferSize);
if (topic == 0) {
return false;
}
if (this->bufferSize < 9 + topicLength) {
// Too long
return false;
}
if (connected()) {
uint16_t length = 5;
uint16_t length = MQTT_MAX_HEADER_SIZE;
nextMsgId++;
if (nextMsgId == 0) {
nextMsgId = 1;
}
buffer[length++] = (nextMsgId >> 8);
buffer[length++] = (nextMsgId & 0xFF);
length = writeString(topic, buffer,length);
return write(MQTTUNSUBSCRIBE|MQTTQOS1,buffer,length-5);
this->buffer[length++] = (nextMsgId >> 8);
this->buffer[length++] = (nextMsgId & 0xFF);
length = writeString(topic, this->buffer,length);
return write(MQTTUNSUBSCRIBE|MQTTQOS1,this->buffer,length-MQTT_MAX_HEADER_SIZE);
}
return false;
}
void PubSubClient::disconnect() {
buffer[0] = MQTTDISCONNECT;
buffer[1] = 0;
_client->write(buffer,2);
this->buffer[0] = MQTTDISCONNECT;
this->buffer[1] = 0;
_client->write(this->buffer,2);
_state = MQTT_DISCONNECTED;
_client->flush();
_client->stop();
lastInActivity = lastOutActivity = millis();
}
@ -577,6 +665,8 @@ boolean PubSubClient::connected() {
_client->flush();
_client->stop();
}
} else {
return this->_state == MQTT_CONNECTED;
}
}
return rc;
@ -620,11 +710,24 @@ int PubSubClient::state() {
}
boolean PubSubClient::setBufferSize(uint16_t size) {
this->buffer = (uint8_t*)realloc(this->buffer, size);
this->buffer_size = size;
return (this->buffer == NULL);
if (size == 0) {
// Cannot set it back to 0
return false;
}
if (this->bufferSize == 0) {
this->buffer = (uint8_t*)malloc(size);
} else {
uint8_t* newBuffer = (uint8_t*)realloc(this->buffer, size);
if (newBuffer != NULL) {
this->buffer = newBuffer;
} else {
return false;
}
}
this->bufferSize = size;
return (this->buffer != NULL);
}
uint16_t PubSubClient::getBufferSize() {
return this->buffer_size;
return this->bufferSize;
}

View File

@ -23,7 +23,7 @@
// MQTT_MAX_PACKET_SIZE : Maximum packet size. Override with setBufferSize().
#ifndef MQTT_MAX_PACKET_SIZE
#define MQTT_MAX_PACKET_SIZE 128
#define MQTT_MAX_PACKET_SIZE 256
#endif
// MQTT_KEEPALIVE : keepAlive interval in Seconds
@ -73,28 +73,38 @@
#define MQTTQOS1 (1 << 1)
#define MQTTQOS2 (2 << 1)
#ifdef ESP8266
// Maximum size of fixed header and variable length size header
#define MQTT_MAX_HEADER_SIZE 5
#if defined(ESP8266) || defined(ESP32)
#include <functional>
#define MQTT_CALLBACK_SIGNATURE std::function<void(char*, uint8_t*, unsigned int)> callback
#else
#define MQTT_CALLBACK_SIGNATURE void (*callback)(char*, uint8_t*, unsigned int)
#endif
class PubSubClient {
#define CHECK_STRING_LENGTH(l,s) if (l+2+strnlen(s, this->bufferSize) > this->bufferSize) {_client->stop();return false;}
class PubSubClient : public Print {
private:
Client* _client;
uint8_t* buffer;
uint16_t buffer_size;
uint16_t bufferSize;
uint16_t nextMsgId;
unsigned long lastOutActivity;
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);
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 - <returned 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;
@ -125,24 +135,45 @@ public:
PubSubClient& setClient(Client& client);
PubSubClient& setStream(Stream& stream);
boolean setBufferSize(uint16_t size);
uint16_t getBufferSize();
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);
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);
// 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)
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
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);
boolean loop();
boolean connected();
int state();
boolean setBufferSize(uint16_t size);
uint16_t getBufferSize();
};