16 Commits

Author SHA1 Message Date
26ce89fa47 Update for 2.7 2018-11-02 11:42:44 +00:00
a29d0c3d72 Merge pull request #336 from jaecktec/master
Enable ESP32 to use PubSubClient (make MQTT_CALLBACK_SIGNATURE functional)
2018-11-02 01:07:40 +00:00
fa3c4362ea Merge branch 'master' into master 2018-11-02 01:07:33 +00:00
b381728998 Add yield to mock test framework 2018-11-02 01:05:02 +00:00
2bcd9b074a Merge pull request #472 from apicquot/master
Add yield to resolve connection failures
2018-11-02 01:01:44 +00:00
2ed03ad522 Merge pull request #362 from eykamp/new_sig
Create new signature to permit cleaner user code
2018-11-02 00:53:02 +00:00
2d053d2df0 Add buffer overflow protection to connect
Closes #492
2018-11-02 00:50:52 +00:00
ee30733e24 Fixup bad revert of 500 2018-11-02 00:12:44 +00:00
4daba0ae5c Fix remaining length protection 2018-11-02 00:06:32 +00:00
af860133e8 Merge branch 'pr_500' 2018-11-01 23:47:15 +00:00
a0f09681f5 Add separate connect function for clean session + test 2018-11-01 23:46:09 +00:00
05a601cc55 Merge pull request #512 from knolleary/revert-500-master
Revert "Added support of CleanSession flag during connect"
2018-11-01 23:35:56 +00:00
9e1a6e6479 Update PubSubClient.cpp
added yield to resolve random connection failure
2018-08-07 17:29:29 -04:00
8795fdf0f5 Create new signature to permit cleaner user code 2017-11-16 12:49:01 -08:00
8498284792 Add ESP32 to documentation 2017-09-19 18:10:09 +02:00
49f307506b Add ESP32 callback signature to be functional like ESP8266 2017-09-18 19:27:44 +02:00
9 changed files with 74 additions and 12 deletions

View File

@ -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 2.4
* Add MQTT_SOCKET_TIMEOUT to prevent it blocking indefinitely * Add MQTT_SOCKET_TIMEOUT to prevent it blocking indefinitely
whilst waiting for inbound data whilst waiting for inbound data
* Fixed return code when publishing >256 bytes * Fixed return code when publishing >256 bytes
2.3 2.3
* Add publish(topic,payload,retained) function * Add publish(topic,payload,retained) function

View File

@ -37,6 +37,7 @@ boards and shields, including:
- TI CC3000 WiFi - [library](https://github.com/sparkfun/SFE_CC3000_Library) - TI CC3000 WiFi - [library](https://github.com/sparkfun/SFE_CC3000_Library)
- Intel Galileo/Edison - Intel Galileo/Edison
- ESP8266 - ESP8266
- ESP32
The library cannot currently be used with hardware based on the ENC28J60 chip 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 such as the Nanode or the Nuelectronics Ethernet Shield. For those, there is an

View File

@ -6,7 +6,7 @@
"type": "git", "type": "git",
"url": "https://github.com/knolleary/pubsubclient.git" "url": "https://github.com/knolleary/pubsubclient.git"
}, },
"version": "2.6", "version": "2.7",
"exclude": "tests", "exclude": "tests",
"examples": "examples/*/*.ino", "examples": "examples/*/*.ino",
"frameworks": "arduino", "frameworks": "arduino",

View File

@ -1,5 +1,5 @@
name=PubSubClient name=PubSubClient
version=2.6 version=2.7
author=Nick O'Leary <nick.oleary@gmail.com> author=Nick O'Leary <nick.oleary@gmail.com>
maintainer=Nick O'Leary <nick.oleary@gmail.com> maintainer=Nick O'Leary <nick.oleary@gmail.com>
sentence=A client library for MQTT messaging. sentence=A client library for MQTT messaging.

View File

@ -102,18 +102,22 @@ PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGN
} }
boolean PubSubClient::connect(const char *id) { 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) { 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) { 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) {
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()) { if (!connected()) {
int result = 0; int result = 0;
@ -141,9 +145,12 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass
uint8_t v; uint8_t v;
if (willTopic) { if (willTopic) {
v = 0x06|(willQos<<3)|(willRetain<<5); v = 0x04|(willQos<<3)|(willRetain<<5);
} else { } else {
v = 0x02; v = 0x00;
}
if (cleanSession) {
v = v|0x02;
} }
if(user != NULL) { if(user != NULL) {
@ -158,15 +165,21 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass
buffer[length++] = ((MQTT_KEEPALIVE) >> 8); buffer[length++] = ((MQTT_KEEPALIVE) >> 8);
buffer[length++] = ((MQTT_KEEPALIVE) & 0xFF); buffer[length++] = ((MQTT_KEEPALIVE) & 0xFF);
CHECK_STRING_LENGTH(length,id)
length = writeString(id,buffer,length); length = writeString(id,buffer,length);
if (willTopic) { if (willTopic) {
CHECK_STRING_LENGTH(length,willTopic)
length = writeString(willTopic,buffer,length); length = writeString(willTopic,buffer,length);
CHECK_STRING_LENGTH(length,willMessage)
length = writeString(willMessage,buffer,length); length = writeString(willMessage,buffer,length);
} }
if(user != NULL) { if(user != NULL) {
CHECK_STRING_LENGTH(length,user)
length = writeString(user,buffer,length); length = writeString(user,buffer,length);
if(pass != NULL) { if(pass != NULL) {
CHECK_STRING_LENGTH(length,pass)
length = writeString(pass,buffer,length); length = writeString(pass,buffer,length);
} }
} }
@ -209,6 +222,7 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass
boolean PubSubClient::readByte(uint8_t * result) { boolean PubSubClient::readByte(uint8_t * result) {
uint32_t previousMillis = millis(); uint32_t previousMillis = millis();
while(!_client->available()) { while(!_client->available()) {
yield();
uint32_t currentMillis = millis(); uint32_t currentMillis = millis();
if(currentMillis - previousMillis >= ((int32_t) MQTT_SOCKET_TIMEOUT * 1000)){ if(currentMillis - previousMillis >= ((int32_t) MQTT_SOCKET_TIMEOUT * 1000)){
return false; return false;
@ -240,7 +254,7 @@ uint16_t PubSubClient::readPacket(uint8_t* lengthLength) {
uint8_t start = 0; uint8_t start = 0;
do { do {
if (len == 6) { if (len == 5) {
// Invalid remaining length encoding - kill the connection // Invalid remaining length encoding - kill the connection
_state = MQTT_DISCONNECTED; _state = MQTT_DISCONNECTED;
_client->stop(); _client->stop();
@ -385,6 +399,10 @@ boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigne
return false; 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) { boolean PubSubClient::publish_P(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) {
uint8_t llen = 0; uint8_t llen = 0;
uint8_t digit; uint8_t digit;

View File

@ -76,13 +76,15 @@
// Maximum size of fixed header and variable length size header // Maximum size of fixed header and variable length size header
#define MQTT_MAX_HEADER_SIZE 5 #define MQTT_MAX_HEADER_SIZE 5
#ifdef ESP8266 #if defined(ESP8266) || defined(ESP32)
#include <functional> #include <functional>
#define MQTT_CALLBACK_SIGNATURE std::function<void(char*, uint8_t*, unsigned int)> callback #define MQTT_CALLBACK_SIGNATURE std::function<void(char*, uint8_t*, unsigned int)> callback
#else #else
#define MQTT_CALLBACK_SIGNATURE void (*callback)(char*, uint8_t*, unsigned int) #define MQTT_CALLBACK_SIGNATURE void (*callback)(char*, uint8_t*, unsigned int)
#endif #endif
#define CHECK_STRING_LENGTH(l,s) if (l+2+strlen(s) > MQTT_MAX_PACKET_SIZE) {_client->stop();return false;}
class PubSubClient : public Print { class PubSubClient : public Print {
private: private:
Client* _client; Client* _client;
@ -134,11 +136,13 @@ public:
boolean connect(const char* id, const char* user, const char* pass); 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* 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 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(); void disconnect();
boolean publish(const char* topic, const char* payload); boolean publish(const char* topic, const char* payload);
boolean publish(const char* topic, const char* payload, boolean retained); 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 publish(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained); 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 publish_P(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained);
// Start to publish a message. // Start to publish a message.
// This API: // This API:

View File

@ -98,6 +98,33 @@ int test_connect_fails_on_bad_rc() {
END_IT 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() { int test_connect_accepts_username_password() {
IT("accepts a username and password"); IT("accepts a username and password");
ShimClient shimClient; ShimClient shimClient;
@ -256,10 +283,12 @@ int test_connect_disconnect_connect() {
int main() int main()
{ {
SUITE("Connect"); SUITE("Connect");
test_connect_fails_no_network(); test_connect_fails_no_network();
test_connect_fails_on_no_response(); test_connect_fails_on_no_response();
test_connect_properly_formatted(); test_connect_properly_formatted();
test_connect_non_clean_session();
test_connect_accepts_username_password(); test_connect_accepts_username_password();
test_connect_fails_on_bad_rc(); test_connect_fails_on_bad_rc();
test_connect_properly_formatted_hostname(); test_connect_properly_formatted_hostname();

View File

@ -21,4 +21,6 @@ extern "C"{
#define PROGMEM #define PROGMEM
#define pgm_read_byte_near(x) *(x) #define pgm_read_byte_near(x) *(x)
#define yield(x) {}
#endif // Arduino_h #endif // Arduino_h

View File

@ -174,8 +174,8 @@ int test_drop_invalid_remaining_length_message() {
int rc = client.connect((char*)"client_test1"); int rc = client.connect((char*)"client_test1");
IS_TRUE(rc); 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}; 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,21); shimClient.respond(publish,20);
rc = client.loop(); rc = client.loop();