AWS IoT Device SDK C: MQTT
MQTT 3.1.1 client library
Return to main page ↑
Design

Architecture behind the MQTT library.

Asynchronous and synchronous operations

This library provides both asynchronous and synchronous MQTT operations. Asynchronous operation functions end with Async, and their synchronous variants end with Sync.

For example, IotMqtt_PublishAsync and IotMqtt_PublishSync are the respective asynchronous and synchronous MQTT PUBLISH functions. The CONNECT and DISCONNECT operations only have synchronous functions.

Asynchronous functions return immediately to the calling thread after allocating appropriate resources. The application thread can then continue executing while the MQTT operation is processed in the background. Once the MQTT operation is complete, the MQTT library will invoke a callback function provided by the application. The function IotMqtt_Wait can be used to wait for an asynchronous operation's completion. It can also be used to cancel asynchronous operations if passed a timeout of 0.

Synchronous functions block their calling thread until the MQTT operation is complete. Synchronous functions take a timeout parameter; if the operation does not complete within this timeout, the function returns IOT_MQTT_TIMEOUT and cancels the operation. Synchronous operations do not use a callback; they return a value that represents the result of the operation to the calling thread.

Operation diagram

The following diagram shows the workflow of an operation.

MQTT relies on the task pool library to process asynchronous MQTT operations in the background. Each MQTT API function allocates the required resources, then schedules a background task to send the MQTT packet and receive the server's response. Incoming responses are received through a network receive callback, which schedules another job to process the response.

Synchronous operations are implemented as a call to the corresponding asynchronous operation. The synchronous function then waits on a semaphore until it receives a notification of completion. The workflow of a synchronous operation is otherwise identical to an asynchronous operation.

Some operations, such as QoS 1 PUBLISHes, may be retried. See IotMqttPublishInfo_t for a description of the retry strategy.

mqtt_design_typicaloperation.png

Subscriptions

This section provides a description of how the library handles subscriptions.

MQTT subscriptions are added with IotMqtt_SubscribeAsync or IotMqtt_SubscribeSync; subscriptions are removed with IotMqtt_UnsubscribeSync or IotMqtt_UnsubscribeAsync. Subscriptions are associated with a callback function that will be invoked by the library every time a message matching the associated topic filter is received. For example, if a connection has subscriptions for # (which matches everything) and test, and a message is received on test, the callback functions for both # and test will be invoked. Callbacks are invoked from the context of a background task pool threads. Because incoming messages are asynchronous (may arrive at any time), subscription callbacks are also asynchronous.

This library supports the use of MQTT persistent sessions. Persistent sessions cause the MQTT server to store subscriptions and undelivered messages. When re-establishing a persistent session, the client should set IotMqttConnectInfo_t::pPreviousSubscriptions and IotMqttConnectInfo_t::previousSubscriptionCount to restore a list of sessions that were present in the persistent session. Setting these members does not send an MQTT SUBSCRIBE packet to the server, so they may only be used with topics that are active on the server.

Periodic keep-alive

This section provides a description of the workflow of periodic keep-alive.

The MQTT standard specifies a keep-alive mechanism to detect half-open or otherwise unusable network connections. An MQTT client will send periodic ping requests (PINGREQ) to the server if the connection is idle. The MQTT server must respond to ping requests with a ping response (PINGRESP).

The standard does not specify how long the server has to respond to a ping request, noting only a "reasonable amount of time". In this library, the amount of time a server has to respond to a ping request is set with IOT_MQTT_RESPONSE_WAIT_MS.

The PINGREQ is allocated with the MQTT connection when it is created. A failure flag is also set to 0. For simplicity, the diagram below only shows the portions of MQTT CONNECT relevant for keep-alive.

Once MQTT CONNECT returns to the application, the keep-alive is processed entirely through background tasks. The period of the keep-alive is controlled with IotMqttConnectInfo_t::keepAliveSeconds (represented by keepAliveSec in the diagram below). Every keepAliveSec, the following code is run by a background task in the task pool.

  1. If another MQTT packet was sent within the keep-alive period, don't send the PINGREQ and reschedule for the next keep-alive period. For simplicity, this is not shown in the diagram below.
  2. The failure flag is set to 1.
  3. A PINGREQ is sent to the server.
  4. If the connection is alive, the server will respond with a PINGRESP. When the client receives the PINGRESP, it sets failure to 0.
  5. After IOT_MQTT_RESPONSE_WAIT_MS, the client checks the failure flag. If failure=0, then a PINGRESP was received and the next PINGREQ is scheduled. Otherwise, if failure=1, then no PINGRESP was received and the connection terminates.