From 315e45803f38d1b3adca94f6e9c7103200f03f0f Mon Sep 17 00:00:00 2001 From: Johannes Schriewer Date: Mon, 30 Jul 2018 22:34:28 +0200 Subject: [PATCH] Bugfix: Expose config to error handler to be able to change and reconnect Re #16 --- Readme.md | 14 ++++++++++---- src/mqtt.c | 14 +++++++------- src/mqtt.h | 2 +- tests/connect_publish.c | 2 +- tests/connect_subscribe.c | 2 +- tests/encode_packet.c | 1 + 6 files changed, 21 insertions(+), 14 deletions(-) diff --git a/Readme.md b/Readme.md index 5dbc8a9..8aeede2 100644 --- a/Readme.md +++ b/Readme.md @@ -19,7 +19,6 @@ MQTT library for multiple platforms including embedded targets. - [ ] QoS testing, client -> server QoS partly works, server -> client does not - [ ] Running in MQTT Broker mode -- [ ] Last will is implemented but not exposed in API - [ ] Implement Protocol level 3 (low prio) - [ ] Implement Draft Protocol level 5 (somewhat low prio as it's a draft spec) - [ ] Support ESP8266 (RTOS) @@ -79,10 +78,15 @@ typedef struct { char *hostname; /**< Hostname to connect to, will do DNS resolution */ uint16_t port; /**< Port the broker listens on, set to 0 for 1883 default */ - char *client_id; /**< Client identification */ + char *client_id; /**< Client identification max 23 chars */ + bool clean_session; /**< Set to true to reset the session on reconnect */ char *username; /**< User name, set to NULL to connect anonymously */ char *password; /**< Password, set to NULL to connect without password */ + + char *last_will_topic; /**< last will topic that is automatically published on connection loss */ + char *last_will_message; /**< last will message */ + bool last_will_retain; /**< tell server to retain last will message */ } MQTTConfig; ``` @@ -104,7 +108,7 @@ or re-trying by changing settings and calling mqtt_reconnect() and returning fal The error handler should be defined like this: ```c -bool error_handler(MQTTHandle *handle, MQTTErrorCode code) { +bool error_handler(MQTTHandle *handle, MQTTConfig *config, MQTTErrorCode code) { return true; // kill the handle, return false to keep it } @@ -138,10 +142,11 @@ a successful reconnect. #### Subscribe to a topic ```c -MQTTStatus mqtt_subscribe(MQTTHandle *handle, char *topic, MQTTPublishEventHandler callback); +MQTTStatus mqtt_subscribe(MQTTHandle *handle, char *topic, MQTTQosLevel qos_level, MQTTPublishEventHandler callback); ``` - `handle`: MQTT Handle from `mqtt_connect` - `topic`: Topic to subscribe +- `qos_level`: Maximum QoS level to subscribe for - `callback`: Callback function to call when receiving something for that topic - Returns status code @@ -174,6 +179,7 @@ MQTTStatus mqtt_publish(MQTTHandle *handle, char *topic, char *payload, MQTTQosL - `handle`: MQTT Handle from `mqtt_connect` - `topic`: Topic to publish to - `payload`: Message payload to publish +- `qos_level`: QoS Level for the publish (0 = Fire and forget, 1 = At least once, 2 = One time for sure) - Returns status code This uses a c-string as the payload, theoretically the protocol would allow for binary payloads, but this is currently diff --git a/src/mqtt.c b/src/mqtt.c index 4b8dc4b..dcd5536 100644 --- a/src/mqtt.c +++ b/src/mqtt.c @@ -137,7 +137,7 @@ static void _mqtt_connect(MQTTHandle *handle, MQTTEventHandler callback, void *c char ip[40]; if (!hostname_to_ip(handle->config->hostname, ip)) { - bool free_handle = handle->error_handler(handle, MQTT_Error_Host_Not_Found); + bool free_handle = handle->error_handler(handle, handle->config, MQTT_Error_Host_Not_Found); if (free_handle) { mqtt_free(handle); } @@ -147,7 +147,7 @@ static void _mqtt_connect(MQTTHandle *handle, MQTTEventHandler callback, void *c } ret = inet_pton(AF_INET, ip, &(servaddr.sin_addr)); if (ret == 0) { - bool free_handle = handle->error_handler(handle, MQTT_Error_Host_Not_Found); + bool free_handle = handle->error_handler(handle, handle->config, MQTT_Error_Host_Not_Found); if (free_handle) { mqtt_free(handle); } @@ -158,7 +158,7 @@ static void _mqtt_connect(MQTTHandle *handle, MQTTEventHandler callback, void *c ret = connect(handle->sock, (struct sockaddr *)&servaddr, sizeof(servaddr)); if (ret != 0) { - bool free_handle = handle->error_handler(handle, MQTT_Error_Connection_Refused); + bool free_handle = handle->error_handler(handle, handle->config, MQTT_Error_Connection_Refused); if (free_handle) { mqtt_free(handle); } @@ -174,7 +174,7 @@ static void _mqtt_connect(MQTTHandle *handle, MQTTEventHandler callback, void *c bool result = send_connect_packet(handle); if (result == false) { DEBUG_LOG("Sending connect packet failed, running error handler"); - bool free_handle = handle->error_handler(handle, MQTT_Error_Broker_Disconnected); + bool free_handle = handle->error_handler(handle, handle->config, MQTT_Error_Broker_Disconnected); if (free_handle) { mqtt_free(handle); } @@ -223,7 +223,7 @@ MQTTStatus mqtt_reconnect(MQTTHandle *handle, MQTTEventHandler callback, void *c MQTTStatus mqtt_subscribe(MQTTHandle *handle, char *topic, MQTTQosLevel qos_level, MQTTPublishEventHandler callback) { if (!handle->reader_alive) { - handle->error_handler(handle, MQTT_Error_Connection_Reset); + handle->error_handler(handle, handle->config, MQTT_Error_Connection_Reset); return MQTT_STATUS_ERROR; } add_subscription(handle, topic, qos_level, callback); @@ -232,7 +232,7 @@ MQTTStatus mqtt_subscribe(MQTTHandle *handle, char *topic, MQTTQosLevel qos_leve MQTTStatus mqtt_unsubscribe(MQTTHandle *handle, char *topic) { if (!handle->reader_alive) { - handle->error_handler(handle, MQTT_Error_Connection_Reset); + handle->error_handler(handle, handle->config, MQTT_Error_Connection_Reset); return MQTT_STATUS_ERROR; } remove_subscription(handle, topic); @@ -241,7 +241,7 @@ MQTTStatus mqtt_unsubscribe(MQTTHandle *handle, char *topic) { MQTTStatus mqtt_publish(MQTTHandle *handle, char *topic, char *payload, MQTTQosLevel qos_level) { if (!handle->reader_alive) { - handle->error_handler(handle, MQTT_Error_Connection_Reset); + handle->error_handler(handle, handle->config, MQTT_Error_Connection_Reset); return MQTT_STATUS_ERROR; } return (send_publish_packet(handle, topic, payload, qos_level) ? MQTT_STATUS_OK : MQTT_STATUS_ERROR); diff --git a/src/mqtt.h b/src/mqtt.h index 3f5c218..55e7247 100644 --- a/src/mqtt.h +++ b/src/mqtt.h @@ -45,7 +45,7 @@ typedef enum { * * Return true if the handle should be freed, false to keep it */ -typedef bool (*MQTTErrorHandler)(MQTTHandle *handle, MQTTErrorCode code); +typedef bool (*MQTTErrorHandler)(MQTTHandle *handle, MQTTConfig *config, MQTTErrorCode code); /** Event handler callback */ typedef void (*MQTTEventHandler)(MQTTHandle *handle, void *context); diff --git a/tests/connect_publish.c b/tests/connect_publish.c index 5b95ec8..6d872dd 100644 --- a/tests/connect_publish.c +++ b/tests/connect_publish.c @@ -8,7 +8,7 @@ bool leave = false; #define LOG(fmt, ...) fprintf(stdout, fmt "\n", ## __VA_ARGS__) -bool err_handler(MQTTHandle *handle, MQTTErrorCode error) { +bool err_handler(MQTTHandle *handle, MQTTConfig *config, MQTTErrorCode error) { LOG("Error received: %d", error); exit(1); diff --git a/tests/connect_subscribe.c b/tests/connect_subscribe.c index 3cdaa40..c8f8f03 100644 --- a/tests/connect_subscribe.c +++ b/tests/connect_subscribe.c @@ -8,7 +8,7 @@ bool leave = false; #define LOG(fmt, ...) fprintf(stdout, fmt "\n", ## __VA_ARGS__) -bool err_handler(MQTTHandle *handle, MQTTErrorCode error) { +bool err_handler(MQTTHandle *handle, MQTTConfig *config, MQTTErrorCode error) { LOG("Error received: %d", error); return 1; diff --git a/tests/encode_packet.c b/tests/encode_packet.c index 3fff34a..3b0452f 100644 --- a/tests/encode_packet.c +++ b/tests/encode_packet.c @@ -286,6 +286,7 @@ TestResult test_encode_publish_dup_qos0(void) { Buffer *encoded = mqtt_packet_encode(&(MQTTPacket){ PacketTypePublish, payload }); free(payload); TESTASSERT(encoded == NULL, "DUP and QoS level 0 is an incompatible combination"); + TEST_OK(); } TestResult test_encode_publish_with_msg(void) {