CommsChampion Ecosystem MQTT v3.1.1 Client
MQTT v3.1.1 Client Library.
MQTT v3.1.1 Client Library

Table of Contents

Overview

The MQTT v3.1.1 Client Library from the CommsChampion Ecosystem provides simple, asynchronous, non-blocking, and easy to use interface to operate MQTT v3.1.1 client. The library doesn't make any assumption on the system it is running on, as well as on the type of I/O link being used to communicate its data to the MQTT v3.1.1 capable broker.

It is a responsibility of the calling application to manage network connectivity as well as measure time required for the correct operation of the MQTT v3.1.1 protocol.

The library allows the application to have a full control over the raw data for any extra analysis and/or manipulation, such as encryption or extra framing.

Version of the Library

The version is of the library applicable to this documentation is defined in the cc_mqtt311_client/common.h file using the following defines:

Header

To use this MQTT v3.1.1 Client Library use the following single include statement:

#include "cc_mqtt311_client/client.h"

Client Allocation

The library supports multiple independent MQTT v3.1.1 client sessions. The allocation of data structures relevant to a single client is performed using cc_mqtt311_client_alloc() function.

CC_Mqtt311ClientHandle cc_mqtt311_client_alloc()
Allocate new client.
CC_Mqtt311Client * CC_Mqtt311ClientHandle
Handle used to access client specific data structures.
Definition: common.h:132

All other functions are client specific, they receive the returned handle as their first parameter.

When work with allocated client is complete, it must be freed using cc_mqtt311_client_free() function.

void cc_mqtt311_client_free(CC_Mqtt311ClientHandle handle)
Free previously allocated client.

When working with C++ it is advised to use a smart pointer with a custom deleter.

struct MyDeleter
{
void operator()(CC_Mqtt311Client* ptr)
{
}
};
using MyClientPtr = std::unique_ptr<CC_Mqtt311Client, MyDeleter>;
MyClientPtr clientPtr(::cc_mqtt311_client_alloc());
CC_Mqtt311ClientHandle client = clientPtr.get();

IMPORTANT: The function cc_mqtt311_client_free() must NOT be called from within a callback. Use next event loop iteration.

"Must Have" Callbacks Registration

In order to properly function the library requires setting several callbacks.

Sending Data To Broker

To client application must assign a callback for the library to be able to send binary data out to the connected broker.

void my_send_data_cb(void* data, const unsigned char* buf, unsigned bufLen)
{
... /* send requested buffer to the broker */
}
cc_mqtt311_client_set_send_output_data_callback(client, &my_send_data_cb, data);
void cc_mqtt311_client_set_send_output_data_callback(CC_Mqtt311ClientHandle handle, CC_Mqtt311SendOutputDataCb cb, void *data)
Set callback to send raw data over I/O link.

See also the documentation of the CC_Mqtt311SendOutputDataCb callback function definition.

In the invoked callback the application is responsible to send the provided data over the I/O link. The application can also perform extra data manipulation like encryption.

The reported data resides in internal data structures of the client library, which can be updated / deleted right after the callback function returns. It means the data may need to be copied into some other buffer, which will be held intact until the send over I/O link operation is complete.

Reporting Unsolicited Broker Disconnection

The client application must assign a callback for the library to report discovered broker disconnection.

void my_broker_disconnected_cb(void* data, CC_Mqtt311BrokerDisconnectReason reason)
{
... /* handle broker disconnection */
if (info != NULL) {
... /* Access disconnection report details */
}
}
cc_mqtt311_client_set_broker_disconnect_report_callback(client, &my_broker_disconnected_cb, data);
void cc_mqtt311_client_set_broker_disconnect_report_callback(CC_Mqtt311ClientHandle handle, CC_Mqtt311BrokerDisconnectReportCb cb, void *data)
Set callback to report unsolicited disconnection of the broker.
CC_Mqtt311BrokerDisconnectReason
Reason for reporting unsolicited broker disconnection.
Definition: common.h:100

See also the documentation of the CC_Mqtt311BrokerDisconnectReportCb callback function definition.

See also Unsolicited Broker Disconnection below for details.

Reporting Received Message

The client application must assign a callback for the library to report application level messages received from the broker.

void my_message_received_cb(void* data, const CC_Mqtt311MessageInfo* info)
{
... /* handle the received message */
}
cc_mqtt311_client_set_message_received_report_callback(client, &my_message_received_cb, data);
void cc_mqtt311_client_set_message_received_report_callback(CC_Mqtt311ClientHandle handle, CC_Mqtt311MessageReceivedReportCb cb, void *data)
Set callback to report received message from the broker.
Received message information.
Definition: common.h:245

See also the documentation of the CC_Mqtt311MessageReceivedReportCb callback function definition.

Time Measurement

For the correct operation of the MQTT v3.1.1 client side of the protocol, the library requires an ability to measure time. This responsibility is delegated to the application.

The easiest (although not very efficient or very precise) method is to periodically (say every 20ms - 50ms) call the cc_mqtt311_client_tick() function reporting the amount of elapsed milliseconds:

void cc_mqtt311_client_tick(CC_Mqtt311ClientHandle handle, unsigned ms)
Notify client about requested time expiry.

The library will check if some inner timer has expired and may initiate some response via invocation one of the registered callbacks.

Another (recommended) method is to register a callback so the library may request the time measurement from the application, and when the requested time expires, the application is expected to call the cc_mqtt311_client_tick() function reporting amount of elapsed milliseconds.

void my_tick_program_cb(void* data, unsigned ms)
{
... // program appropriate timer
}
cc_mqtt311_client_set_next_tick_program_callback(client, &my_tick_program_cb, data);
void cc_mqtt311_client_set_next_tick_program_callback(CC_Mqtt311ClientHandle handle, CC_Mqtt311NextTickProgramCb cb, void *data)
Set callback to call when time measurement is required.

It is allowed to invoke the cc_mqtt311_client_tick() before the actual requested timeout has expired, just make sure that the correct amount of elapsed milliseconds is reported. When the cc_mqtt311_client_tick() is invoked, it is assumed that the previously requested tick programming has been cancelled and the registered callback requesting to re-program the timer may be invoked again from within the cc_mqtt311_client_tick().

See also the documentation of the CC_Mqtt311NextTickProgramCb callback function definition.

In case of callback approach for time measurement is chosen, another callback function (in addition to requesting the new timer programming) to allow interruption of the previously programmed timer must also to be registered.

unsigned my_cancel_tick_program_cb(void* data)
{
...
return ... /* return amount of elapsed milliseconds since last tick program */
}
cc_mqtt311_client_set_cancel_next_tick_wait_callback(client, &my_cancel_tick_program_cb, data);
void cc_mqtt311_client_set_cancel_next_tick_wait_callback(CC_Mqtt311ClientHandle handle, CC_Mqtt311CancelNextTickWaitCb cb, void *data)
Set callback to terminate current time measurement.

See also the documentation of the CC_Mqtt311CancelNextTickWaitCb callback function definition.

Usually the callbacks of canceling the previously programmed tick and programming a new one will be invoked as a side effect of other events, like report of the incoming data or client requesting to perform one of the available operations.

Error Logging

Sometimes the library may exhibit unexpected behaviour, like rejecting some of the parameters. To allow getting extra guidance information of what went wrong it is possible to register optional error logging callback.

void my_error_log_cb(void* data, const char* msg)
{
printf("ERROR: %s\n", msg);
}
cc_mqtt311_client_set_error_log_callback(client, &my_error_log_cb, data);
void cc_mqtt311_client_set_error_log_callback(CC_Mqtt311ClientHandle handle, CC_Mqtt311ErrorLogCb cb, void *data)
Set callback to report error messages.

See also the documentation of the CC_Mqtt311ErrorLogCb callback function definition.

Reporting Incoming Data

It is the responsibility of the application to receive data from the broker and report it to the library. The report is performed using the cc_mqtt311_client_process_data() function.

uint8_t buf[MAX_BUF_SIZE];
... // Receive data into buffer
unsigned bufLen = ...; // Amount of received bytes in the buffer.
unsigned consumed = cc_mqtt311_client_process_data(client, buf, bufLen);
... // Remove the first "consumed" bytes from the buffer and retain the rest
// until the new data chunk arrives.
unsigned cc_mqtt311_client_process_data(CC_Mqtt311ClientHandle handle, const unsigned char *buf, unsigned bufLen)
Provide data (received over I/O link), to the library for processing.

The application is responsible to maintain the input buffer. The value returned from the cc_mqtt311_client_process_data() function reports amount of consumed bytes. In case not all of the reported bytes were consumed the application is responsible to keep them and report again with new appended data when such arrives.

When new data chunk is reported the library may invoke several callbacks, such as reporting received message, sending new data out, as well as canceling the old and programming new tick timeout.

Operating Concepts

The library abstracts away multiple MQTT v3.1.1 protocol based "operations". Every such operation has multiple stages:

  • prepare - The operation is "allocated" and relevant handle is returned.
  • configure - Apply one or multiple configurations to the prepared operation.
  • send - Send the configured operation message to the broker.

During the send stage the application is expected to provide the callback to report to the application when the operation is complete. One of the parameters of the callback is always "status" of the CC_Mqtt311AsyncOpStatus type. It indicates whether the operation was successfully complete. In addition to the status it reports some extra information reported by the broker. The information from the broker is available if and only if the status is CC_Mqtt311AsyncOpStatus_Complete.

The send stage function also returns CC_Mqtt311ErrorCode value to indicate whether the send was successfully performed. The provided callback will be invoked if and only if the send returns CC_Mqtt311ErrorCode_Success.

After the send stage the handle returned in the prepare stage can be discarded (no explicit de-allocation is needed / supported) regardless of the return code. After successful send the handle still remains valid until the callback invocation and can be used to cancel the operation. Note that in case the appropriate message has already be sent to the broker, cancelling the outstanding operation can be dangerous. When broker sends a response and client is not expecting it any more, unexpected behaviour (like treating the unexpected message as "protocol error" and disconnecting from the broker) may happen.

In case something went wrong during the configure stage, it is possible to de-allocate the prepared operation using the cancel request. After performing the cancel stage the allocated handle is no longer valid.

IMPORTANT LIBRARY LIMITATION: Once an operation is prepared, it must be be immediately configured and sent (or cancelled) before any other other operation can be prepared. For example:

assert(connect != nullptr);
// The following attempt to prepare the "subscribe" operation will fail because
// previously allocated "connect" hasn't been sent or cancelled yet.
assert(subscribe == NULL);
CC_Mqtt311ConnectHandle cc_mqtt311_client_connect_prepare(CC_Mqtt311ClientHandle handle, CC_Mqtt311ErrorCode *ec)
Prepare "connect" operation.
CC_Mqtt311Connect * CC_Mqtt311ConnectHandle
Handle for "connect" operation.
Definition: common.h:141
CC_Mqtt311ErrorCode
Error code returned by various API functions.
Definition: common.h:54
@ CC_Mqtt311ErrorCode_Success
The requested function executed successfully.
Definition: common.h:55
CC_Mqtt311SubscribeHandle cc_mqtt311_client_subscribe_prepare(CC_Mqtt311ClientHandle handle, CC_Mqtt311ErrorCode *ec)
Prepare "subscribe" operation.
CC_Mqtt311Subscribe * CC_Mqtt311SubscribeHandle
Handle for "subscribe" operation.
Definition: common.h:159

Default Response Timeout

After sending any operation request to the broker, the client library has to allow some time for the broker to process the request. If it takes too much time, the client must report that operation has failed via the set callback. By default the client library allows 2 seconds for such response to arrive. Changing this default value is possible using the cc_mqtt311_client_set_default_response_timeout() function, and retrieving of the currently configured value can be done using the cc_mqtt311_client_get_default_response_timeout() function.

... /* Something went wrong */
}
CC_Mqtt311ErrorCode cc_mqtt311_client_set_default_response_timeout(CC_Mqtt311ClientHandle handle, unsigned ms)
Configure default response timeout period.

Connecting to Broker

To connect to broker use connect operation.

Preparing "Connect" Operation.

if (connect == NULL) {
printf("ERROR: Connect allocation failed with ec=%d\n", ec);
}

NOTE that the cc_mqtt311_client_connect_prepare() cannot be called from within a callback. For example, if the broker disconnection is reported via callback then the cc_mqtt311_client_connect_prepare() cannot be invoked right away. It needs to be postponed until the next event loop iteration.

Configuring "Connect" Response Timeout

When created, the "connect" operation inherits the Default Response Timeout configuration. It can be changed for the allocated operation using the cc_mqtt311_client_connect_set_response_timeout() function.

... /* Something went wrong */
}
CC_Mqtt311ErrorCode cc_mqtt311_client_connect_set_response_timeout(CC_Mqtt311ConnectHandle handle, unsigned ms)
Configure the broker response timeout for the "connect" operation.

To retrieve the configured response timeout use the cc_mqtt311_client_connect_get_response_timeout() function.

Configuration of "Connect" Operation

To configure "connect" operation use cc_mqtt311_client_connect_config() function.

// Assign default values to the "config"
// Update the values if needed:
config.m_clientId = "some_client";
config.m_cleanSession = true;
// Perform the configuration
ec = cc_mqtt311_client_connect_config(connect, &config);
printf("ERROR: Basic configuration failed with ec=%d\n", ec);
...
}
void cc_mqtt311_client_connect_init_config(CC_Mqtt311ConnectConfig *config)
Intialize the CC_Mqtt311ConnectConfig configuration structure.
CC_Mqtt311ErrorCode cc_mqtt311_client_connect_config(CC_Mqtt311ConnectHandle handle, const CC_Mqtt311ConnectConfig *config)
Perform basic configuration of the "connect" operation.
Configuration structure to be passed to the cc_mqtt311_client_connect_config().
Definition: common.h:188
bool m_cleanSession
Clean session flag, defaults to false.
Definition: common.h:194
const char * m_clientId
Zero terminated Client ID string, can be NULL. When NULL means empty "Client ID". Defaults to NULL.
Definition: common.h:189

IMPORTANT: MQTT v3.1.1 specification allows reconnection to the broker while requesting previous session restoration (via "clean session" bit). By default, the client library verifies that the message received from the broker was actually subscribed to before reporting the message to the application (see Receiving Messages for details). To prevent potential errors of the client and broker inner states being out of sync, the first "connect" operation requires setting the CC_Mqtt311ConnectConfig::m_cleanSession value to true. The only exception to this rule is when the subscription verification on message reception was disabled (described in the Receiving Messages section below). In case the subscription verification is still enabled and the CC_Mqtt311ConnectConfig::m_cleanSession value is NOT set to true, the function rejects the configuration with the CC_Mqtt311ErrorCode_BadParam error code. Any subsequent reconnection attempts will allow setting the value to false.

See also documentation of the CC_Mqtt311ConnectConfig structure.

Will Configuration

To perform will configuration use the cc_mqtt311_client_connect_config_will() function.

// Assign default values to the configuration
// Update values if needed
willConfig.m_topic = "some/topic";
willConfig.m_data = ...;
willConfig.m_dataLen = ...;
...
// Perform the configuration
ec = cc_mqtt311_client_connect_config_will(connect, &willConfig);
printf("ERROR: Will configuration failed with ec=%d\n", ec);
...
}
CC_Mqtt311ErrorCode cc_mqtt311_client_connect_config_will(CC_Mqtt311ConnectHandle handle, const CC_Mqtt311ConnectWillConfig *config)
Perform will configuration of the "connect" operation.
void cc_mqtt311_client_connect_init_config_will(CC_Mqtt311ConnectWillConfig *config)
Intialize the CC_Mqtt311ConnectWillConfig configuration structure.
Configuration structure to be passed to the cc_mqtt311_client_connect_config_will().
Definition: common.h:201
const unsigned char * m_data
Will message data, can be NULL. Defaults to NULL.
Definition: common.h:203
unsigned m_dataLen
Number of will data bytes. When 0 means no data. Defaults to 0.
Definition: common.h:204
const char * m_topic
Will topic string, must NOT be NULL or empty. Defaults to NULL.
Definition: common.h:202

See also documentation of the CC_Mqtt311ConnectWillConfig structure.

Sending Connection Request

When all the necessary configurations are performed for the allocated "connect" operation it can actually be sent to the broker. To initiate sending use the cc_mqtt311_client_connect_send() function.

void my_connect_complete_cb(void* data, CC_Mqtt311AsyncOpStatus status, const CC_Mqtt311ConnectResponse* response)
{
printf("ERROR: The connection operation has failed with status=%d\n", status);
... // handle error.
return;
}
// "response" is not NULL when status is CC_Mqtt311AsyncOpStatus_Complete.
assert(response != NULL);
... // Analyze response values.
}
ec = cc_mqtt311_client_connect_send(connect, &my_connect_complete_cb, data);
printf("ERROR: Failed to send connect request with ec=%d\n", ec);
...
}
CC_Mqtt311ErrorCode cc_mqtt311_client_connect_send(CC_Mqtt311ConnectHandle handle, CC_Mqtt311ConnectCompleteCb cb, void *cbData)
Send the configured "connect" operation to broker.
CC_Mqtt311AsyncOpStatus
Status of the asynchronous operation.
Definition: common.h:76
@ CC_Mqtt311AsyncOpStatus_Complete
The requested operation has been completed, refer to reported extra details for information.
Definition: common.h:77
Response information from broker to "connect" request.
Definition: common.h:212

The provided callback will be invoked when the "connect" operation is complete if and only if the function returns CC_Mqtt311ErrorCode_Success.

The handle returned by the cc_mqtt311_client_connect_prepare() function can be discarded (there is no free / de-allocation) right after the cc_mqtt311_client_connect_send() invocation regardless of the returned error code. However, the handle remains valid until the callback is called (in case the CC_Mqtt311ErrorCode_Success was returned). The valid handle can be used to cancel the operation before the completion callback is invoked.

When the "connect" operation completion callback is invoked the reported "response" information is present if and only if the "status" is CC_Mqtt311AsyncOpStatus_Complete.

NOTE that only single "connect" operation is allowed at a time, any attempt to prepare a new one via cc_mqtt311_client_connect_prepare() will be rejected until the "connect" operation completion callback is invoked or the operation is cancelled.

Quote from the MQTT v3.1.1 specification:

If a server sends a CONNACK packet containing a non-zero return code it MUST
then close the Network Connection [MQTT-3.2.2-5].

When the callback reporting the connection status is invoked, it is responsibility of the application to check the CC_Mqtt311ConnectResponse::m_returnCode value. If it's not CC_Mqtt311ConnectReturnCode_Accepted, the application is responsible to close the network connection and retry the "connect" operation after the network connection to the broker is re-established. The same should be done when the "connect" operation is not properly completed, i.e. the reported status is NOT CC_Mqtt311AsyncOpStatus_Complete.

Cancel the "Connect" Operation.

While the handle returned by the cc_mqtt311_client_connect_prepare() is still valid it is possible to cancel / discard the operation.

printf("ERROR: Failed to cancel connect with ec=%d\n", ec);
...
}
CC_Mqtt311ErrorCode cc_mqtt311_client_connect_cancel(CC_Mqtt311ConnectHandle handle)
Cancel the allocated "connect" operation.

In case the cc_mqtt311_client_connect_send() function was successfully called before the cc_mqtt311_client_connect_cancel(), the operation is cancelled without callback invocation.

Simplifying the "Connect" Operation Preparation.

In many use cases the "connect" operation can be quite simple with a lot of defaults. To simplify the sequence of the operation preparation and handling of errors, the library provides wrapper function(s) that can be used:

For example:

// Assign default values to the "config"
// Update the values if needed:
config.m_clientId = "some_client";
config.m_cleanSession = true;
ec = cc_mqtt311_client_connect(client, config, null, &my_connect_complete_cb, data);
printf("ERROR: Failed to send connect request with ec=%d\n", ec);
...
}
CC_Mqtt311ErrorCode cc_mqtt311_client_connect(CC_Mqtt311ClientHandle handle, const CC_Mqtt311ConnectConfig *config, const CC_Mqtt311ConnectWillConfig *willConfig, CC_Mqtt311ConnectCompleteCb cb, void *cbData)
Prepare, configure, and send "connect" request in one go.

Note that the wrapper function does NOT expose the handle returned by the cc_mqtt311_client_connect_prepare(). It means that it's not possible to cancel the "connect" operation before its completion.

Check The Library Remains Connected

At any time it is possible to check the internal state of the library of whether it's properly connected to the broker.

bool isConnected = cc_mqtt311_client_is_connected(client);
bool cc_mqtt311_client_is_connected(CC_Mqtt311ClientHandle handle)
Check the inner state of the library of whether it's connected to the broker.

Disconnecting From Broker

To intentionally disconnect from broker use disconnect operation. The unsolicited disconnection from the broker is described in ref Unsolicited Broker Disconnection section below.

Preparing "Disconnect" Operation.

if (disconnect == NULL) {
printf("ERROR: Disconnect allocation failed with ec=%d\n", ec);
}
CC_Mqtt311DisconnectHandle cc_mqtt311_client_disconnect_prepare(CC_Mqtt311ClientHandle handle, CC_Mqtt311ErrorCode *ec)
Prepare "disconnect" operation.
CC_Mqtt311Disconnect * CC_Mqtt311DisconnectHandle
Handle for "disconnect" operation.
Definition: common.h:150

Sending Disconnection Request

When the necessary configuration is performed for the allocated "disconnect" operation it can be sent to the broker. To initiate sending use the cc_mqtt311_client_disconnect_send() function.

printf("ERROR: Failed to send disconnect request with ec=%d\n", ec);
...
return;
}
assert(!cc_mqtt311_client_is_connected(client)); // Expect immediate disconnection after the successful send
CC_Mqtt311ErrorCode cc_mqtt311_client_disconnect_send(CC_Mqtt311DisconnectHandle handle)
Send the configured "disconnect" operation to broker.

NOTE that the cc_mqtt311_client_disconnect_send() function doesn't receive any callback because there is no expected response to the DISCONNECT message from the broker. The disconnection effect is immediate. The application is expected to terminate the network connection (while making sure that the the requested data is actually sent). The handle returned by the cc_mqtt311_client_disconnect_prepare() must be discarded.

In case there are other asynchronous operations that hasn't been completed yet, their completion callback is automatically invoked with CC_Mqtt311AsyncOpStatus_Aborted status.

IMPORTANT: In case of sending the explicit disconnection request the registered unsolicited disconnection callback is NOT invoked.

After the disconnection the application can re-establish network connection to the broker and perform the connect operation again.

Cancel the "Disconnect" Operation.

While the handle returned by the cc_mqtt311_client_disconnect_prepare() is still valid it is possible to cancel / discard the operation.

printf("ERROR: Failed to cancel disconnect with ec=%d\n", ec);
...
}
CC_Mqtt311ErrorCode cc_mqtt311_client_disconnect_cancel(CC_Mqtt311DisconnectHandle handle)
Cancel the allocated "disconnect" operation.

Simplifying the "Disonnect" Operation Preparation.

In many use cases the "disconnect" operation can be quite simple. To simplify the sequence of the operation preparation and handling of errors, the library provides wrapper function(s) that can be used:

For example:

printf("ERROR: Failed to send disconnect request with ec=%d\n", ec);
...
}
CC_Mqtt311ErrorCode cc_mqtt311_client_disconnect(CC_Mqtt311ClientHandle handle)
Prepare, and send "disconnect" request in one go.

Subscribing to Receive Messages

To subscribe to receive incoming messages use subscribe operation. The application can issue multiple "subscribe" operations in parallel.

Preparing "Subscribe" Operation.

if (subscribe == NULL) {
printf("ERROR: Subscribe allocation failed with ec=%d\n", ec);
}

Configuring "Subscribe" Response Timeout

When created, the "subscribe" operation inherits the Default Response Timeout configuration. It can be changed for the allocated operation using the cc_mqtt311_client_subscribe_set_response_timeout() function.

... /* Something went wrong */
}
CC_Mqtt311ErrorCode cc_mqtt311_client_subscribe_set_response_timeout(CC_Mqtt311SubscribeHandle handle, unsigned ms)
Configure the broker response timeout for the "subscribe" operation.

To retrieve the configured response timeout use the cc_mqtt311_client_subscribe_get_response_timeout() function.

Topic Configuration

Single SUBSCRIBE message can carry multiple topic subscriptions. Use separate cc_mqtt311_client_subscribe_config_topic() function invocation to configure each such subscription.

// Assign default values to the configuration
// Update values if needed
topicConfig.m_topic = "some/topic";
// Perform the configuration
ec = cc_mqtt311_client_subscribe_config_topic(subscribe, &topicConfig);
printf("ERROR: Topic configuration failed with ec=%d\n", ec);
...
}
CC_Mqtt311ErrorCode cc_mqtt311_client_subscribe_config_topic(CC_Mqtt311SubscribeHandle handle, const CC_Mqtt311SubscribeTopicConfig *config)
Add topic configuration of the "subscribe" operation.
void cc_mqtt311_client_subscribe_init_config_topic(CC_Mqtt311SubscribeTopicConfig *config)
Intialize the CC_Mqtt311SubscribeTopicConfig configuration structure.
Topic filter configuration structure of the "subscribe" operation.
Definition: common.h:221
const char * m_topic
"Topic Filter" string, mustn't be NULL
Definition: common.h:222

See also documentation of the CC_Mqtt311SubscribeTopicConfig structure.

By default the library will perform the analysis of the submitted topic format and reject it if topic format is incorrect. However, for performance reasons it is possible to disable such verification when client application ensures that no invalid topics are used.

... /* Something is wrong */
}
CC_Mqtt311ErrorCode cc_mqtt311_client_set_verify_outgoing_topic_enabled(CC_Mqtt311ClientHandle handle, bool enabled)
Control outgoing topic format verification.

NOTE that the configuration is global per client and not per "subscribe" operation.

Also note that the same function controls the verification of the "subscribe", "unsubscribe" and "publish" topic formats.

To retrieve the current configuration use cc_mqtt311_client_get_verify_outgoing_topic_enabled() function.

Sending Subscription Request

When all the necessary configurations are performed for the allocated "subscribe" operation it can actually be sent to the broker. To initiate sending use the cc_mqtt311_client_subscribe_send() function.

void my_subscribe_complete_cb(void* data, CC_Mqtt311SubscribeHandle handle, CC_Mqtt311AsyncOpStatus status, const CC_Mqtt311SubscribeResponse* response)
{
printf("ERROR: The subscription operation has failed with status=%d\n", status);
... // handle error.
return;
}
// "response" is not NULL when status is CC_Mqtt311AsyncOpStatus_Complete.
assert(response != NULL);
... // Analyze response values.
}
ec = cc_mqtt311_client_subscribe_send(subscribe, &my_subscribe_complete_cb, data);
printf("ERROR: Failed to send subscribe request with ec=%d\n", ec);
...
}
CC_Mqtt311ErrorCode cc_mqtt311_client_subscribe_send(CC_Mqtt311SubscribeHandle handle, CC_Mqtt311SubscribeCompleteCb cb, void *cbData)
Send the configured "subscribe" operation to broker.
Response information from broker to "subscribe" request.
Definition: common.h:229

The provided callback will be invoked when the "subscribe" operation is complete if and only if the function returns CC_Mqtt311ErrorCode_Success.

The handle returned by the cc_mqtt311_client_subscribe_prepare() function can be discarded (there is no free / de-allocation) right after the cc_mqtt311_client_subscribe_send() invocation regardless of the returned error code. However, the handle remains valid until the callback is called (in case the CC_Mqtt311ErrorCode_Success was returned). The valid handle can be used to cancel the operation before the completion callback is invoked.

Note that the callback function receives the "subscribe" operation handle as its second parameter. Although the handle is already invalid and cannot be used in any other function, it allows the application to identify the original "subscribe" request if multiple have been issued in parallel and use the same callback function for all of them.

When the "subscribe" operation completion callback is invoked the reported "response" information is present if and only if the "status" is CC_Mqtt311AsyncOpStatus_Complete.

Cancel the "Subscribe" Operation.

While the handle returned by the cc_mqtt311_client_subscribe_prepare() is still valid it is possible to cancel / discard the operation.

printf("ERROR: Failed to cancel subscribe with ec=%d\n", ec);
...
}
CC_Mqtt311ErrorCode cc_mqtt311_client_subscribe_cancel(CC_Mqtt311SubscribeHandle handle)
Cancel the allocated "subscribe" operation.

In case the cc_mqtt311_client_subscribe_send() function was successfully called before the cc_mqtt311_client_subscribe_cancel(), the operation is cancelled without callback invocation.

Simplifying the "Subscribe" Operation Preparation.

In many use cases the "subscribe" operation can be quite simple with a lot of defaults. To simplify the sequence of the operation preparation and handling of errors, the library provides wrapper function that can be used:

For example:

// Assign default values to the configuration
// Update values if needed
topicConfig.m_topic = "some/topic";
ec = cc_mqtt311_client_subscribe(client, &topicConfig, 1, &my_subscribe_complete_cb, data);
printf("ERROR: Failed to send subscribe request with ec=%d\n", ec);
...
}
CC_Mqtt311ErrorCode cc_mqtt311_client_subscribe(CC_Mqtt311ClientHandle handle, const CC_Mqtt311SubscribeTopicConfig *topicConfigs, unsigned topicConfigsCount, CC_Mqtt311SubscribeCompleteCb cb, void *cbData)
Prepare, configure, and send "subscribe" request in one go.

Note that the wrapper function does NOT expose the handle returned by the cc_mqtt311_client_subscribe_prepare(). It means that it's not possible to cancel the "subscribe" operation before its completion or identify the subscribe operation by the reported handle when the completion callback is invoked.

Unsubscribing from Message Reception

To unsubscribe from receiving incoming messages use unsubscribe operation. The application can issue multiple "unsubscribe" operations in parallel.

Preparing "Unsubscribe" Operation.

if (unsubscribe == NULL) {
printf("ERROR: Unsubscribe allocation failed with ec=%d\n", ec);
}
CC_Mqtt311Unsubscribe * CC_Mqtt311UnsubscribeHandle
Handle for "unsubscribe" operation.
Definition: common.h:168
CC_Mqtt311UnsubscribeHandle cc_mqtt311_client_unsubscribe_prepare(CC_Mqtt311ClientHandle handle, CC_Mqtt311ErrorCode *ec)
Prepare "unsubscribe" operation.

Configuring "Unsubscribe" Response Timeout

When created, the "unsubscribe" operation inherits the Default Response Timeout configuration. It can be changed for the allocated operation using the cc_mqtt311_client_unsubscribe_set_response_timeout() function.

... /* Something went wrong */
}
CC_Mqtt311ErrorCode cc_mqtt311_client_unsubscribe_set_response_timeout(CC_Mqtt311UnsubscribeHandle handle, unsigned ms)
Configure the broker response timeout for the "unsubscribe" operation.

To retrieve the configured response timeout use the cc_mqtt311_client_unsubscribe_get_response_timeout() function.

Topic Configuration

Single UNSUBSCRIBE message can carry multiple topic unsubscriptions. Use cc_mqtt311_client_unsubscribe_config_topic() function to configure each such unsubscription.

// Assign default values to the configuration
// Update values
topicConfig.m_topic = "some/topic";
// Perform the configuration
ec = cc_mqtt311_client_unsubscribe_config_topic(unsubscribe, &topicConfig);
printf("ERROR: Topic configuration failed with ec=%d\n", ec);
...
}
void cc_mqtt311_client_unsubscribe_init_config_topic(CC_Mqtt311UnsubscribeTopicConfig *config)
Intialize the CC_Mqtt311UnsubscribeTopicConfig configuration structure.
CC_Mqtt311ErrorCode cc_mqtt311_client_unsubscribe_config_topic(CC_Mqtt311UnsubscribeHandle handle, const CC_Mqtt311UnsubscribeTopicConfig *config)
Add topic configuration of the "unsubscribe" operation.
Topic filter configuration structure of the "unsubscribe" operation.
Definition: common.h:238
const char * m_topic
"Topic Filter" string, mustn't be NULL
Definition: common.h:239

See also documentation of the CC_Mqtt311UnsubscribeTopicConfig structure.

Note that explicitly initializing the CC_Mqtt311UnsubscribeTopicConfig configuration object is not really necessary, because it has only a single CC_Mqtt311UnsubscribeTopicConfig::m_topic member, which is going to be overwritten as part of the configuration. However, calling the cc_mqtt311_client_unsubscribe_init_config_topic() is still recommended to make the application's code future updates proof. Potentially the MQTT v3.1.1 specification and as the result this library can be updated by adding new fields to the CC_Mqtt311UnsubscribeTopicConfig struct. Having the "unnecessary" call to the cc_mqtt311_client_unsubscribe_init_config_topic() function makes sure that newly added field gets initialized to the default value without any need to update the application's code.

By default the library will perform the analysis of the submitted topic format and reject it if topic format is incorrect. However, for performance reasons it is possible to disable such verification when client application ensures that no invalid topics are used.

... /* Something is wrong */
}

NOTE that the configuration is global per client and not per "unsubscribe" operation.

Also note that the same function controls the verification of the "subscribe", "unsubscribe" and "publish" topic formats.

To retrieve the current configuration use cc_mqtt311_client_get_verify_outgoing_topic_enabled() function.

Sending Unsubscription Request

When all the necessary configurations are performed for the allocated "unsubscribe" operation it can actually be sent to the broker. To initiate sending use the cc_mqtt311_client_unsubscribe_send() function.

void my_unsubscribe_complete_cb(void* data, CC_Mqtt311UnsubscribeHandle handle, CC_Mqtt311AsyncOpStatus status)
{
printf("ERROR: The unsubscription operation has failed with status=%d\n", status);
... // handle error.
return;
}
...
}
ec = cc_mqtt311_client_unsubscribe_send(unsubscribe, &my_unsubscribe_complete_cb, data);
printf("ERROR: Failed to send unsubscribe request with ec=%d\n", ec);
...
}
CC_Mqtt311ErrorCode cc_mqtt311_client_unsubscribe_send(CC_Mqtt311UnsubscribeHandle handle, CC_Mqtt311UnsubscribeCompleteCb cb, void *cbData)
Send the configured "unsubscribe" operation to broker.

The provided callback will be invoked when the "unsubscribe" operation is complete if and only if the function returns CC_Mqtt311ErrorCode_Success.

The handle returned by the cc_mqtt311_client_unsubscribe_prepare() function can be discarded (there is no free / de-allocation) right after the cc_mqtt311_client_unsubscribe_send() invocation regardless of the returned error code. However, the handle remains valid until the callback is called (in case the CC_Mqtt311ErrorCode_Success was returned). The valid handle can be used to cancel the operation before the completion callback is invoked.

Note that the callback function receives the "unsubscribe" operation handle as its second parameter. Although the handle is already invalid and cannot be used in any other function, it allows the application to identify the original "unsubscribe" request if multiple have been issued in parallel and use the same callback function for all of them.

Cancel the "Unsubscribe" Operation.

While the handle returned by the cc_mqtt311_client_unsubscribe_prepare() is still valid it is possible to cancel / discard the operation.

printf("ERROR: Failed to cancel unsubscribe with ec=%d\n", ec);
...
}
CC_Mqtt311ErrorCode cc_mqtt311_client_unsubscribe_cancel(CC_Mqtt311UnsubscribeHandle handle)
Cancel the allocated "unsubscribe" operation.

In case the cc_mqtt311_client_unsubscribe_send() function was successfully called before the cc_mqtt311_client_unsubscribe_cancel(), the operation is cancelled without callback invocation.

Simplifying the "Unsubscribe" Operation Preparation.

In many use cases the "unsubscribe" operation can be quite simple with a lot of defaults. To simplify the sequence of the operation preparation and handling of errors, the library provides wrapper function that can be used:

For example:

// Assign default values to the configuration
// Update values
topicConfig.m_topic = "some/topic";
ec = cc_mqtt311_client_unsubscribe(client, &topicConfig, 1, &my_unsubscribe_complete_cb, data);
printf("ERROR: Failed to send unsubscribe request with ec=%d\n", ec);
...
}
CC_Mqtt311ErrorCode cc_mqtt311_client_unsubscribe(CC_Mqtt311ClientHandle handle, const CC_Mqtt311UnsubscribeTopicConfig *topicConfigs, unsigned topicConfigsCount, CC_Mqtt311UnsubscribeCompleteCb cb, void *cbData)
Prepare, configure, and send "unsubscribe" request in one go.

Note that the wrapper function does NOT expose the handle returned by the cc_mqtt311_client_unsubscribe_prepare(). It means that it's not possible to cancel the "unsubscribe" operation before its completion or identify the unsubscribe operation by the reported handle when the completion callback is invoked.

Publishing Messages

To publish messages to the broker use publish operation.

Preparing "Publish" Operation.

if (publish == NULL) {
printf("ERROR: Publish allocation failed with ec=%d\n", ec);
}
CC_Mqtt311Publish * CC_Mqtt311PublishHandle
Handle for "publish" operation.
Definition: common.h:177
CC_Mqtt311PublishHandle cc_mqtt311_client_publish_prepare(CC_Mqtt311ClientHandle handle, CC_Mqtt311ErrorCode *ec)
Prepare "publish" operation.

Configuring "Publish" Response Timeout

When publishing messages with QoS value CC_Mqtt311QoS_AtLeastOnceDelivery or above, the response from the broker is expected.

When created, the "publish" operation inherits the Default Response Timeout configuration. It can be changed for the allocated operation using the cc_mqtt311_client_publish_set_response_timeout() function.

... /* Something went wrong */
}
CC_Mqtt311ErrorCode cc_mqtt311_client_publish_set_response_timeout(CC_Mqtt311PublishHandle handle, unsigned ms)
Configure the broker response timeout for the "publish" operation.

To retrieve the configured response timeout use the cc_mqtt311_client_publish_get_response_timeout() function.

Configuring "Publish" Re-Send Attempts

The MQTT v3.1.1 specification has a mechanism of insured delivery of the published message to the broker. In the case of not 100% reliable connection the messages can get lost and needs to be re-sent. The default amount of re-sends is 2, i.e. when the first send is not acknowledged by the broker, it is tried again with DUP flag is set in the PUBLISH message. When the second attempt is not acknowledged, then the publish operation is terminated with appropriate status report. It is possible to change the default by using cc_mqtt311_client_publish_set_resend_attempts() function. The DUP flag will be set in all the re-sent PUBLISH messages.

... /* Something went wrong */
}
CC_Mqtt311ErrorCode cc_mqtt311_client_publish_set_resend_attempts(CC_Mqtt311PublishHandle handle, unsigned attempts)
Configure the amount of attempts to resend "publish" operation until the acknowledgement is received.

To retrieve the configured resend attempts number use the cc_mqtt311_client_publish_get_resend_attempts() function.

Configuration of "Publish" Operation

// Assign default values to the "config"
// Update the required values
config.m_topic = "some/topic";
config.m_data = &some_buf[0];
config.m_dataLen = ...;
config.m_qos = ...;
// Perform the configuration
ec = cc_mqtt311_client_publish_config(publish, &config);
printf("ERROR: Configuration failed with ec=%d\n", ec);
...
}
void cc_mqtt311_client_publish_init_config(CC_Mqtt311PublishConfig *config)
Intialize the CC_Mqtt311PublishConfig configuration structure.
CC_Mqtt311ErrorCode cc_mqtt311_client_publish_config(CC_Mqtt311PublishHandle handle, const CC_Mqtt311PublishConfig *config)
Perform basic configuration of the "publish" operation.
Configuration structure to be passed to the cc_mqtt311_client_publish_config().
Definition: common.h:257
unsigned m_dataLen
Amount of bytes in the publish data buffer, defaults to 0.
Definition: common.h:260
const unsigned char * m_data
Pointer to publish data buffer, defaults to NULL.
Definition: common.h:259
CC_Mqtt311QoS m_qos
Publish QoS value, defaults to CC_Mqtt311QoS_AtMostOnceDelivery.
Definition: common.h:261
const char * m_topic
Publish topic, cannot be NULL.
Definition: common.h:258

See also documentation of the CC_Mqtt311PublishConfig structure.

By default the library will perform the analysis of the submitted topic format and reject it if topic format is incorrect. However, for performance reasons it is possible to disable such verification when client application ensures that no invalid topics are used.

... /* Something is wrong */
}

To retrieve the current configuration use the cc_mqtt311_client_get_verify_outgoing_topic_enabled() function.

NOTE that the configuration is global per client and not per "publish" operation.

Also note that the same function controls the verification of the "subscribe", "unsubscribe", and "publish" filter / topic formats.

Sending Publish Request

When all the necessary configurations are performed for the allocated "publish" operation it can actually be sent to the broker. To initiate sending use the cc_mqtt311_client_publish_send() function.

void my_publish_complete_cb(void* data, CC_Mqtt311PublishHandle handle, CC_Mqtt311AsyncOpStatus status)
{
printf("ERROR: The publish operation has failed with status=%d\n", status);
... // handle error.
return;
}
...
}
ec = cc_mqtt311_client_publish_send(publish, &my_publish_complete_cb, data);
printf("ERROR: Failed to send publish request with ec=%d\n", ec);
...
}
CC_Mqtt311ErrorCode cc_mqtt311_client_publish_send(CC_Mqtt311PublishHandle handle, CC_Mqtt311PublishCompleteCb cb, void *cbData)
Send the configured "publish" operation to broker.

The provided callback will be invoked when the "publish" operation is complete if and only if the function returns CC_Mqtt311ErrorCode_Success.

The callback pointer can also be NULL. In such case the completion of the publish operation is silent.

When QoS value is CC_Mqtt311QoS_AtMostOnceDelivery, there is no broker response to wait for and the callback is invoked right away after sending the serialized data.

The handle returned by the cc_mqtt311_client_publish_prepare() function can be discarded (there is no free / de-allocation) right after the cc_mqtt311_client_publish_send() invocation regardless of the returned error code. However, the handle remains valid until the callback is called (in case the CC_Mqtt311ErrorCode_Success was returned). The valid handle can be used to cancel the operation before the completion callback is invoked.

Note that the callback function receives the "publish" operation handle as its second parameter. Although the handle is already invalid and cannot be used in any other function, it allows the application to identify the original "publish" request if multiple have been issued in parallel and use the same callback function for all of them.

Cancel the "Publish" Operation.

While the handle returned by the cc_mqtt311_client_publish_prepare() is still valid it is possible to cancel / discard the operation.

printf("ERROR: Failed to cancel publish with ec=%d\n", ec);
...
}
CC_Mqtt311ErrorCode cc_mqtt311_client_publish_cancel(CC_Mqtt311PublishHandle handle)
Cancel the allocated "publish" operation.

In case the cc_mqtt311_client_publish_send() function was successfully called before the cc_mqtt311_client_publish_cancel(), the operation is cancelled without callback invocation.

Message Ordering

The library implements strict message ordering for the same QoS messages required by the MQTT v3.1.1 specification. However, when different QoS messages are sent, the messages may arrive to the broker as well as recipient client in different order. For example, if all the publishes below issued together in the specified order, the Message2 and Message3 will probably arrive before Message1.

  • Message1 - QoS2
  • Message2 - Qos1
  • Message3 - QoS0

The library also provides an ability to force strict message ordering for all values of QoS using the cc_mqtt311_client_publish_set_ordering() function.

printf("ERROR: Publish ordering configuration failed with ec=%d\n", ec);
}
CC_Mqtt311ErrorCode cc_mqtt311_client_publish_set_ordering(CC_Mqtt311ClientHandle handle, CC_Mqtt311PublishOrdering ordering)
Configure the ordering of the published messages.
@ CC_Mqtt311PublishOrdering_Full
Preserve strict order between all messages.
Definition: common.h:93

The current configuration can be retrieved using cc_mqtt311_client_publish_get_ordering() function. The default publish ordering is CC_Mqtt311PublishOrdering_SameQos.

When a strict message ordering for all the messages is enabled (by setting CC_Mqtt311PublishOrdering_Full), The PUBLISH message is postponed if any of the statements below are true:

  • There are other postponed PUBLISH messages of previously issued "publish" operations.
  • There are previously issued and incomplete "publish" operation of higher QoS value.

The rules above allow sending the same as well as increasing QoS messages in parallel. For example, if all the publishes below issued together in the specified order, the Message11 and Message12 will be sent, while Message13 and Message14 are postponed until the delivery of the Message12 is complete.

  • Message11 - QoS1
  • Message12 - Qos2
  • Message13 - QoS0
  • Message14 - QoS2

To inquire whether the PUBLISH message was actually sent, the cc_mqtt311_client_publish_was_initiated() function can be used. If the function returns false, the "publish" operation can be safely cancelled without any possible side effects.

Simplifying the "Publish" Operation Preparation.

In many use cases the "publish" operation can be quite simple with a lot of defaults. To simplify the sequence of the operation preparation and handling of errors, the library provides wrapper function that can be used:

For example:

// Assign default values to the configuration
// Update values
config.m_topic = "some/topic";
config.m_data = ...;
...
ec = cc_mqtt311_client_publish(client, &config, &my_publish_complete_cb, data);
printf("ERROR: Failed to send publish request with ec=%d\n", ec);
...
}
CC_Mqtt311ErrorCode cc_mqtt311_client_publish(CC_Mqtt311ClientHandle handle, const CC_Mqtt311PublishConfig *config, CC_Mqtt311PublishCompleteCb cb, void *cbData)
Prepare, configure, and send "publish" request in one go.

Note that the wrapper function does NOT expose the handle returned by the cc_mqtt311_client_publish_prepare(). It means that it's not possible to cancel the "publish" operation before its completion or identify the publish operation by the reported handle when the completion callback is invoked.

Receiving Messages

Right after the successful "connect" operation, the library starts expecting the arrival of the new messages and reports it via the registered callback. By default the library monitors the topics the client application subscribed to and does not report "rogue" messages from the broker.

Note that only topics themselves are monitored, and not the requested maximal QoS values. It means that if application requested maximal QoS1 for a particular subscription, but the broker sends message using the QoS2, the message is still going to be reported to the application.

However, if the broker is trusted to do the right thing, i.e. fully comply to the specification, it is possible to enable / disable the incoming topics check using the cc_mqtt311_client_set_verify_incoming_msg_subscribed() for performance reasons.

CC_Mqtt311ErrorCode cc_mqtt311_client_set_verify_incoming_msg_subscribed(CC_Mqtt311ClientHandle handle, bool enabled)
Control verification of the incoming message being correctly subscribed.

To retrieve the current configuration use the cc_mqtt311_client_get_verify_incoming_msg_subscribed() function.

WARNING: When the incoming message subscription verification is disabled, the library does NOT track any new subscription requests, which can result in dropping legit messages and not reporting them to the application after the subscription verification is re-enabled later.

Similarly, the library also by default verifies the incoming topic format, that it doesn't contain wildcard characters. To enable / disable such verification use the cc_mqtt311_client_set_verify_incoming_topic_enabled() function.

CC_Mqtt311ErrorCode cc_mqtt311_client_set_verify_incoming_topic_enabled(CC_Mqtt311ClientHandle handle, bool enabled)
Control incoming topic format verification.

To retrieve the current configuration use the cc_mqtt311_client_get_verify_incoming_topic_enabled() function.

To prioritize the in-order reception of the messages, the message report callback is invoked immediately on reception of the QoS2 PUBLISH message. Just like it is shown as "Method B" in the "Figure 4.3" of the MQTT v3.1.1 specification.

The QoS2 publish operation initiated by the broker requires exchange of multiple messages between the broker and the client. When the library responds with the PUBREC message, the broker is expected to send PUBREL back. The library uses the Default Response Timeout configuration to measure the time frame during which it allows the reception of the corresponding PUBREL message. If the latter doesn't arrive in time, the inner state of the message reception gets discarded resulting in the future rejection of the relevant PUBREL from the broker (if such arrives). Depending on case whether the PUBREC message was actually received by the broker and how the broker is implemented one of the following scenarios is possible:

  • The broker has NOT received the PUBREC and will resend its PUBLISH resulting in the duplicate delivery of the message.
  • The broker has received the PUBREC and according to MQTT v3.1.1 specification it is not allowed to perform PUBLISH again. Th broker might decide to either drop its message delivery state (best case scenario) or treat it as protocol error and disconnect the client.

With all said above it might be necessary to increase the response timeout for slow networks.

Unsolicited Broker Disconnection

When broker disconnection is detected all the incomplete asynchronous operations (except publish) will be terminated with the an appropriate status report. The incomplete publish operations will be preserved due to the following spec clause:

When a Client reconnects with CleanSession set to 0, both the Client and Server MUST re-send any
unacknowledged PUBLISH Packets (where QoS > 0) and PUBREL Packets using their original Packet
Identifiers [MQTT-4.4.0-1].

The unsolicited broker disconnection can happen in one of the following scenarios:

Keep Alive Timeout

When there was no message from the broker for the "keep alive" timeout (configured during the connect operation) and the broker doesn't respond to the PING message. In such case the library responds in the following way:

Detecting Protocol Error

In case the broker doesn't fully comply with the MQTT v3.1.1 specification or there is some unexpected data corruption the library responds in the following way:

With all said above it means that if application receives CC_Mqtt311AsyncOpStatus_ProtocolError or CC_Mqtt311AsyncOpStatus_BrokerDisconnected status in the operation callback, then the application is expected to wait for the disconnection report callback which will follow.

When the disconnection report callback is called the application is expected to go through the following steps:

  • Close network connection.
  • Re-establish network connection to the broker.
  • Perform the "connect" operation from within a next event loop iteration.

In case the client re-connects to the broker and the broker reports "clean session", then all the incomplete publish operations will be terminated with the CC_Mqtt311AsyncOpStatus_Aborted status.

Network Disconnection

In addition to the Unsolicited Broker Disconnection the network connection can be suddenly terminated. Such network disconnection is usually detected by the failing read or write operations on I/O socket. When the application detects such network disconnection, it is expected to report it to the library using cc_mqtt311_client_notify_network_disconnected() function.

// Report network disconnected
void cc_mqtt311_client_notify_network_disconnected(CC_Mqtt311ClientHandle handle)
Report network disconnected.

When the network disconnection is reported, the similar workflow to one described in the Unsolicited Broker Disconnection section above is performed, excluding the invocation of the broker disconnection report callback. When the incomplete operations get terminated the CC_Mqtt311AsyncOpStatus_BrokerDisconnected status is reported.

When the Unsolicited Broker Disconnection is detected prior to the detection of the network disconnection itself and the broker disconnection report callback is invoked, there is no need to report the network disconnection to the library.

Inquiry about current network disconnection status can be done using the cc_mqtt311_client_is_network_disconnected() function.

bool disconnected = cc_mqtt311_client_is_network_disconnected(client);
bool cc_mqtt311_client_is_network_disconnected(CC_Mqtt311ClientHandle handle)
Check current network disconnected status.

Note that when the new "connect" op is prepared, the library will assume that the network connection is re-established and the subsequent call to the cc_mqtt311_client_is_network_disconnected() function will return false.

Thread Safety

In general the library is NOT thread safe. To support multi-threading the application is expected to use appropriate locking mechanisms before calling relevant API functions. However, if each thread operates on a separate allocated client, then the locking is required only for the client allocation logic.

Debug Build

The client library uses COMMS_ASSERT() macro to check some internal pre- and post-conditions. It is a bug if the assertion fails, please report if encountered. By default it is like standard assert() but allows overriding the default failure behavour, which can be more suitable for bare-metal systems. Please refer to the documentation for details.