MQTT server#
Overview#
This tutorial demonstrates how Mongoose Library can be used to implement a simple MQTT 3.1.1 server that is capable of:
- Handling CONNECT requests from clients. User / password are not verified
- Handling SUBSCRIBE requests
- Handling PUBLISH request
This implementation, therefore, implements only a subset of MQTT specification, but it is enough for preforming some basic tasks, and is easy to extend.
A full source code for this tutorial is at https://github.com/cesanta/mongoose/tree/master/tutorials/mqtt/mqtt-server
Global variables#
First we declare global variables to make it easy to change tunable parameters. In our case it is one - a listening address:
Also, we need to keep a list of subscriptions. For each SUBSCRIBE request, we'd like to store which connection requested it, which QoS, and which topic:
Signal handler#
It is a best practice to register a signal handler. Our signal handler function just sets a global variable which will be checked in the event loop:
Main function#
The main()
function is usual - we initialise an event manager,
create a listening connection, and fall into an event loop until a termination
signal is received. Then we cleanup and exit:
Event handler#
The event handler function is the meat of the server implementation.
It handles two events: MG_EV_CLOSE
and MG_EV_MQTT_CMD
.
The code that handles MG_EV_MQTT_CMD
looks up which specific command
has been sent:
Handling MQTT CONNECT#
We perform some sanity check for the received data, check that the client is using MQTT version 3, and send a successful CONNACK response back.A CONNECT command sent by a client may contain extra settings - like user, password, will message, "clean session" flag, client ID, and others. We silently ignore them.
Handling MQTT SUBSCRIBE#
When SUBSCRIBE command is received, it may contain multiple topic names with
QoS for each. We iterate over all topics using
mg_mqtt_next_sub API function, and
for each requested topic, create a subscription descriptor and add it to the
global list of subscription, s_subs
. Next we send a SUBACK acknowledgement
with a number of topics we've handled.
Handling MQTT PUBLISH#
Hadling PUBLISH requests is easy - we iterate a list of subscriptions, compare topic names, and send the message to the subscribed connection if topics match. We use mg_globmatch() as a matching function, which handles wildcards.
Handling disconnection#
When a client disconnects, we iterate over the global subscription list, and remove all subscriptions installed by that client.
Testing#
Let's test our server. Follow the Build Tools tutorial to setup your development environment. Start a terminal in the project directory; clone the Mongoose Library repo, and execute:
make clean all
Make sure you have mosquitto client setup on your workstartion. Start another
terminal and subscribe to three topics: a/#
, b/+/test
and c/foo
~$ mosquitto_sub -v -h localhost -p 1883 -t 'a/#' -t 'b/+/test' -t c/foo
Start another terminal. Let's publish messages! First, send a message
to a topic d/
. We are not subscribed to that topic so should not see
anything in the "subscribed" terminal:
$ mosquitto_pub -h localhost -p 1883 -t d/ -m hello
Now let's send to a topic c/foo
, which we should catch:
$ mosquitto_pub -h localhost -p 1883 -t c/foo -m hello
Also, we should catch a message on topic b/123/test
:
$ mosquitto_pub -h localhost -p 1883 -t b/123/test -m hello
And of course on topic a/what/ever
:
$ mosquitto_pub -h localhost -p 1883 -t a/what/ever -m hello