MQTT Client Library Encyclopedia – wolfMQTT

Written by David Garske

Category: MQTT MQTT Client Library

Published: December 21, 2015




Short info

wolfMQTT
Language C
License GPL v2
Website https://www.wolfssl.com/products/wolfmqtt/
API Style Blocking or Non-Blocking

Description

The wolfMQTT library is a client implementation of the MQTT written in C for embedded use. It supports SSL/TLS via the wolfSSL library. It was built from the ground up to be multi-platform, space conscience and extensible. It supports all Packet Types, all Quality of Service (QoS) levels 0-2 and supports SSL/TLS using the wolfSSL library. This implementation supports the MQTT v3.1.1, MQTT v5.0 and MQTT-SN v1.2 specifications.

The wolfMQTT library was created in October 2015 due to many requests from wolfSSL customers for us to have an MQTT client library with TLS support.

Features

Feature
MQTT 3.1 nok
MQTT 3.1.1 ok
MQTT 5.0 ok
MQTT-SN v1.2 ok
LWT ok
Automatic Reconnect nok
Feature
QoS 0 ok
QoS 1 ok
QoS 2 ok
Authentication ok
Throttling nok
SSL/TLS ok

Additional Features

  • Built from scratch by wolfSSL engineers
  • Supports MQTT v3.1.1 specification
  • Support for MQTT v5.0
  • Support for MQTT Sensor Network (MQTT-SN) v1.2
  • Supports all client side packet types and protocol options
  • QoS Levels 0-2 (guarenteed delivery)
  • Supports plain TCP or TLS (via the wolfSSL library)
  • Single threaded model and single message callback
  • Written in Native C89 with portability/compatibility in mind
  • Space conscience design (Compiled size is about 3.6KB)
  • User manual with build instructions, example overview and API documentation
  • Example MQTT client implementations
  • Network interface is abstracted via callbacks for extensibility
  • Packet parsing encoding/decoding structured for custom use
  • Minimal external dependencies (strlen, memcpy, memset) (overridable macros)
  • Detailed error checking/handling
  • Doxygen style inline documentation
  • Less than 1200 lines of well structured C code
  • Tested on multiple variants of MQTT broker servers, QoS levels 0-2 with/without TLS.
  • Tested on Linux, Mac OS X and Freescale Kinetis K64.
  • Inherits wolfSSL library features such as lightweight TLS using ChaCha20/Poly1305 AEAD, small size and portability.
  • Open source (GPLv2)
  • Support for FreeRTOS+TCP
  • Includes an example Arduino IDE project
  • IBM Watson IoT example with an IBM developer recipe.


Usage

Installation

The most recent version can be downloaded from the GitHub website here:

Either click the “Download ZIP” button or use the command
git clone git@github.com:wolfSSL/wolfMQTT.git

When building on Linux, *BSD, OS X, Solaris, or other *nix-like systems, use the autoconf system. To build wolfMQTT you only need to run three commands:

1
2
3
./configure
make
make install

When building on Windows there is a Visual Studio 2015 solution included.

For additional help see the wolfMQTT User Manual:

Connect

1
2
3
int MqttClient_Connect(
	MqttClient *client,
	MqttConnect *connect);

Encodes and sends the MQTT Connect packet and waits for the Connect Acknowledgement packet. This is a blocking function that will wait for MqttNet.read data.

Return Values:

1
2
See MqttPacketResponseCodes in /wolfmqtt/mqtt_types.h
MQTT_CODE_SUCCESS - Success

Parameters:

1
2
client - Pointer to MqttClient structure already initialized using MqttClient_Init.
connect - Pointer to MqttConnect structure populated with connection options.

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <wolfmqtt/mqtt_client.h>;
int rc = 0;
MqttClient client;
MqttConnect connect;
MqttMessage lwt_msg;

/* Define connect parameters */
connect.keep_alive_sec = keep_alive_sec;
connect.clean_session = clean_session;
connect.client_id = client_id;

/* Last will and testament sent by broker to subscribers of topic when broker connection is lost */
memset(&lwt_msg, 0, sizeof(lwt_msg));
connect.lwt_msg = &lwt_msg;
connect.enable_lwt = enable_lwt;
if (enable_lwt) {
lwt_msg.qos = qos;
lwt_msg.retain = 0;
lwt_msg.topic_name = "lwttopic";
lwt_msg.message = (byte*)DEFAULT_CLIENT_ID;
lwt_msg.message_len = strlen(DEFAULT_CLIENT_ID);
}
/* Optional authentication */
connect.username = username;
connect.password = password;

/* Send Connect and wait for Connect Ack */
rc = MqttClient_Connect(&client, &connect);
if (rc != MQTT_CODE_SUCCESS) {
   printf("MQTT Connect: %s (%d)\n", MqttClient_ReturnCodeToString(rc), rc);
}

Connect with LWT

See Connect example above.

Connect with Username / Password

See Connect example above.

Publish

1
2
3
int MqttClient_Publish(
        MqttClient *client, 
        MqttPublish *publish);

Encodes and sends the MQTT Publish packet and waits for the Publish response (if QoS > 0). This is a blocking function that will wait for MqttNet.read data. If QoS level = 1 then will wait for PUBLISH_ACK. If QoS level = 2 then will wait for PUBLISH_REC then send PUBLISH_REL and wait for PUBLISH_COMP.

Return Values:

1
2
See enum MqttPacketResponseCodes in /wolfmqtt/mqtt_types.h
MQTT_CODE_SUCCESS - success

Parameters:

1
2
client - Pointer to MqttClient structure already initialized using MqttClient_Init.
publish - Pointer to MqttPublish structure initialized with message data. Note: MqttPublish and MqttMessage are same structure.

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#include <wolfmqtt/mqtt_client.h>
#define TEST_MESSAGE            "test" /* NULL */

int rc = 0;
MqttPublish publish;
word16 packet_id = 0;

/* Publish Topic */
publish.retain = 0;
publish.qos = qos;
publish.duplicate = 0;
publish.topic_name = "pubtopic";
publish.packet_id = ++packet_id;
publish.message = (byte*)TEST_MESSAGE;
publish.message_len = strlen(TEST_MESSAGE);
rc = MqttClient_Publish(&client, &publish);
if (rc != MQTT_CODE_SUCCESS) {
	printf("MQTT Publish: %s (%d)\n", MqttClient_ReturnCodeToString(rc), rc);
}

Publish a retained message

See publish example. Set publish.retain = 1.

Subscribe

1
2
3
4
int MqttClient_Subscribe(
        MqttClient *client, 
        MqttSubscribe *subscribe);
        

Encodes and sends the MQTT Subscribe packet and waits for the Subscribe Acknowledgement packet. This is a blocking function that will wait for MqttNet.read data

Return Values: See

1
enum MqttPacketResponseCodes 
in
1
/wolfmqtt/mqtt_types.h
1
MQTT_CODE_SUCCESS - Success

Parameters:

1
2
client - Pointer to MqttClient structure already initialized using MqttClient_Init.
subscribe - Pointer to MqttSubscribe structure initialized with subscription topic list and desired QoS.

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <wolfmqtt/mqtt_client.h>
#define TEST_TOPIC_COUNT        2

int rc = 0;
MqttSubscribe subscribe;
MqttTopic topics[TEST_TOPIC_COUNT], *topic;
word16 packet_id = 0;

/* Build list of topics */
topics[0].topic_filter = "subtopic1";
topics[0].qos = qos;
topics[1].topic_filter = "subtopic2";
topics[1].qos = qos;

/* Subscribe Topic */
subscribe.packet_id = ++packet_id;
subscribe.topic_count = TEST_TOPIC_COUNT;
subscribe.topics = topics;
rc = MqttClient_Subscribe(&client, &subscribe);

if (rc == MQTT_CODE_SUCCESS) {
 	for (i = 0; i < subscribe.topic_count; i++) {
		topic = &subscribe.topics[i];
		printf("  Topic %s, Qos %u, Return Code %u\n",
		topic->topic_filter, topic->qos, topic->return_code);
	}
}
else {
	printf("MQTT Subscribe: %s (%d)\n", MqttClient_ReturnCodeToString(rc), rc);
}

Unsubscribe

1
2
3
4
int MqttClient_Unsubscribe(
        MqttClient *client, 
        MqttUnsubscribe *unsubscribe);
        

Encodes and sends the MQTT Unsubscribe packet and waits for the Unsubscribe Acknowledgement packet. This is a blocking function that will wait for MqttNet.read data.

Return Values: See

1
enum MqttPacketResponseCodes
in
1
/wolfmqtt/mqtt_types.h
1
`MQTT_CODE_SUCCESS - Success

Parameters:

1
2
client - Pointer to MqttClient structure already initialized using MqttClient_Init.
unsubscribe - Pointer to MqttUnsubscribe structure initialized with topic list.

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include <wolfmqtt/mqtt_client.h>
#define TEST_TOPIC_COUNT        2

int rc = 0;
MqttUnsubscribe unsubscribe;
MqttTopic topics[TEST_TOPIC_COUNT], *topic;
word16 packet_id = 0;

/* Build list of topics */
topics[0].topic_filter = "subtopic1";
topics[1].topic_filter = "subtopic2";

/* Unsubscribe Topics */
unsubscribe.packet_id = ++packet_id;
unsubscribe.topic_count = TEST_TOPIC_COUNT;
unsubscribe.topics = topics;
rc = MqttClient_Unsubscribe(&client, &unsubscribe);
if (rc != MQTT_CODE_SUCCESS) {
	printf("MQTT Unsubscribe: %s (%d)\n", MqttClient_ReturnCodeToString(rc), rc);
}

Disconnect

1
2
int MqttClient_Disconnect(
        MqttClient *client);

Encodes and sends the MQTT Disconnect packet (no response).

Return Values: See enum

1
MqttPacketResponseCodes
in
1
2
/wolfmqtt/mqtt_types.h
MQTT_CODE_SUCCESS - Success

Parameters:

1
client - Pointer to MqttClient structure already initialized using MqttClient_Init.

Example:

1
2
3
4
5
6
7
#include <wolfmqtt/mqtt_client.h>

int rc = MqttClient_Disconnect(&client);
if (rc != MQTT_CODE_SUCCESS) {
	printf("MQTT Disconnect: %s (%d)\n", MqttClient_ReturnCodeToString(rc),
rc);
}

Using SSL / TLS

1
2
3
4
5
/* Connect to broker */
rc = MqttClient_NetConnect(&client, host, port,
	DEFAULT_CON_TIMEOUT_MS, use_tls, mqttclient_tls_cb);
printf("MQTT Socket Connect: %s (%d)\n",
	MqttClient_ReturnCodeToString(rc), rc);   

Full example application

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include <wolfmqtt/mqtt_client.h>

int rc;
MqttNet net;
MqttClient client;

/* Start example MQTT Client */
printf("MQTT Client\n");

/* Initialize Network */
rc = MqttClientNet_Init(&net);
printf("MQTT Net Init: %s (%d)\n",
    MqttClient_ReturnCodeToString(rc), rc);

/* Initialize MqttClient structure */
tx_buf = malloc(MAX_BUFFER_SIZE);
rx_buf = malloc(MAX_BUFFER_SIZE);
rc = MqttClient_Init(&client, &net, mqttclient_message_cb,
    tx_buf, MAX_BUFFER_SIZE, rx_buf, MAX_BUFFER_SIZE,
    DEFAULT_CMD_TIMEOUT_MS);
printf("MQTT Init: %s (%d)\n",
    MqttClient_ReturnCodeToString(rc), rc);

/* Connect to broker */
rc = MqttClient_NetConnect(&client, host, port,
    DEFAULT_CON_TIMEOUT_MS, use_tls, mqttclient_tls_cb);
printf("MQTT Socket Connect: %s (%d)\n",
    MqttClient_ReturnCodeToString(rc), rc);

if (rc == 0) {
    /* Define connect parameters */
    MqttConnect connect;
    MqttMessage lwt_msg;
    connect.keep_alive_sec = keep_alive_sec;
    connect.clean_session = clean_session;
    connect.client_id = client_id;
    /* Last will and testament sent by broker to subscribers
        of topic when broker connection is lost */
    memset(&lwt_msg, 0, sizeof(lwt_msg));
    connect.lwt_msg = &lwt_msg;
    connect.enable_lwt = enable_lwt;
    if (enable_lwt) {
        lwt_msg.qos = qos;
        lwt_msg.retain = 0;
        lwt_msg.topic_name = "lwttopic";
        lwt_msg.buffer = (byte*)DEFAULT_CLIENT_ID;
        lwt_msg.total_len = (word16)strlen(DEFAULT_CLIENT_ID);
    }
    /* Optional authentication */
    connect.username = username;
    connect.password = password;

    /* Send Connect and wait for Connect Ack */
    rc = MqttClient_Connect(&client, &connect);
    printf("MQTT Connect: %s (%d)\n",
        MqttClient_ReturnCodeToString(rc), rc);
    if (rc == MQTT_CODE_SUCCESS) {
        MqttSubscribe subscribe;
        MqttUnsubscribe unsubscribe;
        MqttTopic topics[TEST_TOPIC_COUNT], *topic;
        MqttPublish publish;
        int i;

        /* Build list of topics */
        topics[0].topic_filter = "subtopic1";
        topics[0].qos = qos;
        topics[1].topic_filter = "subtopic2";
        topics[1].qos = qos;

        /* Validate Connect Ack info */
        printf("MQTT Connect Ack: Return Code %u, Session Present %d\n",
            connect.ack.return_code,
            (connect.ack.flags & MQTT_CONNECT_ACK_FLAG_SESSION_PRESENT) ?
                1 : 0
        );

        /* Subscribe Topic */
        subscribe.packet_id = mqttclient_get_packetid();
        subscribe.topic_count = TEST_TOPIC_COUNT;
        subscribe.topics = topics;
        rc = MqttClient_Subscribe(&client, &subscribe);
        printf("MQTT Subscribe: %s (%d)\n",
            MqttClient_ReturnCodeToString(rc), rc);
        for (i = 0; i < subscribe.topic_count; i++) {
            topic = &subscribe.topics[i];
            printf("  Topic %s, Qos %u, Return Code %u\n",
                topic->topic_filter, topic->qos, topic->return_code);
        }

        /* Publish Topic */
        publish.retain = 0;
        publish.qos = qos;
        publish.duplicate = 0;
        publish.topic_name = "pubtopic";
        publish.packet_id = mqttclient_get_packetid();
        publish.buffer = (byte*)TEST_MESSAGE;
        publish.total_len = (word16)strlen(TEST_MESSAGE);
        rc = MqttClient_Publish(&client, &publish);
        printf("MQTT Publish: Topic %s, %s (%d)\n",
            publish.topic_name, MqttClient_ReturnCodeToString(rc), rc);

        /* Read Loop */
        printf("MQTT Waiting for message...\n");
        while (mStopRead == 0) {
            /* Try and read packet */
            rc = MqttClient_WaitMessage(&client, DEFAULT_CMD_TIMEOUT_MS);
            if (rc != MQTT_CODE_SUCCESS && rc != MQTT_CODE_ERROR_TIMEOUT) {
                /* There was an error */
                printf("MQTT Message Wait: %s (%d)\n",
                    MqttClient_ReturnCodeToString(rc), rc);
                break;
            }
        }

        /* Unsubscribe Topics */
        unsubscribe.packet_id = mqttclient_get_packetid();
        unsubscribe.topic_count = TEST_TOPIC_COUNT;
        unsubscribe.topics = topics;
        rc = MqttClient_Unsubscribe(&client, &unsubscribe);
        printf("MQTT Unsubscribe: %s (%d)\n",
            MqttClient_ReturnCodeToString(rc), rc);

        rc = MqttClient_Disconnect(&client);
        printf("MQTT Disconnect: %s (%d)\n",
            MqttClient_ReturnCodeToString(rc), rc);
    }

    rc = MqttClient_NetDisconnect(&client);
    printf("MQTT Socket Disconnect: %s (%d)\n",
         MqttClient_ReturnCodeToString(rc), rc);
}

/* Free resources */
if (tx_buf) free(tx_buf);
if (rx_buf) free(rx_buf);

/* Cleanup network */
rc = MqttClientNet_DeInit(&net);
printf("MQTT Net DeInit: %s (%d)\n",
    MqttClient_ReturnCodeToString(rc), rc);

About David Garske

Thanks for this guest blog

• David Garske works for wolfSSL and has been in IoT embedded software development since 2005. wolfSSL, founded in 2004, is an Open Source Internet security company with products including the wolfSSL embedded SSL/TLS library, wolfCrypt crypto engine, SSL Inspection, and wolfMQTT.

contact us

<  MQTT Client Library Encyclopedia – Paho Android Service   |   HiveMQ 3.0.3 Released   >