CommsChampion Ecosystem MQTT v3.1.1 Client
MQTT v3.1.1 Client Library.
|
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.
The version is of the library applicable to this documentation is defined in the cc_mqtt311_client/common.h file using the following defines:
To use this MQTT v3.1.1 Client Library use the following single include statement:
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.
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.
When working with C++ it is advised to use a smart pointer with a custom deleter.
IMPORTANT: The function cc_mqtt311_client_free() must NOT be called from within a callback. Use next event loop iteration.
In order to properly function the library requires setting several callbacks.
To client application must assign a callback for the library to be able to send binary data out to the connected broker.
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.
The client application must assign a callback for the library to report discovered broker disconnection.
See also the documentation of the CC_Mqtt311BrokerDisconnectReportCb callback function definition.
See also Unsolicited Broker Disconnection below for details.
The client application must assign a callback for the library to report application level messages received from the broker.
See also the documentation of the CC_Mqtt311MessageReceivedReportCb callback function definition.
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:
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.
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.
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.
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.
See also the documentation of the CC_Mqtt311ErrorLogCb callback function definition.
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.
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.
The library abstracts away multiple MQTT v3.1.1 protocol based "operations". Every such operation has multiple stages:
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:
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.
To connect to broker use connect operation.
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.
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.
To retrieve the configured response timeout use the cc_mqtt311_client_connect_get_response_timeout() function.
To configure "connect" operation use cc_mqtt311_client_connect_config() function.
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.
To perform will configuration use the cc_mqtt311_client_connect_config_will() function.
See also documentation of the CC_Mqtt311ConnectWillConfig structure.
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.
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:
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.
While the handle returned by the cc_mqtt311_client_connect_prepare() is still valid it is possible to cancel / discard the 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.
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:
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.
At any time it is possible to check the internal state of the library of whether it's properly connected to the broker.
To intentionally disconnect from broker use disconnect operation. The unsolicited disconnection from the broker is described in ref Unsolicited Broker Disconnection section below.
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.
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.
While the handle returned by the cc_mqtt311_client_disconnect_prepare() is still valid it is possible to cancel / discard the operation.
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:
To subscribe to receive incoming messages use subscribe operation. The application can issue multiple "subscribe" operations in parallel.
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.
To retrieve the configured response timeout use the cc_mqtt311_client_subscribe_get_response_timeout() function.
Single SUBSCRIBE message can carry multiple topic subscriptions. Use separate cc_mqtt311_client_subscribe_config_topic() function invocation to configure each such subscription.
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.
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.
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.
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.
While the handle returned by the cc_mqtt311_client_subscribe_prepare() is still valid it is possible to cancel / discard the 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.
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:
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.
To unsubscribe from receiving incoming messages use unsubscribe operation. The application can issue multiple "unsubscribe" operations in parallel.
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.
To retrieve the configured response timeout use the cc_mqtt311_client_unsubscribe_get_response_timeout() function.
Single UNSUBSCRIBE message can carry multiple topic unsubscriptions. Use cc_mqtt311_client_unsubscribe_config_topic() function to configure each such unsubscription.
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.
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.
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.
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.
While the handle returned by the cc_mqtt311_client_unsubscribe_prepare() is still valid it is possible to cancel / discard the 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.
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:
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.
To publish messages to the broker use publish operation.
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.
To retrieve the configured response timeout use the cc_mqtt311_client_publish_get_response_timeout() function.
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.
To retrieve the configured resend attempts number use the cc_mqtt311_client_publish_get_resend_attempts() function.
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.
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.
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.
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.
While the handle returned by the cc_mqtt311_client_publish_prepare() is still valid it is possible to cancel / discard the 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.
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.
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.
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:
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.
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.
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:
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.
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.
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.
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:
With all said above it might be necessary to increase the response timeout for slow networks.
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:
The unsolicited broker disconnection can happen in one of the following scenarios:
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:
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:
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.
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.
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.
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.
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.
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.