|
| 1 | +# wolfMQTT Broker |
| 2 | + |
| 3 | +wolfMQTT includes a lightweight MQTT broker suitable for embedded and resource-constrained environments. It serves both MQTT v3.1.1 and v5.0 clients, with optional TLS via wolfSSL, optional WebSocket transport, and optional encrypted persistence. The broker uses non-blocking sockets driven by a single `select()` loop, so it runs without threads. |
| 4 | + |
| 5 | +## Features |
| 6 | + |
| 7 | +* QoS 0, QoS 1, and QoS 2 publish/subscribe (full QoS 2 flow with PUBREC/PUBREL/PUBCOMP) |
| 8 | +* Retained messages |
| 9 | +* Last Will and Testament (LWT), including v5 Will Delay Interval |
| 10 | +* Wildcard subscriptions (`+` and `#`) |
| 11 | +* Username/password authentication |
| 12 | +* MQTT v5 ordering and Receive Maximum (per-subscriber inflight shaping) |
| 13 | +* TLS support (requires wolfSSL with `--enable-tls`) |
| 14 | +* WebSocket / secure WebSocket transport (requires libwebsockets; see the WebSocket section of the main [README.md](README.md)) |
| 15 | +* Clean session handling with subscription persistence |
| 16 | +* Keep-alive monitoring with automatic client disconnect |
| 17 | +* Unique client ID enforcement (existing session takeover) |
| 18 | +* Optional on-disk persistence of sessions, subscriptions, retained messages, and offline queues, with optional AES-GCM encryption-at-rest |
| 19 | +* Static memory mode (`WOLFMQTT_STATIC_MEMORY`) for zero-malloc operation |
| 20 | + |
| 21 | +## Quick start |
| 22 | + |
| 23 | +With autotools: |
| 24 | + |
| 25 | +```sh |
| 26 | +./configure --enable-broker |
| 27 | +make |
| 28 | +./src/mqtt_broker -p 1883 |
| 29 | +``` |
| 30 | + |
| 31 | +With CMake: |
| 32 | + |
| 33 | +```sh |
| 34 | +cmake .. -DWOLFMQTT_BROKER=yes |
| 35 | +cmake --build . |
| 36 | +``` |
| 37 | + |
| 38 | +For TLS: |
| 39 | + |
| 40 | +```sh |
| 41 | +./configure --enable-broker --enable-tls |
| 42 | +make |
| 43 | +./src/mqtt_broker -p 8883 -t -A ca-cert.pem -K server-key.pem -c server-cert.pem |
| 44 | +``` |
| 45 | + |
| 46 | +Run `./src/mqtt_broker -h` to see the options compiled into your build. |
| 47 | + |
| 48 | +## Command-line options |
| 49 | + |
| 50 | +``` |
| 51 | +usage: mqtt_broker [-p port] [-v level] [-u user] [-P pass] |
| 52 | + [-t] [-s port] [-V ver] [-c cert] [-K key] [-A ca] |
| 53 | + [-w port] [-D dir] [-E source] |
| 54 | +``` |
| 55 | + |
| 56 | +| Option | Available when | Description | |
| 57 | +|---|---|---| |
| 58 | +| `-p <port>` | always | Plain (non-TLS) port (default: 1883) | |
| 59 | +| `-v <level>` | always | Log level: 1=error, 2=info (default), 3=debug | |
| 60 | +| `-u <user>` | auth build | Username for authentication | |
| 61 | +| `-P <pass>` | auth build | Password for authentication | |
| 62 | +| `-t` | TLS build | Enable the TLS listener | |
| 63 | +| `-s <port>` | TLS build | TLS port (default: 8883) | |
| 64 | +| `-V <ver>` | TLS build | TLS version: 12=TLS 1.2, 13=TLS 1.3 (default: auto) | |
| 65 | +| `-c <file>` | TLS build | Server certificate file (PEM) | |
| 66 | +| `-K <file>` | TLS build | Server private key file (PEM) | |
| 67 | +| `-A <file>` | TLS build | CA certificate for mutual TLS (PEM) | |
| 68 | +| `-w <port>` | WebSocket build | WebSocket listen port (enables WebSocket) | |
| 69 | +| `-D <dir>` | persist build | Persistent storage directory (enables persistence; default `/var/lib/wolfmqtt`) | |
| 70 | +| `-E <source>` | encrypt + dev-key build | Encryption key source. Only `dev` is recognized, selecting the development hard-coded key. NOT FOR PRODUCTION. | |
| 71 | + |
| 72 | +## Build options |
| 73 | + |
| 74 | +All broker features are enabled by default and can be disabled at build time to reduce code and memory footprint on constrained platforms. |
| 75 | + |
| 76 | +| Feature | Autotools | CMake | Define | |
| 77 | +|---|---|---|---| |
| 78 | +| Broker support | `--enable-broker` | `-DWOLFMQTT_BROKER=yes` | `WOLFMQTT_BROKER` | |
| 79 | +| Retained messages | `--disable-broker-retained` | `-DWOLFMQTT_BROKER_RETAINED=no` | `WOLFMQTT_BROKER_NO_RETAINED` | |
| 80 | +| Last Will and Testament | `--disable-broker-will` | `-DWOLFMQTT_BROKER_WILL=no` | `WOLFMQTT_BROKER_NO_WILL` | |
| 81 | +| Wildcard subscriptions | `--disable-broker-wildcards` | `-DWOLFMQTT_BROKER_WILDCARDS=no` | `WOLFMQTT_BROKER_NO_WILDCARDS` | |
| 82 | +| Authentication | `--disable-broker-auth` | `-DWOLFMQTT_BROKER_AUTH=no` | `WOLFMQTT_BROKER_NO_AUTH` | |
| 83 | +| Logging | `--disable-broker-log` | `-DWOLFMQTT_BROKER_LOG=no` | `WOLFMQTT_BROKER_NO_LOG` | |
| 84 | +| Plain-text listener | `--disable-broker-insecure` | `-DWOLFMQTT_BROKER_INSECURE=no` | `WOLFMQTT_BROKER_NO_INSECURE` | |
| 85 | + |
| 86 | +The maximum QoS the broker negotiates is capped by `--enable-max-qos=<0,1,2>` (default 2). Setting it to 1 or 0 compiles out the QoS 2 state machine and shrinks the broker. |
| 87 | + |
| 88 | +## Static memory tuning |
| 89 | + |
| 90 | +When built with `WOLFMQTT_STATIC_MEMORY`, the broker uses fixed-size arrays instead of dynamic allocation. The limits below can be overridden via CFLAGS at build time. |
| 91 | + |
| 92 | +| Macro | Default | Description | |
| 93 | +|---|---|---| |
| 94 | +| `BROKER_MAX_CLIENTS` | 8 | Maximum concurrent client connections | |
| 95 | +| `BROKER_MAX_SUBS` | 32 | Maximum total subscriptions across all clients | |
| 96 | +| `BROKER_MAX_RETAINED` | 16 | Maximum retained messages | |
| 97 | +| `BROKER_MAX_CLIENT_ID_LEN` | 64 | Maximum client ID length | |
| 98 | +| `BROKER_MAX_USERNAME_LEN` | 64 | Maximum username length | |
| 99 | +| `BROKER_MAX_PASSWORD_LEN` | 64 | Maximum password length | |
| 100 | +| `BROKER_MAX_FILTER_LEN` | 128 | Maximum subscription filter length | |
| 101 | +| `BROKER_MAX_TOPIC_LEN` | 128 | Maximum topic name length | |
| 102 | +| `BROKER_MAX_PAYLOAD_LEN` | 4096 | Maximum retained message payload | |
| 103 | +| `BROKER_MAX_WILL_PAYLOAD_LEN` | 256 | Maximum LWT payload | |
| 104 | +| `BROKER_MAX_PENDING_WILLS` | 4 | Maximum queued pending wills | |
| 105 | +| `BROKER_MAX_INBOUND_QOS2` | 16 | Concurrent inbound QoS 2 packet IDs per client | |
| 106 | +| `BROKER_RX_BUF_SZ` | 4096 | Per-client receive buffer size | |
| 107 | +| `BROKER_TX_BUF_SZ` | 4096 | Per-client transmit buffer size | |
| 108 | +| `BROKER_TIMEOUT_MS` | 1000 | `select()` timeout | |
| 109 | +| `BROKER_LISTEN_BACKLOG` | 128 | Listen queue depth | |
| 110 | + |
| 111 | +With dynamic memory the per-subscriber inflight window is derived at runtime, bounded by `BROKER_MIN_INFLIGHT_PER_SUB` (default 8) and `BROKER_MAX_INFLIGHT_PER_SUB`. Define `BROKER_MAX_INFLIGHT_PER_SUB=1` to force strict serial delivery (one inflight QoS 1/2 message per subscriber). |
| 112 | + |
| 113 | +## Persistence |
| 114 | + |
| 115 | +Build with `--enable-broker-persist` to persist sessions, subscriptions, retained messages, and offline queues across restarts. The persistence layer is hook-based: a default POSIX backend stores records as files under the directory given with `-D` (default `/var/lib/wolfmqtt`). Embedded targets can supply their own storage backend through `MqttBroker_SetPersistHooks()`. |
| 116 | + |
| 117 | +| Macro | Default | Description | |
| 118 | +|---|---|---| |
| 119 | +| `BROKER_MAX_PERSIST_SESSIONS` | 64 | Persistent sessions retained across restarts | |
| 120 | +| `BROKER_MAX_OFFLINE_MSGS_PER_SUB` | 32 | Offline queue depth per session | |
| 121 | +| `WOLFMQTT_BROKER_PERSIST_SCHEMA_VER` | 3 | On-disk record schema version | |
| 122 | + |
| 123 | +### Encryption at rest |
| 124 | + |
| 125 | +Add `--enable-broker-persist-encrypt` (requires `--enable-broker-persist`) to wrap persisted records with wolfCrypt AES-GCM. The key is provided by a `derive_key` callback that real deployments install via `MqttBroker_SetPersistHooks()` before starting the broker. |
| 126 | + |
| 127 | +For development and CI only, the CLI can link a fixed-pattern `derive_key` hook so the AES-GCM round-trip can be exercised without external key management. This is NOT a configure option -- define the macro through CFLAGS: |
| 128 | + |
| 129 | +```sh |
| 130 | +CFLAGS="-DWOLFMQTT_BROKER_PERSIST_ENCRYPT_DEV_KEY" \ |
| 131 | + ./configure --enable-broker --enable-broker-persist --enable-broker-persist-encrypt |
| 132 | +make |
| 133 | +./src/mqtt_broker -p 1883 -D ./state -E dev |
| 134 | +``` |
| 135 | + |
| 136 | +The dev key is a trivially-recoverable hard-coded pattern. Never define `WOLFMQTT_BROKER_PERSIST_ENCRYPT_DEV_KEY` in a production build, and never pass `-E dev` in production -- doing so substitutes the fixed key for real key management. Production builds omit the macro entirely, so the `-E` option and the dev hook are not present in the binary. |
| 137 | + |
| 138 | +## Testing |
| 139 | + |
| 140 | +The repository ships an end-to-end broker test harness: |
| 141 | + |
| 142 | +```sh |
| 143 | +./scripts/broker.test |
| 144 | +``` |
| 145 | + |
| 146 | +It builds the client examples (`examples/pub-sub/mqtt-pub`, `examples/pub-sub/mqtt-sub`) and `mosquitto`-based checks against the wolfMQTT broker, covering QoS flows, retained messages, wildcards, persistence round-trips, and AES-GCM encryption (when the dev-key hook is linked). Tests that depend on features not present in the current build are reported as `SKIP`. |
| 147 | + |
| 148 | +The CONNECT-handler unit test (`tests/test_broker_connect`) is part of `make check` and exercises the broker packet path with a mock network layer. |
| 149 | + |
| 150 | +## Limitations |
| 151 | + |
| 152 | +The wolfMQTT broker targets embedded and edge use cases. It is intentionally smaller in scope than full-featured server brokers such as Mosquitto or EMQX: there is no clustering, no bridging, no plugin/ACL framework, and no dynamic configuration reload. For large-scale or feature-rich deployments use a dedicated server broker; for a small, auditable, optionally-TLS broker that runs without threads or a heap, wolfMQTT is a good fit. |
0 commit comments