Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

mqtt_broker

Full MQTT v3.1.1 + v5.0 broker. The protocol engine (C_PROT_MQTT2) is an adaptation of the Mosquitto logic onto Yuneta GClasses, with sessions, subscriptions, retained messages and per-client queues persisted on TreeDB / TimeRanger2.

Architecture

The yuno (main.c) composes two services:

C_AUTHZ (service "authz")        <- authentication / authorization
C_MQTT_BROKER (default service)  <- broker: sessions, subscriptions, queues, retained
    per connection:
      C_CHANNEL > C_PROT_MQTT2   <- one MQTT protocol FSM per client connection

mqtt_broker is a citizen yuno: it does not open its own listening socket. MQTT client connections arrive through the node’s public gateway and are delivered to the broker’s __input_side__ as channels; each channel runs a C_PROT_MQTT2 instance. The same C_PROT_MQTT2 gclass also works as an MQTT client (it carries client-side attrs like mqtt_client_id, mqtt_protocol, will/keepalive).

Protocol support

Persistence

When mqtt_persistent_db is true (default), the broker keeps state in a TreeDB (treedb_mqtt_broker, schema treedb_schema_mqtt_broker.c) plus TimeRanger2 queues:

Persistent sessions survive broker restarts; clean_session clients are transient. Set mqtt_persistent_db=0 for an in-memory-only broker.

Configuration

C_MQTT_BROKER (the mqtt_broker service):

AttributeDefaultPurpose
mqtt_persistent_dbtruePersist clients/sessions/subscriptions/queues/retained
enable_new_clientsfalseAuto-create unknown clients on connect
enable_aclfalseEnforce per-group publish/subscribe ACLs (see Authorization)
deny_subscribesJSON list of topics for which SUBSCRIBE is refused
mqtt_service(yuno_role)Service name (multi-service)
mqtt_tenant(yuno_name)Tenant id (multi-tenant)
use_internal_schematrueUse the hardcoded TreeDB schema
on_critical_error2LOG_OPT_EXIT_ZERO (exit, no auto-restart) on error

Session limits come from C_AUTHZ (e.g. Authz.max_sessions_per_user, default 4 in main.c).

Per-connection limits live on C_PROT_MQTT2 and apply to each client:

AttributeDefaultPurpose
max_qos2Max QoS allowed for connecting clients
retain_availabletrueAllow retained messages (else RETAIN clients are dropped)
max_inflight_messages20Outgoing QoS 1/2 in flight (1 = strict in-order; 0 = unlimited)
max_inflight_bytes0Byte cap on in-flight messages (0 = no limit)
max_queued_messages1000Per-client queue depth above in-flight (0 = unlimited)
max_queued_bytes0Per-client queue byte cap (0 = no limit)
message_size_limit0Max publish payload accepted (0 = MQTT max)
max_packet_size0Max MQTT packet (v5 advertises it; 0 = no limit)

Authorization (publish/subscribe ACL)

Authentication (who the client is) is handled by C_AUTHZ — see Authentication, authorisation, and TLS. Authorization of which topics a client may use is a separate, broker-local mechanism: a per-group topic ACL stored in the broker’s own TreeDB.

The model (model A — group-based ACL in the treedb):

Posture (backward-compatible, default off)

Enforcement is gated by the enable_acl attr on C_MQTT_BROKER (default false). The ACL helper allows when:

With enable_acl on and patterns authored, a topic must match one of the client’s group patterns. An unknown client (with ACL on) is denied. Both PUBLISH and SUBSCRIBE denials are logged (never silently dropped).

Wiring

The two sides enforce at the point where each one’s outcome is decided, both through the same mqtt_acl_check() helper:

Authoring an ACL

# 1. Turn enforcement on for the broker (config attr, then restart the yuno):
#      "enable_acl": true   (SDF_WR|SDF_PERSIST)

# 2. Give a group publish/subscribe patterns (broker's own treedb):
ycommand -c 'command-yuno id=<yuno> service=<mqtt_service> command=update-node \
    topic_name=client_groups \
    record={"id":"g_limited","publish_acl":["sensors/+/up"],"subscribe_acl":["sensors/+/cmd"]} \
    options={"create":1}'

# 3. Link the client to the group (clients.client_groups fkey):
ycommand -c 'command-yuno id=<yuno> service=<mqtt_service> command=link-nodes \
    hook=client_groups parent_topic=client_groups parent_id=g_limited \
    child_topic=clients child_id=<client_id>'

A group with empty publish_acl/subscribe_acl keeps allow-all for that access (useful for an unrestricted g_open group while others are constrained).

Regression test: tests/c/c_mqtt/acl (main_acl.c + c_acl.c) drives EV_MQTT_ACL_CHECK at an embedded broker — the exact path the protocol gate uses — across matching/non-matching publish and subscribe, # wildcard (incl. the parent level), the two allow-all fallbacks, and the unknown-client deny.

Commands

CommandDescription
list-channelsInput channels of connected devices
list-sessionsActive/persistent sessions
list-queuesPer-client message queues
normal-subs / shared-subsList normal / shared ($share) subscribers
flatten-subsFlattened subscriber view
list-retains / remove-retainsList / remove retained messages (note: # shown as /)
clean-queuesDrop non-persistent, not-in-use sessions and their queues
authzsAuthorization help
helpCommand help

Debugging

GClassLevelShows
C_MQTT_BROKERmessages / messages2Broker-level message flow (verbose / icon form)
C_PROT_MQTT2trafficMQTT packets in/out (no payload)
C_PROT_MQTT2traffic-payloadInclude payload bytes
C_PROT_MQTT2show-decodeDecoded packet structure
C_PROT_MQTT2messages2Simplified per-packet trace (icons)

Enable with ycommand command-yuno id=<id> service=__yuno__ command=set-gclass-trace gclass=<G> set=1 level=<L>.