Skip to content

Commit e1caa8e

Browse files
authored
Merge pull request #457 from dgarske/broker
Embedded MQTT v3.11 / v5.0 broker
2 parents dcea52b + beef18f commit e1caa8e

17 files changed

Lines changed: 4794 additions & 42 deletions

File tree

.github/workflows/broker-check.yml

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
name: Broker Build Test
2+
3+
on:
4+
push:
5+
branches: [ 'master', 'main', 'release/**' ]
6+
pull_request:
7+
branches: [ '*' ]
8+
9+
jobs:
10+
build:
11+
12+
runs-on: ubuntu-22.04
13+
timeout-minutes: 5
14+
15+
strategy:
16+
fail-fast: false
17+
matrix:
18+
include:
19+
- name: "Broker default (dynamic alloc)"
20+
cflags: ""
21+
wolfmqtt_opts: "--enable-broker"
22+
- name: "Broker static memory"
23+
cflags: "-DWOLFMQTT_STATIC_MEMORY"
24+
wolfmqtt_opts: "--enable-broker"
25+
- name: "Broker with TLS"
26+
cflags: ""
27+
wolfmqtt_opts: "--enable-broker --enable-tls"
28+
- name: "Broker with TLS (static memory)"
29+
cflags: "-DWOLFMQTT_STATIC_MEMORY"
30+
wolfmqtt_opts: "--enable-broker --enable-tls"
31+
- name: "Broker no logging"
32+
cflags: ""
33+
wolfmqtt_opts: "--enable-broker --disable-broker-log"
34+
- name: "Broker minimal (no log, no retained, no will, no wildcards, no auth)"
35+
cflags: ""
36+
wolfmqtt_opts: "--enable-broker --disable-broker-log --disable-broker-retained --disable-broker-will --disable-broker-wildcards --disable-broker-auth"
37+
38+
steps:
39+
- name: Install dependencies
40+
run: |
41+
export DEBIAN_FRONTEND=noninteractive
42+
sudo apt-get update
43+
sudo apt-get install -y mosquitto-clients
44+
45+
- uses: actions/checkout@master
46+
with:
47+
repository: wolfssl/wolfssl
48+
path: wolfssl
49+
- name: wolfssl autogen
50+
working-directory: ./wolfssl
51+
run: ./autogen.sh
52+
- name: wolfssl configure
53+
working-directory: ./wolfssl
54+
run: ./configure --enable-enckeys
55+
- name: wolfssl make
56+
working-directory: ./wolfssl
57+
run: make
58+
- name: wolfssl make install
59+
working-directory: ./wolfssl
60+
run: sudo make install
61+
62+
- uses: actions/checkout@master
63+
- name: wolfmqtt autogen
64+
run: ./autogen.sh
65+
66+
- name: "wolfmqtt configure (${{ matrix.name }})"
67+
run: ./configure ${{ matrix.wolfmqtt_opts }} CFLAGS="${{ matrix.cflags }}"
68+
- name: wolfmqtt make
69+
run: make
70+
71+
- name: "Run broker tests (${{ matrix.name }})"
72+
run: ./scripts/broker.test
73+
74+
- name: Show logs on failure
75+
if: failure() || cancelled()
76+
run: |
77+
ls -la /tmp/tmp.* 2>/dev/null || true
78+
for d in /tmp/tmp.*; do
79+
if [ -d "$d" ]; then
80+
echo "=== Logs in $d ==="
81+
cat "$d"/*.log 2>/dev/null || true
82+
fi
83+
done

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ lt*.m4
2525
*.cache
2626
config.*
2727
configure
28+
configure~
2829
libtool
2930
libtool.m4
3031
*.log
@@ -123,3 +124,4 @@ examples/websocket/websocket_client
123124
# Never exclude Espressif config.h files
124125
!/IDE/Espressif/**/config.h
125126

127+
src/mqtt_broker

CMakeLists.txt

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,49 @@ if(ENABLE_WEBSOCKET)
184184
endif()
185185
endif()
186186

187+
# Broker
188+
add_option(WOLFMQTT_BROKER
189+
"Enable lightweight broker support"
190+
"no" "yes;no")
191+
if (WOLFMQTT_BROKER)
192+
list(APPEND WOLFMQTT_DEFINITIONS "-DWOLFMQTT_BROKER")
193+
194+
add_option(WOLFMQTT_BROKER_RETAINED
195+
"Enable broker retained message support"
196+
"yes" "yes;no")
197+
if (NOT WOLFMQTT_BROKER_RETAINED)
198+
list(APPEND WOLFMQTT_DEFINITIONS "-DWOLFMQTT_BROKER_NO_RETAINED")
199+
endif()
200+
201+
add_option(WOLFMQTT_BROKER_WILL
202+
"Enable broker Last Will and Testament support"
203+
"yes" "yes;no")
204+
if (NOT WOLFMQTT_BROKER_WILL)
205+
list(APPEND WOLFMQTT_DEFINITIONS "-DWOLFMQTT_BROKER_NO_WILL")
206+
endif()
207+
208+
add_option(WOLFMQTT_BROKER_WILDCARDS
209+
"Enable broker wildcard topic matching"
210+
"yes" "yes;no")
211+
if (NOT WOLFMQTT_BROKER_WILDCARDS)
212+
list(APPEND WOLFMQTT_DEFINITIONS "-DWOLFMQTT_BROKER_NO_WILDCARDS")
213+
endif()
214+
215+
add_option(WOLFMQTT_BROKER_AUTH
216+
"Enable broker username/password authentication"
217+
"yes" "yes;no")
218+
if (NOT WOLFMQTT_BROKER_AUTH)
219+
list(APPEND WOLFMQTT_DEFINITIONS "-DWOLFMQTT_BROKER_NO_AUTH")
220+
endif()
221+
222+
add_option(WOLFMQTT_BROKER_LOG
223+
"Enable broker logging"
224+
"yes" "yes;no")
225+
if (NOT WOLFMQTT_BROKER_LOG)
226+
list(APPEND WOLFMQTT_DEFINITIONS "-DWOLFMQTT_BROKER_NO_LOG")
227+
endif()
228+
endif()
229+
187230
# Note: not adding stress option to cmake build as of yet. stress is for
188231
# testing only and requires the scripts/ dir to be useful.
189232

@@ -286,6 +329,14 @@ if (WOLFMQTT_EXAMPLES)
286329
add_mqtt_example(mqtt-sub pub-sub/mqtt-sub.c)
287330
endif()
288331

332+
if (WOLFMQTT_BROKER)
333+
add_executable(mqtt_broker src/mqtt_broker.c)
334+
target_link_libraries(mqtt_broker wolfmqtt)
335+
target_include_directories(mqtt_broker PRIVATE
336+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
337+
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)
338+
endif()
339+
289340
####################################################
290341
# Installation
291342
####################################################
@@ -326,4 +377,5 @@ message("\tExamples: ${ENABLE_EXAMPLES}")
326377
message("\tFirmware Examples: ${ENABLE_FIRMWARE_EXAMPLES}")
327378
message("\tMultithread: ${ENABLE_MULTITHREAD}")
328379
message("\tCurl: ${ENABLE_CURL}")
380+
message("\tBroker: ${WOLFMQTT_BROKER}")
329381
message("-----------------------------------------------")

README.md

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ We setup an AWS IoT endpoint and testing device certificate for testing. The AWS
185185

186186
### Watson IoT Example
187187
This example enables the wolfMQTT client to connect to the IBM Watson Internet of Things (WIOT) Platform. The WIOT Platform has a limited test broker called "Quickstart" that allows non-secure connections to exercise the component. The example is located in `/examples/wiot/`. Works with MQTT v5 support enabled.
188-
**NOTE** The WIOT Platform will be disabled DEC2023. The demo may still be useful for users of IBM Watson IOT.
188+
**NOTE** The WIOT Platform will be disabled DEC2023. The demo may still be useful for users of IBM Watson IOT.
189189

190190
### MQTT-SN Example
191191
The Sensor Network client implements the MQTT-SN protocol for low-bandwidth networks. There are several differences from MQTT, including the ability to use a two byte Topic ID instead the full topic during subscribe and publish. The SN client requires an MQTT-SN gateway. The gateway acts as an intermediary between the SN clients and the broker. This client was tested with the Eclipse Paho MQTT-SN Gateway, which connects by default to the public Eclipse broker, much like our wolfMQTT Client example. The address of the gateway must be configured as the host. The example is located in `/examples/sn-client/`.
@@ -262,7 +262,7 @@ The initially supported version with full specification support for all features
262262

263263
### MQTT v5.0 Specification Support
264264

265-
The wolfMQTT client supports connecting to v5 enabled brokers when configured with the `--enable-v5` option.
265+
The wolfMQTT client supports connecting to v5 enabled brokers when configured with the `--enable-v5` option.
266266
The following v5.0 specification features are supported by the wolfMQTT client:
267267
* AUTH packet
268268
* User properties
@@ -413,6 +413,78 @@ Note: When stress is enabled, the Multithread Example becomes localhost only
413413
and will not connect to remote servers. Additionally the test `scripts/stress.test`
414414
is added to `make check`, and all other tests are disabled.
415415

416+
## Broker
417+
418+
wolfMQTT includes a lightweight MQTT broker implementation suitable for embedded and resource-constrained environments. It supports both MQTT v3.1.1 and v5.0 clients, with optional TLS via wolfSSL.
419+
420+
### Features
421+
422+
* QoS 0, QoS 1, and QoS 2 publish/subscribe (full QoS 2 flow with PUBREC/PUBREL/PUBCOMP)
423+
* Retained messages
424+
* Last Will and Testament (LWT) with v5 Will Delay Interval
425+
* Wildcard subscriptions (`+` and `#`)
426+
* Username/password authentication
427+
* TLS support (requires wolfSSL with `--enable-tls`)
428+
* Clean session handling with subscription persistence
429+
* Keep-alive monitoring with automatic client disconnect
430+
* Unique client ID enforcement (existing session takeover)
431+
* Static memory mode (`WOLFMQTT_STATIC_MEMORY`) for zero-malloc operation
432+
433+
### Building
434+
435+
With autotools:
436+
437+
```
438+
./configure --enable-broker
439+
make
440+
```
441+
442+
With CMake:
443+
444+
```
445+
cmake .. -DWOLFMQTT_BROKER=yes
446+
cmake --build .
447+
```
448+
449+
### Running
450+
451+
```
452+
./src/mqtt_broker -p 1883
453+
```
454+
455+
For TLS:
456+
457+
```
458+
./src/mqtt_broker -p 8883 -t -A ca-cert.pem -K server-key.pem -c server-cert.pem
459+
```
460+
461+
Run `./src/mqtt_broker -h` to see all available options.
462+
463+
### Feature Build Options
464+
465+
All broker features are enabled by default. Individual features can be disabled at build time to reduce code and memory footprint on constrained platforms.
466+
467+
| Feature | Autotools | CMake | Define |
468+
|---|---|---|---|
469+
| Retained messages | `--disable-broker-retained` | `-DWOLFMQTT_BROKER_RETAINED=no` | `WOLFMQTT_BROKER_NO_RETAINED` |
470+
| Last Will and Testament | `--disable-broker-will` | `-DWOLFMQTT_BROKER_WILL=no` | `WOLFMQTT_BROKER_NO_WILL` |
471+
| Wildcard subscriptions | `--disable-broker-wildcards` | `-DWOLFMQTT_BROKER_WILDCARDS=no` | `WOLFMQTT_BROKER_NO_WILDCARDS` |
472+
| Authentication | `--disable-broker-auth` | `-DWOLFMQTT_BROKER_AUTH=no` | `WOLFMQTT_BROKER_NO_AUTH` |
473+
474+
### Static Memory Mode
475+
476+
When built with `WOLFMQTT_STATIC_MEMORY`, the broker uses fixed-size arrays instead of dynamic allocation. Buffer sizes and limits can be tuned via compile-time macros:
477+
478+
| Macro | Default | Description |
479+
|---|---|---|
480+
| `BROKER_MAX_CLIENTS` | 8 | Maximum concurrent client connections |
481+
| `BROKER_MAX_SUBS` | 32 | Maximum total subscriptions |
482+
| `BROKER_MAX_RETAINED` | 16 | Maximum retained messages |
483+
| `BROKER_RX_BUF_SZ` | 4096 | Per-client receive buffer size |
484+
| `BROKER_TX_BUF_SZ` | 4096 | Per-client transmit buffer size |
485+
| `BROKER_MAX_PAYLOAD_LEN` | 4096 | Maximum retained message payload |
486+
| `BROKER_MAX_WILL_PAYLOAD_LEN` | 256 | Maximum LWT payload size |
487+
416488
## WebSocket Support
417489

418490
wolfMQTT supports MQTT over WebSockets, allowing clients to connect to MQTT brokers through WebSocket endpoints. This is useful for environments where traditional MQTT ports might be blocked or when integrating with web applications.
@@ -544,11 +616,11 @@ You can test the wolfMQTT client against public brokers supporting websockets:
544616
* Mosquitto unencrypted
545617

546618
`./examples/websocket/websocket_client -h test.mosquitto.org -p8080`
547-
619+
548620
* Mosquitto secure websocket
549621

550622
`./examples/websocket/websocket_client -h test.mosquitto.org -p8081 -t`
551-
623+
552624
* HiveMQ unencrypted
553625

554626
`./examples/websocket/websocket_client -h broker.hivemq.com -p8000`

configure.ac

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ then
304304
[ ENABLED_PROPCB=$enableval ],
305305
[ ENABLED_PROPCB=yes ]
306306
)
307-
307+
308308
if test "x$ENABLED_PROPCB" = "xyes"
309309
then
310310
AM_CFLAGS="$AM_CFLAGS -DWOLFMQTT_PROPERTY_CB"
@@ -405,6 +405,70 @@ then
405405
[AC_MSG_ERROR([libwebsockets not found. Install libwebsockets or use --disable-websocket])])
406406
fi
407407

408+
# Broker
409+
AC_ARG_ENABLE([broker],
410+
[AS_HELP_STRING([--enable-broker],[Enable lightweight broker support (default: disabled)])],
411+
[ ENABLED_BROKER=$enableval ],
412+
[ ENABLED_BROKER=no ]
413+
)
414+
415+
if test "x$ENABLED_BROKER" = "xyes"
416+
then
417+
AM_CFLAGS="$AM_CFLAGS -DWOLFMQTT_BROKER"
418+
fi
419+
420+
# Broker feature toggles (only relevant when --enable-broker)
421+
AC_ARG_ENABLE([broker-retained],
422+
[AS_HELP_STRING([--disable-broker-retained],[Disable broker retained message support])],
423+
[ ENABLED_BROKER_RETAINED=$enableval ],
424+
[ ENABLED_BROKER_RETAINED=yes ]
425+
)
426+
if test "x$ENABLED_BROKER_RETAINED" = "xno"
427+
then
428+
AM_CFLAGS="$AM_CFLAGS -DWOLFMQTT_BROKER_NO_RETAINED"
429+
fi
430+
431+
AC_ARG_ENABLE([broker-will],
432+
[AS_HELP_STRING([--disable-broker-will],[Disable broker Last Will and Testament support])],
433+
[ ENABLED_BROKER_WILL=$enableval ],
434+
[ ENABLED_BROKER_WILL=yes ]
435+
)
436+
if test "x$ENABLED_BROKER_WILL" = "xno"
437+
then
438+
AM_CFLAGS="$AM_CFLAGS -DWOLFMQTT_BROKER_NO_WILL"
439+
fi
440+
441+
AC_ARG_ENABLE([broker-wildcards],
442+
[AS_HELP_STRING([--disable-broker-wildcards],[Disable broker wildcard subscription support])],
443+
[ ENABLED_BROKER_WILDCARDS=$enableval ],
444+
[ ENABLED_BROKER_WILDCARDS=yes ]
445+
)
446+
if test "x$ENABLED_BROKER_WILDCARDS" = "xno"
447+
then
448+
AM_CFLAGS="$AM_CFLAGS -DWOLFMQTT_BROKER_NO_WILDCARDS"
449+
fi
450+
451+
AC_ARG_ENABLE([broker-auth],
452+
[AS_HELP_STRING([--disable-broker-auth],[Disable broker username/password authentication])],
453+
[ ENABLED_BROKER_AUTH=$enableval ],
454+
[ ENABLED_BROKER_AUTH=yes ]
455+
)
456+
if test "x$ENABLED_BROKER_AUTH" = "xno"
457+
then
458+
AM_CFLAGS="$AM_CFLAGS -DWOLFMQTT_BROKER_NO_AUTH"
459+
fi
460+
461+
AC_ARG_ENABLE([broker-log],
462+
[AS_HELP_STRING([--disable-broker-log],[Disable broker logging])],
463+
[ ENABLED_BROKER_LOG=$enableval ],
464+
[ ENABLED_BROKER_LOG=yes ]
465+
)
466+
if test "x$ENABLED_BROKER_LOG" = "xno"
467+
then
468+
AM_CFLAGS="$AM_CFLAGS -DWOLFMQTT_BROKER_NO_LOG"
469+
fi
470+
471+
408472
AM_CONDITIONAL([HAVE_LIBWOLFSSL], [test "x$ENABLED_TLS" = "xyes"])
409473
AM_CONDITIONAL([HAVE_LIBCURL], [test "x$ENABLED_CURL" = "xyes"])
410474
AM_CONDITIONAL([BUILD_STRESS], [test "x$ENABLED_STRESS" != "xno"])
@@ -415,6 +479,8 @@ AM_CONDITIONAL([BUILD_MQTT5], [test "x$ENABLED_MQTTV50" = "xyes"])
415479
AM_CONDITIONAL([BUILD_NONBLOCK], [test "x$ENABLED_NONBLOCK" = "xyes"])
416480
AM_CONDITIONAL([BUILD_MULTITHREAD], [test "x$ENABLED_MULTITHREAD" = "xyes"])
417481
AM_CONDITIONAL([BUILD_WEBSOCKET], [test "x$ENABLED_WEBSOCKET" = "xyes"])
482+
AM_CONDITIONAL([BUILD_BROKER], [test "x$ENABLED_BROKER" = "xyes"])
483+
418484

419485

420486
# HARDEN FLAGS
@@ -542,3 +608,4 @@ echo " * CURL: $ENABLED_CURL"
542608
echo " * Multi-thread: $ENABLED_MULTITHREAD"
543609
echo " * Stress: $ENABLED_STRESS"
544610
echo " * WebSocket: $ENABLED_WEBSOCKET"
611+
echo " * Broker: $ENABLED_BROKER"

0 commit comments

Comments
 (0)