From 13f42e6a58a7a4b4f0c77c02c14dbe8d8b5916cc Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 13 May 2026 09:51:47 -0700 Subject: [PATCH 1/6] Fix for MQTTv5 QoS 2 interop --- scripts/broker.test | 7 +++++-- src/mqtt_broker.c | 10 +++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/scripts/broker.test b/scripts/broker.test index 7053d408..62c51e57 100755 --- a/scripts/broker.test +++ b/scripts/broker.test @@ -603,10 +603,13 @@ if [ "$has_v5" = "yes" ]; then >"${TMP_DIR}/t12.log" 2>&1 T12_RC=$? - # 12b: Verify CONNACK server properties were received + # 12b: Verify CONNACK server properties were received. + # Type 37 = Retain Available, Type 40 = Wildcard Subscription Available. + # Maximum QoS (Type 36) is intentionally omitted per [MQTT-3.2.2.3.4] + # (absence signals QoS 2 support; emitting Max QoS=2 is a Protocol Error). T12_PROPS=yes grep -q "Property CB: Type 37" "${TMP_DIR}/t12.log" 2>/dev/null || T12_PROPS=no - grep -q "Property CB: Type 36" "${TMP_DIR}/t12.log" 2>/dev/null || T12_PROPS=no + grep -q "Property CB: Type 40" "${TMP_DIR}/t12.log" 2>/dev/null || T12_PROPS=no # 12c: v5 pub/sub with separate clients (property forwarding) start_broker diff --git a/src/mqtt_broker.c b/src/mqtt_broker.c index d09512a0..61d92b8f 100644 --- a/src/mqtt_broker.c +++ b/src/mqtt_broker.c @@ -3445,11 +3445,11 @@ static int BrokerHandle_Connect(BrokerClient* bc, int rx_len, prop->data_byte = 0; #endif } - prop = MqttProps_Add(&ack.props); - if (prop != NULL) { - prop->type = MQTT_PROP_MAX_QOS; - prop->data_byte = MQTT_QOS_2; - } + /* [MQTT-3.2.2.3.4] Maximum QoS property MUST be 0 or 1. Absence of + * the property means the server supports Maximum QoS 2, which is + * what this broker supports, so the property is omitted entirely. + * Emitting Maximum QoS = 2 is a Protocol Error and strict v5 + * clients (e.g. mosquitto) will disconnect on receipt. */ } #endif From 20cf5ddbe4dde27b4486b5359e40f9b5e0f4c812 Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 13 May 2026 15:23:43 -0700 Subject: [PATCH 2/6] Add WOLFMQTT_MAX_QOS knob; broker emits Max QoS property only when capped --- src/mqtt_broker.c | 17 ++++++++++++----- wolfmqtt/mqtt_packet.h | 11 +++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/mqtt_broker.c b/src/mqtt_broker.c index 61d92b8f..02b48dc4 100644 --- a/src/mqtt_broker.c +++ b/src/mqtt_broker.c @@ -3445,11 +3445,18 @@ static int BrokerHandle_Connect(BrokerClient* bc, int rx_len, prop->data_byte = 0; #endif } - /* [MQTT-3.2.2.3.4] Maximum QoS property MUST be 0 or 1. Absence of - * the property means the server supports Maximum QoS 2, which is - * what this broker supports, so the property is omitted entirely. - * Emitting Maximum QoS = 2 is a Protocol Error and strict v5 - * clients (e.g. mosquitto) will disconnect on receipt. */ + /* [MQTT-3.2.2.3.4] Maximum QoS property MUST be 0 or 1. Absence + * of the property signals server supports Maximum QoS 2. Emitting + * Maximum QoS = 2 is a Protocol Error and strict v5 clients will + * disconnect on receipt. Emit the property only when this build + * caps below QoS 2 via WOLFMQTT_MAX_QOS. */ + #if WOLFMQTT_MAX_QOS < 2 + prop = MqttProps_Add(&ack.props); + if (prop != NULL) { + prop->type = MQTT_PROP_MAX_QOS; + prop->data_byte = (byte)WOLFMQTT_MAX_QOS; + } + #endif } #endif diff --git a/wolfmqtt/mqtt_packet.h b/wolfmqtt/mqtt_packet.h index bc60388f..fdda8677 100644 --- a/wolfmqtt/mqtt_packet.h +++ b/wolfmqtt/mqtt_packet.h @@ -196,6 +196,17 @@ typedef enum _MqttQoS { MQTT-SN - QoS -1 allows publish without connection */ } MqttQoS; +/* Maximum QoS supported by this build. Legal values: 0, 1, 2. Default 2. + * Define in user_settings.h to compile a QoS-capped client/broker. Wired + * into broker CONNACK Maximum QoS property emission today; broader code + * gating lives on the mqtt_qos_max branch. */ +#ifndef WOLFMQTT_MAX_QOS + #define WOLFMQTT_MAX_QOS 2 +#endif +#if (WOLFMQTT_MAX_QOS < 0) || (WOLFMQTT_MAX_QOS > 2) + #error "WOLFMQTT_MAX_QOS must be 0, 1, or 2" +#endif + /* Topic */ typedef struct _MqttTopic { From 80788dc2f3c13e87d1f9038166e7209e290e8b26 Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 13 May 2026 15:33:41 -0700 Subject: [PATCH 3/6] Gate QoS-2 code paths on WOLFMQTT_MAX_QOS for capped builds Builds with -DWOLFMQTT_MAX_QOS=1 (or 0) now compile out the broker's inbound QoS-2 dedup state, BrokerHandle_PublishRel / PublishRec, and the PUBLISH_REC/REL/COMP dispatch cases; subscribe grants are capped at the build's max; PUBLISH at QoS > cap is rejected with a v5 DISCONNECT reason 0x9B (QoS Not Supported); will QoS is clamped on CONNECT. Client side clamps initial max_qos and post-CONNACK property value against the same cap so MqttPublishMsg rejects out-of-range publishes locally. Default build (WOLFMQTT_MAX_QOS=2) is unchanged: broker.test passes in full, no behavior change. Measured code-size delta on src/.libs/mqtt_broker (.text): default 48178 -> capped 45587 (-2591 bytes / -5.4%). Verified against mosquitto_pub -q 2: capped broker disconnects with "Message QoS not supported on broker, try a lower QoS." --- src/mqtt_broker.c | 60 +++++++++++++++++++++++++++++++++++++----- src/mqtt_client.c | 19 +++++++++---- wolfmqtt/mqtt_broker.h | 10 +++++-- 3 files changed, 76 insertions(+), 13 deletions(-) diff --git a/src/mqtt_broker.c b/src/mqtt_broker.c index 02b48dc4..83765572 100644 --- a/src/mqtt_broker.c +++ b/src/mqtt_broker.c @@ -1278,8 +1278,13 @@ static int BrokerNetDisconnect(void* context) /* must NOT be re-delivered to subscribers. The state is per-client and is */ /* cleared on disconnect; surviving across reconnect would require the */ /* broader session-state work (see #485/#489/#494). */ +/* */ +/* The entire QoS 2 inbound state and PUBREL/PUBREC/PUBCOMP handling is */ +/* compiled out when WOLFMQTT_MAX_QOS < 2. Subscribe-grant capping and */ +/* inbound-publish QoS rejection cover the corresponding wire paths. */ /* -------------------------------------------------------------------------- */ +#if WOLFMQTT_MAX_QOS >= 2 /* Returns 1 if packet_id is currently awaiting PUBREL, 0 otherwise. */ static int BrokerInboundQos2_Contains(BrokerClient* bc, word16 packet_id) { @@ -1425,13 +1430,16 @@ static void BrokerInboundQos2_Clear(BrokerClient* bc) bc->qos2_pending_count = 0; #endif } +#endif /* WOLFMQTT_MAX_QOS >= 2 */ static void BrokerClient_Free(BrokerClient* bc) { if (bc == NULL) { return; } +#if WOLFMQTT_MAX_QOS >= 2 BrokerInboundQos2_Clear(bc); +#endif #ifdef ENABLE_MQTT_WEBSOCKET if (bc->ws_ctx != NULL) { @@ -3264,7 +3272,12 @@ static int BrokerHandle_Connect(BrokerClient* bc, int rx_len, #endif bc->will_payload_len = wp_len; } - bc->will_qos = mc.lwt_msg->qos; + /* Clamp will QoS to this build's Maximum QoS. A v5 client that + * sent Will QoS > advertised Max QoS would already be in + * Protocol Error territory, but for v3.1.1 (no advertisement) + * we silently downgrade rather than rejecting CONNECT. */ + bc->will_qos = (mc.lwt_msg->qos > WOLFMQTT_MAX_QOS) ? + (MqttQoS)WOLFMQTT_MAX_QOS : mc.lwt_msg->qos; bc->will_retain = mc.lwt_msg->retain; bc->will_delay_sec = 0; #ifdef WOLFMQTT_V5 @@ -3524,9 +3537,10 @@ static int BrokerHandle_Subscribe(BrokerClient* bc, int rx_len, MqttQoS topic_qos = sub.topics[i].qos; MqttQoS granted_qos; - /* Cap at QoS 2 */ - if (topic_qos > MQTT_QOS_2) { - topic_qos = MQTT_QOS_2; + /* [MQTT-3.8.4-7] / [MQTT-3.9.3]: subscribe grant capped at the + * build's Maximum QoS. Default is QoS 2. */ + if (topic_qos > WOLFMQTT_MAX_QOS) { + topic_qos = (MqttQoS)WOLFMQTT_MAX_QOS; } granted_qos = topic_qos; @@ -3669,7 +3683,9 @@ static int BrokerHandle_Publish(BrokerClient* bc, int rx_len, MqttPublishResp resp; byte* payload = NULL; char* topic = NULL; +#if WOLFMQTT_MAX_QOS >= 2 int qos2_duplicate = 0; +#endif #ifdef WOLFMQTT_STATIC_MEMORY char topic_buf[BROKER_MAX_TOPIC_LEN]; #endif @@ -3691,6 +3707,26 @@ static int BrokerHandle_Publish(BrokerClient* bc, int rx_len, * MALFORMED_DATA before reaching this handler. The broker no longer * needs a per-handler scan. */ +#if WOLFMQTT_MAX_QOS < 2 + /* [MQTT-3.2.2.3.4] / [MQTT-3.3.4]: this build advertised Maximum QoS + * below 2. A client publishing at QoS > our cap is a Protocol Error; + * v5 spec wants reason 0x9B QoS Not Supported. v3 has no reason code + * field, so we just abnormally close. */ + if (pub.qos > WOLFMQTT_MAX_QOS) { + WBLOG_ERR(broker, + "broker: PUBLISH QoS %d exceeds WOLFMQTT_MAX_QOS=%d sock=%d", + pub.qos, WOLFMQTT_MAX_QOS, (int)bc->sock); + #ifdef WOLFMQTT_V5 + if (bc->protocol_level >= MQTT_CONNECT_PROTOCOL_LEVEL_5) { + (void)BrokerSend_Disconnect(bc, MQTT_REASON_QOS_NOT_SUPPORTED); + } + #endif + rc = MQTT_CODE_ERROR_MALFORMED_DATA; + goto publish_cleanup; + } +#endif /* WOLFMQTT_MAX_QOS < 2 */ + +#if WOLFMQTT_MAX_QOS >= 2 /* [MQTT-4.3.3] QoS 2 duplicate detection. If we already PUBREC'd this * packet_id and are still waiting for PUBREL, treat the inbound PUBLISH * as a retransmission: send another PUBREC but DO NOT re-deliver the @@ -3729,6 +3765,7 @@ static int BrokerHandle_Publish(BrokerClient* bc, int rx_len, } } } +#endif /* WOLFMQTT_MAX_QOS >= 2 */ /* Create null-terminated topic copy for matching/logging */ if (pub.topic_name && pub.topic_name_len > 0) { @@ -3756,7 +3793,11 @@ static int BrokerHandle_Publish(BrokerClient* bc, int rx_len, #ifdef WOLFMQTT_BROKER_RETAINED /* Handle retained messages - skipped for QoS 2 duplicates: the original * PUBLISH already updated the retained store. */ - if (!qos2_duplicate && topic != NULL && pub.retain) { + if ( + #if WOLFMQTT_MAX_QOS >= 2 + !qos2_duplicate && + #endif + topic != NULL && pub.retain) { if (pub.total_len == 0) { BrokerRetained_Delete(broker, topic); } @@ -3785,7 +3826,10 @@ static int BrokerHandle_Publish(BrokerClient* bc, int rx_len, /* Fan-out is skipped for QoS 2 duplicates: subscribers already received * the application message from the original PUBLISH ([MQTT-4.3.3]). */ - if (!qos2_duplicate && + if ( + #if WOLFMQTT_MAX_QOS >= 2 + !qos2_duplicate && + #endif topic != NULL && (payload != NULL || pub.total_len == 0)) { #ifdef WOLFMQTT_STATIC_MEMORY int i; @@ -3890,6 +3934,7 @@ static int BrokerHandle_Publish(BrokerClient* bc, int rx_len, return rc; } +#if WOLFMQTT_MAX_QOS >= 2 static int BrokerHandle_PublishRel(BrokerClient* bc, int rx_len) { int rc; @@ -3964,6 +4009,7 @@ static int BrokerHandle_PublishRec(BrokerClient* bc, int rx_len) } return rc; } +#endif /* WOLFMQTT_MAX_QOS >= 2 */ /* [MQTT-2.2.2-2] / [MQTT-3.8.1-1] etc.: a malformed packet MUST cause the * server to close the network connection. Mirrors the read-failure close @@ -4136,6 +4182,7 @@ static int BrokerClient_Process(MqttBroker* broker, BrokerClient* bc) case MQTT_PACKET_TYPE_PUBLISH_ACK: /* QoS 1 ack from subscriber - delivery complete */ break; + #if WOLFMQTT_MAX_QOS >= 2 case MQTT_PACKET_TYPE_PUBLISH_REC: { /* QoS 2 step 2: subscriber sends PUBREC, broker @@ -4162,6 +4209,7 @@ static int BrokerClient_Process(MqttBroker* broker, BrokerClient* bc) /* QoS 2 step 4: subscriber sends PUBCOMP - delivery * complete */ break; + #endif /* WOLFMQTT_MAX_QOS >= 2 */ case MQTT_PACKET_TYPE_SUBSCRIBE: { int s_rc = BrokerHandle_Subscribe(bc, rc, broker); diff --git a/src/mqtt_client.c b/src/mqtt_client.c index c536c8e3..7fd1ad53 100644 --- a/src/mqtt_client.c +++ b/src/mqtt_client.c @@ -575,10 +575,15 @@ static void Handle_ConnectAck_Props(MqttClient* client, MqttProp* props) for (prop = props; prop != NULL; prop = prop->next) { if (prop->type == MQTT_PROP_MAX_QOS) { /* MQTT v5 [3.1.2.11.6]: only 0 or 1 are legal. Clamp a - * non-conforming broker value so client-side publish guards + * non-conforming broker value, then narrow against this + * build's WOLFMQTT_MAX_QOS so client-side publish guards * remain meaningful. */ - client->max_qos = (prop->data_byte <= MQTT_QOS_1) ? + byte adv = (prop->data_byte <= MQTT_QOS_1) ? prop->data_byte : MQTT_QOS_1; + if (adv > WOLFMQTT_MAX_QOS) { + adv = (byte)WOLFMQTT_MAX_QOS; + } + client->max_qos = adv; } else if (prop->type == MQTT_PROP_RETAIN_AVAIL) { /* MQTT v5 [3.1.2.11.5]: only 0 or 1 are legal. */ @@ -1647,7 +1652,9 @@ int MqttClient_Init(MqttClient *client, MqttNet* net, client->rx_buf_len = rx_buf_len; client->cmd_timeout_ms = cmd_timeout_ms; #ifdef WOLFMQTT_V5 - client->max_qos = MQTT_QOS_2; + /* Initialize to this build's Maximum QoS. Handle_Props will narrow + * this if the server advertises a lower MQTT_PROP_MAX_QOS. */ + client->max_qos = (MqttQoS)WOLFMQTT_MAX_QOS; client->retain_avail = 1; client->protocol_level = MQTT_CONNECT_PROTOCOL_LEVEL; rc = MqttProps_Init(); @@ -1757,8 +1764,10 @@ int MqttClient_Connect(MqttClient *client, MqttConnect *mc_connect) /* Reset server-supplied session limits so stale values from a * prior broker do not leak across reconnects. An accepted CONNACK - * will repopulate these in Handle_ConnectAck_Props. */ - client->max_qos = MQTT_QOS_2; + * will repopulate these in Handle_ConnectAck_Props. Initialize to + * this build's Maximum QoS so the runtime guard in MqttPublishMsg + * caps publishes even before CONNACK is processed. */ + client->max_qos = (MqttQoS)WOLFMQTT_MAX_QOS; client->retain_avail = 1; client->packet_sz_max = 0; #endif diff --git a/wolfmqtt/mqtt_broker.h b/wolfmqtt/mqtt_broker.h index da85d242..66b62c18 100644 --- a/wolfmqtt/mqtt_broker.h +++ b/wolfmqtt/mqtt_broker.h @@ -200,13 +200,16 @@ typedef struct BrokerWsCtx { /* -------------------------------------------------------------------------- */ /* Per-client set of QoS 2 packet IDs that have been received and PUBREC'd * but not yet PUBREL'd. Used to skip the fan-out for duplicate PUBLISHes - * per [MQTT-4.3.3] / Method B. */ + * per [MQTT-4.3.3] / Method B. Gated by WOLFMQTT_MAX_QOS so capped-QoS + * broker builds drop the dedup state and PUBREC/PUBREL/PUBCOMP handlers. */ +#if WOLFMQTT_MAX_QOS >= 2 #ifndef WOLFMQTT_STATIC_MEMORY typedef struct BrokerInboundQos2 { word16 packet_id; struct BrokerInboundQos2* next; } BrokerInboundQos2; #endif +#endif /* WOLFMQTT_MAX_QOS >= 2 */ /* -------------------------------------------------------------------------- */ /* Broker client tracking */ @@ -273,13 +276,16 @@ typedef struct BrokerClient { * not yet PUBREL'd. A duplicate PUBLISH carrying one of these IDs is * acked again (PUBREC) but NOT re-fanned-out to subscribers. The * BROKER_MAX_INBOUND_QOS2 cap is enforced in both memory modes; a - * client that exceeds it is disconnected with malformed-packet error. */ + * client that exceeds it is disconnected with malformed-packet error. + * Compiled out for capped-QoS builds (WOLFMQTT_MAX_QOS < 2). */ +#if WOLFMQTT_MAX_QOS >= 2 #ifdef WOLFMQTT_STATIC_MEMORY word16 qos2_pending[BROKER_MAX_INBOUND_QOS2]; /* 0 = empty slot */ #else BrokerInboundQos2* qos2_pending; int qos2_pending_count; #endif +#endif /* WOLFMQTT_MAX_QOS >= 2 */ } BrokerClient; /* -------------------------------------------------------------------------- */ From 9c1031f6a98080fd8411cc9796f966a261ffe8e4 Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 14 May 2026 08:38:48 -0700 Subject: [PATCH 4/6] Add --enable-max-qos / WOLFMQTT_MAX_QOS option to configure.ac and CMakeLists --- CMakeLists.txt | 13 +++++++++++++ configure.ac | 21 +++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index e05aa4ea..e085a2cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -136,6 +136,19 @@ endif() add_option(WOLFMQTT_DISCB "Enable disconnect callback" "yes" "yes;no") + +# Maximum QoS supported (compile-time cap for both client and broker). +# Default 2 = full QoS support. 1 or 0 compiles out the broker's QoS 2 +# state machine and the client's initial max_qos clamp, and causes the +# broker to advertise v5 MQTT_PROP_MAX_QOS in CONNACK. +set(WOLFMQTT_MAX_QOS "2" CACHE STRING + "Maximum QoS supported by client and broker (0, 1, or 2)") +set_property(CACHE WOLFMQTT_MAX_QOS PROPERTY STRINGS "0;1;2") +if (NOT WOLFMQTT_MAX_QOS MATCHES "^[012]$") + message(SEND_ERROR + "WOLFMQTT_MAX_QOS must be 0, 1, or 2 (got: ${WOLFMQTT_MAX_QOS})") +endif() +list(APPEND WOLFMQTT_DEFINITIONS "-DWOLFMQTT_MAX_QOS=${WOLFMQTT_MAX_QOS}") if (WOLFMQTT_DISCB) list(APPEND WOLFMQTT_DEFINITIONS "-DWOLFMQTT_DISCONNECT_CB") endif() diff --git a/configure.ac b/configure.ac index ab3a8667..d56a74b5 100644 --- a/configure.ac +++ b/configure.ac @@ -323,6 +323,26 @@ then AM_CFLAGS="$AM_CFLAGS -DWOLFMQTT_DISCONNECT_CB" fi +# Maximum QoS supported (compile-time cap for both client and broker). +# Values: 0, 1, 2. Default 2 (full QoS support). Capping at 1 (or 0) +# compiles out the broker's QoS 2 state machine and the client's initial +# max_qos clamp, saves ~2.5 KB of broker .text, and makes the broker +# advertise the v5 MQTT_PROP_MAX_QOS property in CONNACK. +AC_ARG_ENABLE([max-qos], + [AS_HELP_STRING([--enable-max-qos@<:@=0|1|2@:>@], + [Maximum QoS supported by client and broker (default: 2)])], + [ ENABLED_MAX_QOS=$enableval ], + [ ENABLED_MAX_QOS=2 ] + ) +case "x$ENABLED_MAX_QOS" in + "x0"|"x1"|"x2") + AM_CFLAGS="$AM_CFLAGS -DWOLFMQTT_MAX_QOS=$ENABLED_MAX_QOS" + ;; + *) + AC_MSG_ERROR([--enable-max-qos must be 0, 1, or 2 (got: $ENABLED_MAX_QOS)]) + ;; +esac + # Multithread support AC_ARG_ENABLE([mt], [AS_HELP_STRING([--enable-mt],[Enable multiple thread support (default: disabled)])], @@ -611,6 +631,7 @@ echo " * Linker Flags: $LDFLAGS" echo " * LIB Flags: $LIB" echo " * Disconnect Callback: $ENABLED_DISCB" +echo " * Maximum QoS: $ENABLED_MAX_QOS" echo " * Error Strings: $ENABLED_ERROR_STRINGS" echo " * Enable MQTT-SN: $ENABLED_SN" echo " * Enable MQTT v5.0: $ENABLED_MQTTV50" From 969be58070bdf0d6dea10aafa8724b3b18767958 Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 14 May 2026 08:51:18 -0700 Subject: [PATCH 5/6] CI: exercise --enable-max-qos=0|1|2 in broker-check and cmake-build --- .github/workflows/broker-check.yml | 17 +++++++++++++++++ .github/workflows/cmake-build.yml | 20 ++++++++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/.github/workflows/broker-check.yml b/.github/workflows/broker-check.yml index c2887660..120233b1 100644 --- a/.github/workflows/broker-check.yml +++ b/.github/workflows/broker-check.yml @@ -47,6 +47,22 @@ jobs: wolfmqtt_opts: "--enable-broker --enable-tls --enable-websocket" extra_deps: "libwebsockets-dev" wolfssl_opts: "--enable-opensslcoexist --enable-enckeys" + # Maximum-QoS matrix. WOLFMQTT_MAX_QOS=2 is the default and runs + # the full broker.test. =1 and =0 caps compile out the QoS 2 + # state machine; broker.test exercises QoS 2 pub/sub (tests 3 + # and 11) which is intentionally rejected on capped builds, so + # those entries are build-only. + - name: "Broker MAX_QOS=2 (default, full QoS)" + cflags: "" + wolfmqtt_opts: "--enable-v5 --enable-broker --enable-max-qos=2" + - name: "Broker MAX_QOS=1 (build only)" + cflags: "" + wolfmqtt_opts: "--enable-v5 --enable-broker --enable-max-qos=1" + skip_broker_test: "yes" + - name: "Broker MAX_QOS=0 (build only)" + cflags: "" + wolfmqtt_opts: "--enable-v5 --enable-broker --enable-max-qos=0" + skip_broker_test: "yes" steps: - name: Install dependencies @@ -82,6 +98,7 @@ jobs: run: make - name: "Run broker tests (${{ matrix.name }})" + if: matrix.skip_broker_test != 'yes' run: ./scripts/broker.test - name: Show logs on failure diff --git a/.github/workflows/cmake-build.yml b/.github/workflows/cmake-build.yml index b2612dcf..b49a8f5d 100644 --- a/.github/workflows/cmake-build.yml +++ b/.github/workflows/cmake-build.yml @@ -11,6 +11,22 @@ jobs: runs-on: ubuntu-22.04 + strategy: + fail-fast: false + matrix: + # Smoke-build the CMake project under each WOLFMQTT_MAX_QOS value + # to keep the build-option plumbing exercised. "" means leave the + # cache value at its 2 default. + include: + - name: "CMake default (MAX_QOS unset)" + cmake_opts: "" + - name: "CMake MAX_QOS=2" + cmake_opts: "-DWOLFMQTT_V5=yes -DWOLFMQTT_BROKER=yes -DWOLFMQTT_MAX_QOS=2" + - name: "CMake MAX_QOS=1" + cmake_opts: "-DWOLFMQTT_V5=yes -DWOLFMQTT_BROKER=yes -DWOLFMQTT_MAX_QOS=1" + - name: "CMake MAX_QOS=0" + cmake_opts: "-DWOLFMQTT_V5=yes -DWOLFMQTT_BROKER=yes -DWOLFMQTT_MAX_QOS=0" + steps: # Install cmake - name: Install cmake @@ -36,9 +52,9 @@ jobs: - uses: actions/checkout@master #build wolfMQTT - - name: Build wolfMQTT + - name: "Build wolfMQTT (${{ matrix.name }})" run: | mkdir build cd build - cmake .. + cmake ${{ matrix.cmake_opts }} .. cmake --build . From ed375ead78778382320980507340dc316546f36b Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 14 May 2026 11:10:17 -0700 Subject: [PATCH 6/6] Fix CMake broker+TLS build: include options.h in mqtt_broker.h before mqtt_types.h and reorder includes in mqtt_broker.c --- src/mqtt_broker.c | 2 +- wolfmqtt/mqtt_broker.h | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/mqtt_broker.c b/src/mqtt_broker.c index 83765572..19980930 100644 --- a/src/mqtt_broker.c +++ b/src/mqtt_broker.c @@ -24,8 +24,8 @@ #include #endif -#include "wolfmqtt/mqtt_types.h" #include "wolfmqtt/mqtt_broker.h" +#include "wolfmqtt/mqtt_types.h" #include "wolfmqtt/mqtt_client.h" #include "wolfmqtt/mqtt_packet.h" #include "wolfmqtt/mqtt_socket.h" diff --git a/wolfmqtt/mqtt_broker.h b/wolfmqtt/mqtt_broker.h index 66b62c18..4cc5dc2e 100644 --- a/wolfmqtt/mqtt_broker.h +++ b/wolfmqtt/mqtt_broker.h @@ -22,6 +22,13 @@ #ifndef WOLFMQTT_BROKER_H #define WOLFMQTT_BROKER_H +/* Windows uses the vs_settings.h file included via mqtt_types.h */ +#if !defined(WOLFMQTT_USER_SETTINGS) && \ + !defined(_WIN32) && !defined(USE_WINDOWS_API) + /* If options.h is missing use the "./configure" script. Otherwise, copy + * the template "wolfmqtt/options.h.in" into "wolfmqtt/options.h" */ + #include +#endif #include "wolfmqtt/mqtt_types.h" #include "wolfmqtt/mqtt_socket.h" #include "wolfmqtt/mqtt_client.h"