`TLS_PEER_VERIFY` and `TLS_DTLS_ROLE` options accept specific values, yet no symbols were defined for them. In result, magic numbers were used in several places, making the code less readable. Fix this issue, by adding the missing symbols to the `socket.h` header, and using them in places where related socket options are set. Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
174 lines
5.9 KiB
ReStructuredText
174 lines
5.9 KiB
ReStructuredText
.. _mqtt_socket_interface:
|
|
|
|
MQTT
|
|
####
|
|
|
|
.. contents::
|
|
:local:
|
|
:depth: 2
|
|
|
|
Overview
|
|
********
|
|
|
|
MQTT (Message Queuing Telemetry Transport) is an application layer protocol
|
|
which works on top of the TCP/IP stack. It is a lightweight
|
|
publish/subscribe messaging transport for machine-to-machine communication.
|
|
For more information about the protocol itself, see http://mqtt.org/.
|
|
|
|
Zephyr provides an MQTT client library built on top of BSD sockets API. The
|
|
library is configurable at a per-client basis, with support for MQTT versions
|
|
3.1.0 and 3.1.1. The Zephyr MQTT implementation can be used with either plain
|
|
sockets communicating over TCP, or with secure sockets communicating over
|
|
TLS. See :ref:`bsd_sockets_interface` for more information about Zephyr sockets.
|
|
|
|
MQTT clients require an MQTT server to connect to. Such a server, called an MQTT Broker,
|
|
is responsible for managing client subscriptions and distributing messages
|
|
published by clients. There are many implementations of MQTT brokers, one of them
|
|
being Eclipse Mosquitto. See https://mosquitto.org/ for more information about
|
|
the Eclipse Mosquitto project.
|
|
|
|
Sample usage
|
|
************
|
|
|
|
To create an MQTT client, a client context structure and buffers need to be
|
|
defined:
|
|
|
|
.. code-block:: c
|
|
|
|
/* Buffers for MQTT client. */
|
|
static u8_t rx_buffer[256];
|
|
static u8_t tx_buffer[256];
|
|
|
|
/* MQTT client context */
|
|
static struct mqtt_client client_ctx;
|
|
|
|
Multiple MQTT client instances can be created in the application and managed
|
|
independently. Additionally, a structure for MQTT Broker address information
|
|
is needed. This structure must be accessible throughout the lifespan
|
|
of the MQTT client and can be shared among MQTT clients:
|
|
|
|
.. code-block:: c
|
|
|
|
/* MQTT Broker address information. */
|
|
static struct sockaddr_storage broker;
|
|
|
|
An MQTT client library will notify MQTT events to the application through a
|
|
callback function created to handle respective events:
|
|
|
|
.. code-block:: c
|
|
|
|
void mqtt_evt_handler(struct mqtt_client *client,
|
|
const struct mqtt_evt *evt)
|
|
{
|
|
switch (evt->type) {
|
|
/* Handle events here. */
|
|
}
|
|
}
|
|
|
|
For a list of possible events, see :ref:`mqtt_api_reference`.
|
|
|
|
The client context structure needs to be initialized and set up before it can be
|
|
used. An example configuration for TCP transport is shown below:
|
|
|
|
.. code-block:: c
|
|
|
|
mqtt_client_init(&client_ctx);
|
|
|
|
/* MQTT client configuration */
|
|
client_ctx.broker = &broker;
|
|
client_ctx.evt_cb = mqtt_evt_handler;
|
|
client_ctx.client_id.utf8 = (u8_t *)"zephyr_mqtt_client";
|
|
client_ctx.client_id.size = sizeof("zephyr_mqtt_client") - 1;
|
|
client_ctx.password = NULL;
|
|
client_ctx.user_name = NULL;
|
|
client_ctx.protocol_version = MQTT_VERSION_3_1_1;
|
|
client_ctx.transport.type = MQTT_TRANSPORT_NON_SECURE;
|
|
|
|
/* MQTT buffers configuration */
|
|
client_ctx.rx_buf = rx_buffer;
|
|
client_ctx.rx_buf_size = sizeof(rx_buffer);
|
|
client_ctx.tx_buf = tx_buffer;
|
|
client_ctx.tx_buf_size = sizeof(tx_buffer);
|
|
|
|
After the configuration is set up, the MQTT client can connect to the MQTT broker.
|
|
Call the ``mqtt_connect`` function, which will create the appropriate socket,
|
|
establish a TCP/TLS connection, and send an ``MQTT CONNECT`` message.
|
|
When notified, the application should call the ``mqtt_input`` function to process
|
|
the response received. Note, that ``mqtt_input`` is a non-blocking function,
|
|
therefore the application should use socket ``poll`` to wait for the response.
|
|
If the connection was successful, ``MQTT_EVT_CONNACK`` will be notified to the
|
|
application through the callback function.
|
|
|
|
.. code-block:: c
|
|
|
|
rc = mqtt_connect(&client_ctx);
|
|
if (rc != 0) {
|
|
return rc;
|
|
}
|
|
|
|
fds[0].fd = client_ctx.transport.tcp.sock;
|
|
fds[0].events = ZSOCK_POLLIN;
|
|
poll(fds, 1, K_MSEC(5000));
|
|
|
|
mqtt_input(&client_ctx);
|
|
|
|
if (!connected) {
|
|
mqtt_abort(&client_ctx);
|
|
}
|
|
|
|
In the above code snippet, the MQTT callback function should set the ``connected``
|
|
flag upon a successful connection. If the connection fails at the MQTT level
|
|
or a timeout occurs, the connection will be aborted, and the underlying socket
|
|
closed.
|
|
|
|
After the connection is established, an application needs to call ``mqtt_input``
|
|
and ``mqtt_live`` functions periodically to process incoming data and upkeep
|
|
the connection. If an MQTT message is received, an MQTT callback function will
|
|
be called and an appropriate event notified.
|
|
|
|
The connection can be closed by calling the ``mqtt_disconnect`` function.
|
|
|
|
Zephyr provides sample code utilizing the MQTT client API. See
|
|
:ref:`mqtt-publisher-sample` for more information.
|
|
|
|
Using MQTT with TLS
|
|
*******************
|
|
|
|
The Zephyr MQTT library can be used with TLS transport for secure communication
|
|
by selecting a secure transport type (``MQTT_TRANSPORT_SECURE``) and some
|
|
additional configuration information:
|
|
|
|
.. code-block:: c
|
|
|
|
client_ctx.transport.type = MQTT_TRANSPORT_SECURE;
|
|
|
|
struct mqtt_sec_config *tls_config = &client_ctx.transport.tls.config;
|
|
|
|
tls_config->peer_verify = TLS_PEER_VERIFY_REQUIRED;
|
|
tls_config->cipher_list = NULL;
|
|
tls_config->sec_tag_list = m_sec_tags;
|
|
tls_config->sec_tag_count = ARRAY_SIZE(m_sec_tags);
|
|
tls_config->hostname = MQTT_BROKER_HOSTNAME;
|
|
|
|
In this sample code, the ``m_sec_tags`` array holds a list of tags, referencing TLS
|
|
credentials that the MQTT library should use for authentication. We do not specify
|
|
``cipher_list``, to allow the use of all cipher suites available in the system.
|
|
We set ``hostname`` field to broker hostname, which is required for server
|
|
authentication. Finally, we enforce peer certificate verification by setting
|
|
the ``peer_verify`` field.
|
|
|
|
Note, that TLS credentials referenced by the ``m_sec_tags`` array must be
|
|
registered in the system first. For more information on how to do that, refer
|
|
to :ref:`secure sockets documentation <secure_sockets_interface>`.
|
|
|
|
An example of how to use TLS with MQTT is also present in
|
|
:ref:`mqtt-publisher-sample`.
|
|
|
|
.. _mqtt_api_reference:
|
|
|
|
API Reference
|
|
*************
|
|
|
|
.. doxygengroup:: mqtt_socket
|
|
:project: Zephyr
|