diff --git a/MQTTv5Guide.md b/MQTTv5Guide.md index e9d8a99d..0dbc2a1c 100644 --- a/MQTTv5Guide.md +++ b/MQTTv5Guide.md @@ -310,7 +310,7 @@ status = MQTTPropertyBuilder_Init(&propBuilder, propBuffer, sizeof(propBuffer)); // Add session expiry uint32_t sessionExpiry = 3600; // 1 hour status = MQTTPropAdd_SessionExpiry(&propBuilder, sessionExpiry, - &(uint8_t){MQTT_PACKET_TYPE_CONNECT}); + MQTT_PROP_VALIDATE_CONNECT); // Add user property MQTTUserProperty_t userProp = { @@ -320,7 +320,7 @@ MQTTUserProperty_t userProp = { .valueLength = strlen("sensor-001") }; status = MQTTPropAdd_UserProp(&propBuilder, &userProp, - &(uint8_t){MQTT_PACKET_TYPE_CONNECT}); + MQTT_PROP_VALIDATE_CONNECT); ``` 3. **Pass the property builder to API functions:** @@ -532,7 +532,7 @@ MQTTPropertyBuilder_Init(&pubProps, pubPropsBuf, sizeof(pubPropsBuf)); uint16_t topicAlias = 1; MQTTPropAdd_TopicAlias(&pubProps, topicAlias, - &(uint8_t){MQTT_PACKET_TYPE_PUBLISH}); + MQTT_PROP_VALIDATE_PUBLISH); MQTTPublishInfo_t publishInfo = { .qos = MQTTQoS1, @@ -560,10 +560,10 @@ MQTTPropertyBuilder_Init(&pubProps, pubPropsBuf, sizeof(pubPropsBuf)); MQTTPropAdd_ResponseTopic(&pubProps, "response/topic", strlen("response/topic"), - &(uint8_t){MQTT_PACKET_TYPE_PUBLISH}); + MQTT_PROP_VALIDATE_PUBLISH); MQTTPropAdd_CorrelationData(&pubProps, "req-123", strlen("req-123"), - &(uint8_t){MQTT_PACKET_TYPE_PUBLISH}); + MQTT_PROP_VALIDATE_PUBLISH); MQTT_Publish(&context, &publishInfo, packetId, &pubProps); @@ -618,7 +618,7 @@ MQTTPropertyBuilder_Init(&connectProps, connectPropsBuf, sizeof(connectPropsBuf) // Set session expiry to 1 hour uint32_t sessionExpiry = 3600; MQTTPropAdd_SessionExpiry(&connectProps, sessionExpiry, - &(uint8_t){MQTT_PACKET_TYPE_CONNECT}); + MQTT_PROP_VALIDATE_CONNECT); // Connect with session expiry MQTT_Connect(&context, &connectInfo, NULL, 1000, &sessionPresent, @@ -640,7 +640,7 @@ MQTTUserProperty_t deviceId = { .valueLength = strlen("sensor-001") }; MQTTPropAdd_UserProp(&pubProps, &deviceId, - &(uint8_t){MQTT_PACKET_TYPE_PUBLISH}); + MQTT_PROP_VALIDATE_PUBLISH); MQTTUserProperty_t timestamp = { .pKey = "timestamp", @@ -649,7 +649,7 @@ MQTTUserProperty_t timestamp = { .valueLength = strlen("2024-01-23T10:30:00Z") }; MQTTPropAdd_UserProp(&pubProps, ×tamp, - &(uint8_t){MQTT_PACKET_TYPE_PUBLISH}); + MQTT_PROP_VALIDATE_PUBLISH); MQTT_Publish(&context, &publishInfo, packetId, &pubProps); ``` @@ -664,7 +664,7 @@ MQTTPropertyBuilder_Init(&disconnectProps, disconnectPropsBuf, MQTTPropAdd_ReasonString(&disconnectProps, "Shutting down for maintenance", strlen("Shutting down for maintenance"), - &(uint8_t){MQTT_PACKET_TYPE_DISCONNECT}); + MQTT_PROP_VALIDATE_DISCONNECT); MQTTSuccessFailReasonCode_t reason = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION; MQTT_Disconnect(&context, &disconnectProps, &reason); diff --git a/MigrationGuide.md b/MigrationGuide.md index 27a7fd48..6f8c9abf 100644 --- a/MigrationGuide.md +++ b/MigrationGuide.md @@ -407,7 +407,7 @@ static bool eventCallback( /* PUBREC is not a terminating packet — the library will send PUBREL next. * pReasonCode and pSendPropsBuffer are valid here. */ *pReasonCode = MQTT_REASON_PUBREL_SUCCESS; - MQTTPropAdd_ReasonString( pSendPropsBuffer, "Success", 7, &(uint8_t){ MQTT_PACKET_TYPE_PUBREL } ); + MQTTPropAdd_ReasonString( pSendPropsBuffer, "Success", 7, MQTT_PROP_NO_VALIDATE ); } else { @@ -613,7 +613,7 @@ size bufLength = sizeof(buf); MQTTPropertyBuilder_Init(&connectionProperties, buf, bufLength) ; uint32_t sessionExpiryInterval = 100 ; // 100ms -MQTTPropAdd_SessionExpiry(&connectionProperties, sessionExpiryInterval, &(uint8_t){ MQTT_PACKET_TYPE_CONNECT } ); +MQTTPropAdd_SessionExpiry(&connectionProperties, sessionExpiryInterval, MQTT_PROP_VALIDATE_CONNECT ); // Can also use the will properties in a similar way. @@ -713,7 +713,7 @@ MQTTPropertyBuilder_Init(&propertyBuilder, sizeof(propertyBuffer)); // Add subscription identifier property -MQTTPropAdd_SubscriptionId(&propertyBuilder, 1, &(uint8_t){ MQTT_PACKET_TYPE_SUBSCRIBE } ); +MQTTPropAdd_SubscriptionId(&propertyBuilder, 1, MQTT_PROP_VALIDATE_SUBSCRIBE ); status = MQTT_Subscribe(&mqttContext, subscriptionList, @@ -810,8 +810,8 @@ MQTTPropertyBuilder_Init(&propertyBuilder, sizeof(propertyBuffer)); // Add publish properties -MQTTPropAdd_PayloadFormat(&propertyBuilder, 1, &(uint8_t){ MQTT_PACKET_TYPE_PUBLISH } ); -MQTTPropAdd_TopicAlias(&propertyBuilder, 1, &(uint8_t){ MQTT_PACKET_TYPE_PUBLISH } ); +MQTTPropAdd_PayloadFormat(&propertyBuilder, 1, MQTT_PROP_VALIDATE_PUBLISH ); +MQTTPropAdd_TopicAlias(&propertyBuilder, 1, MQTT_PROP_VALIDATE_PUBLISH ); status = MQTT_Publish(&mqttContext, &publishInfo, @@ -913,7 +913,7 @@ MQTTUserProperty_t userProperty = { .pValue = "value", .valueLength = strlen("value") }; -MQTTPropAdd_UserProp(&propertyBuilder, &userProperty, &(uint8_t){ MQTT_PACKET_TYPE_UNSUBSCRIBE } ); +MQTTPropAdd_UserProp(&propertyBuilder, &userProperty, MQTT_PROP_VALIDATE_UNSUBSCRIBE ); status = MQTT_Unsubscribe(&mqttContext, unsubscribeList, @@ -983,7 +983,7 @@ MQTTPropertyBuilder_Init(&propertyBuilder, MQTTPropAdd_ReasonString(&propertyBuilder, "Normal shutdown", strlen("Normal shutdown"), - &(uint8_t){ MQTT_PACKET_TYPE_DISCONNECT }); + MQTT_PROP_VALIDATE_DISCONNECT); MQTTSuccessFailReasonCode_t reason = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION; status = MQTT_Disconnect(&mqttContext, @@ -1083,7 +1083,7 @@ MQTTPropertyBuilder_Init(&willProperties, sizeof(willPropBuffer)); // Add properties as needed -MQTTPropAdd_SessionExpiry(&connectionProperties, 3600, &(uint8_t){ MQTT_PACKET_TYPE_CONNECT } ); +MQTTPropAdd_SessionExpiry(&connectionProperties, 3600, MQTT_PROP_VALIDATE_CONNECT ); MQTTPropAdd_WillDelayInterval(&willProperties, 60, NULL ); status = MQTT_GetConnectPacketSize(&connectInfo, @@ -1179,8 +1179,8 @@ MQTTPropertyBuilder_Init(&publishProperties, sizeof(propBuffer)); // Add publish properties -MQTTPropAdd_TopicAlias(&publishProperties, 1, &(uint8_t){ MQTT_PACKET_TYPE_PUBLISH } ); -MQTTPropAdd_PayloadFormat(&publishProperties, 1, &(uint8_t){ MQTT_PACKET_TYPE_PUBLISH } ); +MQTTPropAdd_TopicAlias(&publishProperties, 1, MQTT_PROP_VALIDATE_PUBLISH ); +MQTTPropAdd_PayloadFormat(&publishProperties, 1, MQTT_PROP_VALIDATE_PUBLISH ); // Get max packet size from CONNACK properties uint32_t serverMaxPacketSize = pContext->connectionProperties.serverMaxPacketSize; // Value from server @@ -1274,7 +1274,7 @@ MQTTPropertyBuilder_Init(&subscribeProperties, sizeof(propBuffer)); // Add subscription identifier -MQTTPropAdd_SubscriptionId(&subscribeProperties, 1, &(uint8_t){ MQTT_PACKET_TYPE_SUBSCRIBE } ); +MQTTPropAdd_SubscriptionId(&subscribeProperties, 1, MQTT_PROP_VALIDATE_SUBSCRIBE ); // Get max packet size from CONNACK properties uint32_t serverMaxPacketSize = pContext->connectionProperties.serverMaxPacketSize; // value from server @@ -1377,7 +1377,7 @@ MQTTUserProperty_t userProperty = { .pValue = "value", .valueLength = strlen("value") }; -MQTTPropAdd_UserProp(&unsubscribeProperties, &userProperty, &(uint8_t){ MQTT_PACKET_TYPE_UNSUBSCRIBE } ); +MQTTPropAdd_UserProp(&unsubscribeProperties, &userProperty, MQTT_PROP_VALIDATE_UNSUBSCRIBE ); // Get max packet size from CONNACK properties uint32_t serverMaxPacketSize = pContext->connectionProperties.serverMaxPacketSize; // Value from server @@ -1455,11 +1455,11 @@ MQTTPropertyBuilder_Init(&disconnectProperties, sizeof(propBuffer)); // Add disconnect properties -MQTTPropAdd_SessionExpiry(&disconnectProperties, 0, &(uint8_t){ MQTT_PACKET_TYPE_DISCONNECT } ); +MQTTPropAdd_SessionExpiry(&disconnectProperties, 0, MQTT_PROP_VALIDATE_DISCONNECT ); MQTTPropAdd_ReasonString(&disconnectProperties, "Normal shutdown", strlen("Normal shutdown"), - &(uint8_t){ MQTT_PACKET_TYPE_DISCONNECT } ); + MQTT_PROP_VALIDATE_DISCONNECT ); MQTTSuccessFailReasonCode_t reason = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION; status = MQTT_GetDisconnectPacketSize(&disconnectProperties, @@ -1587,8 +1587,8 @@ MQTTPropertyBuilder_Init(&willProperties, sizeof(willPropBuffer)); // Add connect properties -MQTTPropAdd_SessionExpiry(&connectionProperties, 3600, &(uint8_t){ MQTT_PACKET_TYPE_CONNECT } ); -MQTTPropAdd_MaxPacketSize(&connectionProperties, 1024, &(uint8_t){ MQTT_PACKET_TYPE_CONNECT } ); +MQTTPropAdd_SessionExpiry(&connectionProperties, 3600, MQTT_PROP_VALIDATE_CONNECT ); +MQTTPropAdd_MaxPacketSize(&connectionProperties, 1024, MQTT_PROP_VALIDATE_CONNECT ); // Add will properties if using will message MQTTPropAdd_WillDelayInterval(&willProperties, 60, NULL ); @@ -1723,9 +1723,9 @@ MQTTPropertyBuilder_Init(&publishProperties, sizeof(propBuffer)); // Add publish properties -MQTTPropAdd_PayloadFormat(&publishProperties, 1, &(uint8_t){ MQTT_PACKET_TYPE_PUBLISH } ); -MQTTPropAdd_TopicAlias(&publishProperties, 1, &(uint8_t){ MQTT_PACKET_TYPE_PUBLISH } ); -MQTTPropAdd_MessageExpiry(&publishProperties, 3600, &(uint8_t){ MQTT_PACKET_TYPE_PUBLISH } ); +MQTTPropAdd_PayloadFormat(&publishProperties, 1, MQTT_PROP_VALIDATE_PUBLISH ); +MQTTPropAdd_TopicAlias(&publishProperties, 1, MQTT_PROP_VALIDATE_PUBLISH ); +MQTTPropAdd_MessageExpiry(&publishProperties, 3600, MQTT_PROP_VALIDATE_PUBLISH ); // Get remaining length first status = MQTT_GetPublishPacketSize(&publishInfo, @@ -1863,9 +1863,9 @@ MQTTPropertyBuilder_Init(&publishProperties, sizeof(propBuffer)); // Add publish properties -MQTTPropAdd_PayloadFormat(&publishProperties, 1, &(uint8_t){ MQTT_PACKET_TYPE_PUBLISH } ); -MQTTPropAdd_TopicAlias(&publishProperties, 1, &(uint8_t){ MQTT_PACKET_TYPE_PUBLISH } ); -MQTTPropAdd_MessageExpiry(&publishProperties, 3600, &(uint8_t){ MQTT_PACKET_TYPE_PUBLISH } ); +MQTTPropAdd_PayloadFormat(&publishProperties, 1, MQTT_PROP_VALIDATE_PUBLISH ); +MQTTPropAdd_TopicAlias(&publishProperties, 1, MQTT_PROP_VALIDATE_PUBLISH ); +MQTTPropAdd_MessageExpiry(&publishProperties, 3600, MQTT_PROP_VALIDATE_PUBLISH ); // Get remaining length first status = MQTT_GetPublishPacketSize(&publishInfo, @@ -2003,7 +2003,7 @@ MQTTPropertyBuilder_Init(&subscribeProperties, sizeof(propBuffer)); // Add subscription identifier -MQTTPropAdd_SubscriptionId(&subscribeProperties, 1, &(uint8_t){ MQTT_PACKET_TYPE_SUBSCRIBE } ); +MQTTPropAdd_SubscriptionId(&subscribeProperties, 1, MQTT_PROP_VALIDATE_SUBSCRIBE ); // Get remaining length first status = MQTT_GetSubscribePacketSize(subscriptionList, @@ -2141,7 +2141,7 @@ MQTTUserProperty_t userProperty = { .pValue = "value", .valueLength = strlen("value") }; -MQTTPropAdd_UserProp(&unsubscribeProperties, &userProperty, &(uint8_t){ MQTT_PACKET_TYPE_UNSUBSCRIBE } ); +MQTTPropAdd_UserProp(&unsubscribeProperties, &userProperty, MQTT_PROP_VALIDATE_UNSUBSCRIBE ); // Get remaining length first status = MQTT_GetUnsubscribePacketSize(subscriptionList, @@ -2242,11 +2242,11 @@ MQTTPropertyBuilder_Init(&disconnectProperties, sizeof(propBuffer)); // Add disconnect properties -MQTTPropAdd_SessionExpiry(&disconnectProperties, 0, &(uint8_t){ MQTT_PACKET_TYPE_DISCONNECT } ); +MQTTPropAdd_SessionExpiry(&disconnectProperties, 0, MQTT_PROP_VALIDATE_DISCONNECT ); MQTTPropAdd_ReasonString(&disconnectProperties, "Normal shutdown", strlen("Normal shutdown"), - &(uint8_t){ MQTT_PACKET_TYPE_DISCONNECT } ); + MQTT_PROP_VALIDATE_DISCONNECT ); // Get remaining length first MQTTSuccessFailReasonCode_t reason = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION; diff --git a/README.md b/README.md index 8eb4dba5..e587d028 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,61 @@ connectInfo.userNameLength = USERNAME_STRING_LENGTH; mqttStatus = MQTT_Connect( pMqttContext, &connectInfo, NULL, CONNACK_RECV_TIMEOUT_MS, pSessionPresent, NULL, NULL ); ``` +## Thread Safety + +coreMQTT is a single-threaded protocol engine: a given `MQTTContext_t` is +**not** safe to use concurrently from multiple threads. The `MQTT_ProcessLoop`, +`MQTT_ReceiveLoop`, and publish/subscribe APIs all read and mutate fields in +the context (timestamps, state records, in-flight packet IDs, etc.) without +internal locking. + +If your application calls coreMQTT APIs from more than one thread — for +example, an MQTT receive loop in one task and application-originated +`MQTT_Publish` calls from another — you must serialize access to the context +yourself. The library provides two extension points for that purpose: + +- `MQTT_PRE_STATE_UPDATE_HOOK( pContext )` — invoked immediately before the + library reads or writes shared context state. +- `MQTT_POST_STATE_UPDATE_HOOK( pContext )` — invoked immediately after the + corresponding read or write completes. + +Both macros expand to nothing by default. Define them in your +`core_mqtt_config.h` (or via the compiler command line) to acquire and release +a mutex that protects the context. Sketch for FreeRTOS: + +```c +/* In core_mqtt_config.h */ +#include "FreeRTOS.h" +#include "semphr.h" + +/* Application provides one mutex per MQTT context and stores a pointer to it + * reachable from the context — for example, inside the NetworkContext or a + * parallel lookup table keyed by pContext. */ +extern SemaphoreHandle_t getMutexForContext( const MQTTContext_t * pContext ); + +#define MQTT_PRE_STATE_UPDATE_HOOK( pContext ) \ + ( void ) xSemaphoreTake( getMutexForContext( pContext ), portMAX_DELAY ) + +#define MQTT_POST_STATE_UPDATE_HOOK( pContext ) \ + ( void ) xSemaphoreGive( getMutexForContext( pContext ) ) +``` + +Notes: + +- The library calls the hooks in matched pre/post pairs around individual + state accesses; it does not re-enter a hook-protected region from inside + another one, so a non-recursive mutex is sufficient. A recursive mutex + also works if you prefer one for defense in depth. +- The hooks surround individual state accesses, not whole API calls. If you + also need atomicity across a full `MQTT_Publish` invocation from the + application's point of view, take a second application-level lock around + the API call. +- On a single-threaded system (for example, cooperative scheduling with one + task owning the MQTT stack), leave the hooks undefined. +- The transport `send` / `recv` callbacks are not called from inside the + hooks, so your transport implementation does not need to be reentrant with + respect to the mutex. + ## Upgrading to v5.0.0 coreMQTT v5.0.0 adds MQTT v5.0 protocol support with breaking API changes. diff --git a/source/include/core_mqtt.h b/source/include/core_mqtt.h index 2377ae83..699c279c 100644 --- a/source/include/core_mqtt.h +++ b/source/include/core_mqtt.h @@ -520,7 +520,7 @@ MQTTStatus_t MQTT_Init( MQTTContext_t * pContext, * @param[in] incomingPublishCount Maximum number of records which can be kept in the memory * pointed to by @p pIncomingPublishRecords. * @param[in] pAckPropsBuf Pointer to memory which will be used to store properties of outgoing publish-ACKS. - * @param[in] ackPropsBufLength Length of the buffer pointed to by @p pBuffer. + * @param[in] ackPropsBufLength Length of the buffer pointed to by @p pAckPropsBuf. * @return #MQTTBadParameter if invalid parameters are passed;
* #MQTTSuccess otherwise.
* @@ -637,8 +637,6 @@ MQTTStatus_t MQTT_InitStatefulQoS( MQTTContext_t * pContext, * // User defined callback used to clear a particular copied publish packet * bool publishClearCallback(struct MQTTContext* pContext, * uint16_t packetId); - * // User defined callback used to clear all copied publish packets - * bool publishClearAllCallback(struct MQTTContext* pContext); * * MQTTContext_t mqttContext; * TransportInterface_t transport; @@ -678,8 +676,7 @@ MQTTStatus_t MQTT_InitStatefulQoS( MQTTContext_t * pContext, * { * status = MQTT_InitRetransmits( &mqttContext, publishStoreCallback, * publishRetrieveCallback, - * publishClearCallback, - * publishClearAllCallback ); + * publishClearCallback ); * * // Now unacked Publishes can be resent on an unclean session resumption. * } @@ -700,7 +697,7 @@ MQTTStatus_t MQTT_InitRetransmits( MQTTContext_t * pContext, * * @return #MQTTBadParameter if invalid parameters are passed; * #MQTTStatusConnected if the MQTT connection is established with the broker. - * #MQTTStatusNotConnected if the MQTT connection is broker. + * #MQTTStatusNotConnected if the MQTT connection is not established with the broker. * #MQTTStatusDisconnectPending if Transport Interface has failed and MQTT connection needs to be closed. * * Example @@ -840,7 +837,7 @@ MQTTStatus_t MQTT_CheckConnectStatus( const MQTTContext_t * pContext ); * * // Set a property in the connectPropsBuilder * uint32_t maxPacketSize = 100 ; - * status = MQTTPropAdd_MaxPacketSize(&connectPropsBuilder, maxPacketSize, &(uint8_t){ MQTT_PACKET_TYPE_CONNECT }); + * status = MQTTPropAdd_MaxPacketSize(&connectPropsBuilder, maxPacketSize, MQTT_PROP_VALIDATE_CONNECT); * * // The last will and testament is optional, it will be published by the broker * // should this client disconnect without sending a DISCONNECT packet. @@ -930,7 +927,7 @@ MQTTStatus_t MQTT_Connect( MQTTContext_t * pContext, * size_t propertyBufferLength = sizeof( propertyBuffer ); * status = MQTTPropertyBuilder_Init( &propertyBuilder, propertyBuffer, propertyBufferLength ); * - * status = MQTTPropAdd_SubscriptionId(&propertyBuilder, 1, &(uint8_t){ MQTT_PACKET_TYPE_SUBSCRIBE }); + * status = MQTTPropAdd_SubscriptionId(&propertyBuilder, 1, MQTT_PROP_VALIDATE_SUBSCRIBE); * * // Obtain a new packet id for the subscription. * packetId = MQTT_GetPacketId( pContext ); @@ -1011,7 +1008,7 @@ MQTTStatus_t MQTT_Subscribe( MQTTContext_t * pContext, * status = MQTTPropertyBuilder_Init( &propertyBuilder, propertyBuffer, propertyBufferLength ); * * // Set a property in the propertyBuilder - * status = MQTTPropAdd_PayloadFormat( &propertyBuilder, 1, &(uint8_t){ MQTT_PACKET_TYPE_PUBLISH }); + * status = MQTTPropAdd_PayloadFormat( &propertyBuilder, 1, MQTT_PROP_VALIDATE_PUBLISH); * * // Packet ID is needed for QoS > 0. * packetId = MQTT_GetPacketId( pContext ); @@ -1130,7 +1127,7 @@ MQTTStatus_t MQTT_Ping( MQTTContext_t * pContext ); * userProperty.pValue = "value"; * userProperty.valueLength = strlen( userProperty.pValue ); * - * status = MQTTPropAdd_UserProp( &propertyBuilder, &userProperty, &(uint8_t){ MQTT_PACKET_TYPE_UNSUBSCRIBE }); + * status = MQTTPropAdd_UserProp( &propertyBuilder, &userProperty, MQTT_PROP_VALIDATE_UNSUBSCRIBE); * * status = MQTT_Unsubscribe( pContext, &unsubscribeList[ 0 ], NUMBER_OF_SUBSCRIPTIONS, packetId, &propertyBuilder ); * @@ -1184,7 +1181,7 @@ MQTTStatus_t MQTT_Unsubscribe( MQTTContext_t * pContext, * status = MQTTPropertyBuilder_Init( &propertyBuilder, propertyBuffer, propertyBufferLength ); * * // Set a property in the propertyBuilder - * status = MQTTPropAdd_ReasonString( &propertyBuilder, "Disconnecting", 13, &(uint8_t){ MQTT_PACKET_TYPE_DISCONNECT }); + * status = MQTTPropAdd_ReasonString( &propertyBuilder, "Disconnecting", 13, MQTT_PROP_VALIDATE_DISCONNECT); * * MQTTSuccessFailReasonCode_t reason = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION; * status = MQTT_Disconnect( pContext, &propertyBuilder, &reason ); diff --git a/source/include/core_mqtt_config_template.h b/source/include/core_mqtt_config_template.h new file mode 100644 index 00000000..79b10c3d --- /dev/null +++ b/source/include/core_mqtt_config_template.h @@ -0,0 +1,151 @@ +/* + * coreMQTT + * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * SPDX-License-Identifier: MIT + */ + +/** + * @file core_mqtt_config_template.h + * @brief Template configuration file for the coreMQTT library. + * + * This file is a starting point for the `core_mqtt_config.h` that coreMQTT + * requires when the preprocessor macro `MQTT_DO_NOT_USE_CUSTOM_CONFIG` is + * not defined. + * + * To use it: + * 1. Copy this file into your application as `core_mqtt_config.h`. + * 2. Make sure the directory that contains your copy is on the compiler's + * include path when building coreMQTT. + * 3. Uncomment and change the values of any macros below whose defaults + * (defined in `core_mqtt_config_defaults.h`) do not match your + * application's needs. + * + * Any macro left commented-out here will pick up the default value from + * `core_mqtt_config_defaults.h`. You do not need to define every macro. + * + * See `core_mqtt_config_defaults.h` for the authoritative list of tunables + * and their documented ranges. + */ + +#ifndef CORE_MQTT_CONFIG_H_ +#define CORE_MQTT_CONFIG_H_ + +/*-------------------- Protocol / buffer sizing --------------------*/ + +/** + * @brief Maximum number of vectors used when sending SUBSCRIBE / UNSUBSCRIBE + * packets via the scatter-gather transport writev interface. + * + * Default: 4 + */ +/* #define MQTT_SUB_UNSUB_MAX_VECTORS ( 4U ) */ + +/*-------------------- Connect handshake --------------------*/ + +/** + * @brief Number of retry attempts for receiving CONNACK when MQTT_Connect is + * called with timeoutMs == 0. Ignored when timeoutMs > 0. + * + * Default: 5 + */ +/* #define MQTT_MAX_CONNACK_RECEIVE_RETRY_COUNT ( 5U ) */ + +/*-------------------- Keep-alive and idle timing --------------------*/ + +/** + * @brief Maximum milliseconds to wait for a PINGRESP after sending a PINGREQ. + * If exceeded, MQTT_ProcessLoop returns MQTTKeepAliveTimeout. + * + * Recommended: <= keepAliveSeconds / 2. Default: 5000. + */ +/* #define MQTT_PINGRESP_TIMEOUT_MS ( 5000U ) */ + +/** + * @brief Maximum milliseconds of transmit idleness before the library sends + * a PINGREQ on its own. Capped by keepAliveSeconds if that is smaller. + * + * Default: 30000. + */ +/* #define PACKET_TX_TIMEOUT_MS ( 30000U ) */ + +/** + * @brief Maximum milliseconds of receive idleness before the library sends + * a PINGREQ to verify the connection is alive. + * + * Default: 30000. + */ +/* #define PACKET_RX_TIMEOUT_MS ( 30000U ) */ + +/*-------------------- Transport I/O timing --------------------*/ + +/** + * @note All three of the transport-I/O timeouts below MUST be set to 0 if + * the MQTTGetCurrentTimeFunc_t passed to MQTT_Init is a dummy that always + * returns 0. See the note on MQTT_Connect's timeoutMs parameter. + */ + +/** + * @brief Maximum milliseconds to wait between successful partial reads when + * assembling an incoming MQTT packet. Exceeding this returns MQTTRecvFailed. + * + * Default: 10. + */ +/* #define MQTT_RECV_POLLING_TIMEOUT_MS ( 10U ) */ + +/** + * @brief Maximum milliseconds to spend sending a single MQTT packet across + * potentially multiple transport send / writev calls. Exceeding this returns + * MQTTSendFailed. + * + * Default: 20000. + */ +/* #define MQTT_SEND_TIMEOUT_MS ( 20000U ) */ + +/*-------------------- Logging --------------------*/ + +/** + * @brief Logging macros. + * + * Map these to your application's logging implementation. All five are + * stripped to no-ops by default, so the library produces no log output + * unless you define them here. + * + * The library invokes each macro with its argument wrapped in double + * parentheses so it remains ISO C89/C90 compliant, for example: + * + * LogInfo( ( "Connected with keep alive = %u", keepAlive ) ); + * + * A simple printf-based mapping: + * + * #include + * #define LogError( msg ) do { printf( "[ERR] " ); printf msg; printf( "\n" ); } while( 0 ) + * #define LogWarn( msg ) do { printf( "[WARN] " ); printf msg; printf( "\n" ); } while( 0 ) + * #define LogInfo( msg ) do { printf( "[INFO] " ); printf msg; printf( "\n" ); } while( 0 ) + * #define LogDebug( msg ) do { } while( 0 ) + * #define LogTrace( msg ) do { } while( 0 ) + */ +/* #define LogError( message ) */ +/* #define LogWarn( message ) */ +/* #define LogInfo( message ) */ +/* #define LogDebug( message ) */ +/* #define LogTrace( message ) */ + +/*-------------------- Thread-safety hooks --------------------*/ + +/** + * @brief Thread-safety hooks. + * + * coreMQTT is single-threaded by default. If multiple threads share one + * MQTTContext_t, define these to acquire and release a mutex that protects + * the context. The library pairs every PRE call with a matching POST call + * and does not re-enter a hook-protected region from inside another, so a + * non-recursive mutex is sufficient. + * + * See the "Thread Safety" section of README.md for a worked FreeRTOS + * example. + */ +/* #define MQTT_PRE_STATE_UPDATE_HOOK( pContext ) */ +/* #define MQTT_POST_STATE_UPDATE_HOOK( pContext ) */ + +#endif /* ifndef CORE_MQTT_CONFIG_H_ */ diff --git a/source/include/core_mqtt_serializer.h b/source/include/core_mqtt_serializer.h index 97f90e14..fff1da27 100644 --- a/source/include/core_mqtt_serializer.h +++ b/source/include/core_mqtt_serializer.h @@ -86,6 +86,21 @@ * MQTTPropAdd_UserProp( &props, &up, MQTT_PROP_NO_VALIDATE ); * @endcode */ +/* + * The five file-scope constants below are intentionally named in the same + * MQTT_PACKET_TYPE_* family as the existing MQTT_PACKET_TYPE_* macros a few + * lines above, and their values match those macros. Coverity flags this as + * MISRA C:2012 Rule 2.2 (unused redundant expression — the name reuse looks + * redundant to the analyser) and Rule 2.8 (unused objects at file scope). + * Both deviations are accepted because these constants have to be addressable + * storage — the MQTT_PROP_VALIDATE_* macros below take their addresses so + * that callers can pass a typed `const uint8_t *` argument to the + * MQTTPropAdd_* APIs without resorting to C99 compound literals. Macros + * cannot be addressed, which is why we cannot reuse the existing + * MQTT_PACKET_TYPE_* macros directly here. + * + * See MISRA.md in the repository root for the project-wide deviation record. + */ /* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-22 */ /* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-28 */ /* coverity[misra_c_2012_rule_2_2_violation] */ @@ -2037,7 +2052,7 @@ MQTTStatus_t MQTT_ValidateConnectProperties( const MQTTPropBuilder_t * pProperty * uint32_t subscriptionId = 12345; * * // Add Subscription Identifier to property builder - * status = MQTTPropAdd_SubscriptionId(&propertyBuilder, subscriptionId, &(uint8_t){ MQTT_PACKET_TYPE_SUBSCRIBE }); + * status = MQTTPropAdd_SubscriptionId(&propertyBuilder, subscriptionId, MQTT_PROP_VALIDATE_SUBSCRIBE); * * if(status == MQTTSuccess) * {